#!/usr/bin/python
# -*- coding: utf-8 -*-
# Insync Nautilus Plugin
#
# Authors
# Brett Hartshorn <brett@insynchq.com>
# Luis Manuel R. Pugoy <lpugoy@insynchq.com>
#
# Copyright Insynchq Pte. Ltd., ("Insync") | http://www.insynchq.com
# License: GNU GPL v2

DEV_MODE = False

import json
import os
import socket
import sys

try:
    from urllib import unquote  # Python 2.X
except ImportError:
    from urllib.parse import unquote  # Python 3+

try:
    from importlib import reload  # Python 3.4+
except ImportError:
    from imp import reload  # Python 2.x-3.3

from gi.repository import GObject  # noqa isort:skip

GTK3 = False
try:
    from gi.repository import Nautilus

    GTK3 = True  # this might not be true
except:
    print("WARN - using Nautilus2 wrapper")
    import nautilus as Nautilus  # Nautilus2

if GTK3:
    # http://python-gtk-3-tutorial.readthedocs.org/en/latest/drag_and_drop.html
    from gi.repository import Gdk

    (TARGET_ENTRY_TEXT, TARGET_ENTRY_PIXBUF) = range(2)
    (COLUMN_TEXT, COLUMN_PIXBUF) = range(2)
    DRAG_ACTION = Gdk.DragAction.COPY

print(Nautilus)

if __name__ == "__main__":  ## this is only for testing ##
    if "--install-local" in sys.argv:
        ## Nautilus2 is no longer supported ##
        # if os.path.isdir( os.path.expanduser('~/.nautilus') ):
        #  path = os.path.expanduser('~/.nautilus/python-extensions')
        #  if not os.path.isdir(path): os.makedirs( path )
        #  os.system('cp -v %s ~/.nautilus/python-extensions/.' %__file__)

        ## Nautilus3 ##
        path = os.path.expanduser("~/.local/share/nautilus-python/extensions")
        if not os.path.isdir(path):
            os.makedirs(path)
        os.system("cp -v %s ~/.local/share/nautilus-python/extensions/." % __file__)
    else:
        os.system("cp -v %s /usr/share/nautilus-python/extensions/." % __file__)

    os.system("nautilus -q")
    sys.exit()


print("Insync Nautilus Plugin")

if sys.getdefaultencoding() != "utf-8":
    reload(sys)
    sys.setdefaultencoding("utf-8")  # pylint: disable=E1101


def ipc_insync(**kw):
    data = json.dumps(kw)
    socket_file = "/tmp/insync%r.sock" % os.getuid()
    if not os.path.exists(socket_file):
        if DEV_MODE:
            print("WARN: insync socket not found")
        return None
    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
    sock.settimeout(0.1)
    try:
        sock.connect(socket_file)
        sock.send(str.encode(data))
        res = sock.recv(4096)
        sock.close()
    except:
        return None
    if res.strip():
        return json.loads(res.strip())
    else:
        return None


_EMBLEM_KEYS = {
    "SYNCED": "nautilus-emblem-insync-synced",
    "SYNCING": "nautilus-emblem-insync-syncing",
    "ERROR": "nautilus-emblem-insync-error",
}


class InsyncExtension(GObject.GObject, Nautilus.MenuProvider, Nautilus.InfoProvider):
    """
    see: /usr/share/doc/python-nautilus/examples/

    1. nautilus.ColumnProvider - It exposes a single function get_columns . This function has to return a sequence of nautilus.Column objects.
    2. nautilus.InfoProvider - Exposes a single function update_file_info with a file as an argument.
    3. nautilus.LocationWidgetProvider - Exposes a single function get_widget, return some gtk widget near the location bar.
    4. nautilus.MenuProvider - Probably the most used interface. It exposes three functions :
       get_file_items, get_background_items and get_toolbar_items . The first two functions determine the entries that appear in the context menu. The difference is that get_background_items is usually called for a folder.
       The last function is used for toolbar items hence you must name the icon parameter of the menuItem.
    5. nautilus.PropertyPageProvider - Exposes get_property_pages function where you reture one or more "pages" or tabs.

    """

    def __init__(self):
        self.file_list = dict()
        print("[__init__ insync plugin]", self)

    def get_background_items(self, *args):
        """
        This method needs to be defined to avoid this warning:
        ** (nautilus:2913): CRITICAL **: nautilus_menu_provider_get_background_items: assertion
        `NAUTILUS_IS_MENU_PROVIDER (provider)' failed
        """
        # print('background items', window, folder)
        return None

    def get_file_items(self, *args):
        if int(Nautilus._version.split(".")[0]) < 4:
            files = args[1]
        else:
            # Nautilus v4.0+
            files = args[0]

        if DEV_MODE:
            print("get file items", files)

        if len(files) != 1:
            # TODO what can we do with mutiple files here
            return None

        file = files[0]
        if file.get_uri_scheme() != "file":
            return None

        path = os.path.realpath(unquote(file.get_uri()[len("file://") :]))
        if sys.version_info[0] < 3:
            path = unicode(path)  # noqa
        else:
            path = str(path)
        if DEV_MODE:
            print(path)
        is_dir = os.path.isdir(path)

        cm_info = ipc_insync(command="CONTEXT-MENU-ITEMS", full_path=path)

        if cm_info:
            title, cm_items = cm_info
            tip = "Insync folder actions" if is_dir else "Insync file actions"
            item = Nautilus.MenuItem(
                name="Insync:" + title, label=title, tip=tip, icon="insync"
            )
            sub_menu = Nautilus.Menu()
            item.set_submenu(sub_menu)

            item_id = 0
            for text, cmd in cm_items:
                if text == "separator":
                    text = "\u2015" * 10
                    name = "Insync:separator:" + str(item_id)
                else:
                    name = "Insync::%d" % (item_id)
                item_id += 1
                menu_item = Nautilus.MenuItem(name=name, label=text, tip=text)
                if cmd:
                    menu_item.connect("activate", self.do_action, file, cmd)
                else:
                    menu_item.sensitive = False
                sub_menu.append_item(menu_item)

            return [item]
        return None

    def do_action(self, menu, file, method):
        path = unquote(file.get_uri()[len("file://") :])
        ipc_insync(method=method, full_path=path)

    def update_file_info(self, file):
        if file.get_uri_scheme() != "file":
            return

        filename = unquote(file.get_uri()[len("file://") :])
        filename = os.path.realpath(filename)
        status = ipc_insync(command="GET-FILE-STATUS", full_path=filename)
        if DEV_MODE:
            print(filename, status)
        if status and status != "UNKNOWN":
            emblem = _EMBLEM_KEYS[status]
            if os.path.isdir(filename):
                is_shared = ipc_insync(command="IS-FILE-SHARED", full_path=filename)
                if is_shared:
                    emblem += "-shared"
            file.add_emblem(emblem)
            old_emblem = self.file_list.get(filename)
            self.file_list[filename] = emblem
            if old_emblem != emblem:
                file.invalidate_extension_info()
        elif self.file_list.pop(filename, None):
            file.invalidate_extension_info()


print(InsyncExtension)
