#!/usr/bin/python3

# Copyright (C) 2015
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License (version 3+) as
# published by the Free Software Foundation. You should have received
# a copy of the GNU General Public License along with this program.
# If not, see <http://www.gnu.org/licenses/>.

from re import search
from sys import argv
from os import path

from gi import require_version
require_version("Gtk", "3.0")
require_version('Notify', '0.7')
from gi.repository import Gtk, Gdk, GdkPixbuf, Pango, GLib, Gio


colour_labels = ["Primary", "Secondary", "Symbol"]

def get_default_colour(colour):
    for d in defaults:
        if colour == defaults[d]:
            return d
        else:
            continue
    return "custom"


def gdk_to_hex(gdk_colour):
    colours = gdk_colour.to_floats()
    return "#" + "".join(["%02x" % (colour * 255) for colour in colours])


def check_hex(colour):
    return search(r'#[a-fA-F0-9]{6}$', colour)


style_fixed = {
    "1": ((False, False, False), (True, False, False)),
    "2": ((False, False, False), (True, True, True)),
    "3": ((False, False, False), (True, True, True)),
    "4": ((False, False, False), (True, True, True)),
    "5": ((False, False, True), (True, True, True)),
    "6": ((False, False, False), (True, True, True))
}


defaults = {
    "blue": ("#42a5f5", "#1976d2", "#2a74b9"),
    "brown": ("#8d6e63", "#5d4037", "#634b43"),
    "green": ("#66bb6a", "#388e3c", "#448647"),
    "grey": ("#bdbdbd", "#757575", "#7f7f7f"),
    "orange": ("#f57c00", "#e65100", "#ab5d0b"),
    "pink": ("#f06292", "#ec407a", "#c64077"),
    "purple": ("#7e57c2", "#512da8", "#54398d"),
    "red": ("#ef5350", "#d32f2f", "#ab3634"),
    "yellow": ("#ffca28", "#ffb300", "#c79a18"),
    "style 1": ("#c4905e", "#b07f51", "#f9f9f9"),
    "style 2": ("#e8b07f", "#9e7757", "#9e7757"),
    "style 3": ("#f2bb64", "#ea9036", "#b58c4b"),
    "style 4": ("#f5c14e", "#e9a439", "#c79d41"),
    "style 5": ("#ffb300", "#f57c00", "#fff8e1"),
    "style 6": ("#ffa726", "#ef6c00", "#b17621")
}

colour_svg = """<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
<g transform="translate(0,-1030.3622)">
<rect width="20" height="20" y="1030.36" style="fill:replacecolour;opacity:1;fill-opacity:1;stroke:none;fill-rule:nonzero"/>
</g>
</svg>"""

colours = ("Default", "Blue", "Brown", "Green", "Grey", "Orange",
           "Pink", "Purple", "Red", "Yellow", "Style 1", "Style 2",
           "Style 3", "Style 4", "Style 5", "Style 6", "Custom")

number_styles = 6
number_colours = 3
default_style = 6

if len(argv) > 1:
    style = argv[1]
else:
    style = str(default_style)

try:
    if int(style) not in range(1, int(style)+1):
        style = str(default_style)
except:
    style = str(default_style)

if len(argv) > 2:
    colour = argv[2].lower()
else:
    colour = "default"

if colour == "custom":
    colour_list = []
    for i in range(number_colours):
        if len(argv) > i+3 and check_hex(argv[i+3]):
            colour_list.append(argv[i+3])
        else:
            colour_list.append("#000000")
elif colour == "default":
    colour_list = defaults["style %s" % (style)]
else:
    try:
        colour_list = defaults[colour]
    except:
        colour = "default"
        colour_list = defaults["style %s" % (style)]


class NumixFoldersGUI(Gtk.Application):

    def __init__(self, style, colour, colour_list):
        Gtk.Application.__init__(self,
                                 application_id='org.gnome.numix-folders',
                                 flags=Gio.ApplicationFlags.FLAGS_NONE)
        GLib.set_application_name("Numix Folders")
        GLib.set_prgname('numix-folders')
        self.connect("activate", self.on_activate, style, colour, colour_list)

    def exit(self, *args):
        self.quit()

    def on_activate(self, app, style, colour, colour_list):
        self.win = Gtk.ApplicationWindow(Gtk.WindowType.TOPLEVEL, application=app)
        self.win.set_title("Numix Folders")
        self.win.set_icon_name('numix-folders')
        self.win.set_border_width(18)
        self.win.set_resizable(False)
        self.win.set_wmclass("numix-folders", "Numix Folders")
        self.win.set_position(Gtk.WindowPosition.CENTER)
        self.colour = colour_list
        self.global_colour = colour
        self.style = style

        # boxes
        vboxall = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        vboxmain = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        hboxpreview = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=30)
        hboxcombo = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
        hboxentry = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
        hboxcolour = []  # filled later
        vboxcolours = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        hboxcolours = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.win.add(vboxall)

        # preview pixmap
        self.image = Gtk.Image()
        svg_path = path.split(path.abspath(__file__))[0] + "/../styles/"
        svg_path += str(self.style)+"/Numix/48/places/custom-user-home.svg"
        with open(svg_path, "r") as svgfile:
            self.svg = svgfile.read()
        fixed = Gtk.Fixed()
        fixed.put(self.image, 0, 0)
        self.update_preview(style, colour_list)
        hboxpreview.pack_start(fixed, False, False, 95)

        # comboboxentrystyle
        self.preview_svgs = []
        for i in range(number_styles):
            svg_path = path.split(path.abspath(__file__))[0] + "/../styles/"
            svg_path += str(i + 1) + "/Numix/22/places/custom-user-home.svg"
            with open(svg_path, "r") as svgfile:
                self.preview_svgs.append(svgfile.read())
        self.style_store = Gtk.ListStore(GdkPixbuf.Pixbuf, str)
        self.update_small_preview()
        self.style_combo = Gtk.ComboBox.new_with_model(self.style_store)
        renderer_pix = Gtk.CellRendererPixbuf()
        self.style_combo.pack_start(renderer_pix, True)
        self.style_combo.add_attribute(renderer_pix, "pixbuf", 0)
        renderer_text = Gtk.CellRendererText()
        self.style_combo.pack_start(renderer_text, True)
        self.style_combo.add_attribute(renderer_text, "text", 1)
        if int(style) in range(1, number_styles + 1):
            self.style_combo.set_active(int(style)-1)
        hboxcombo.pack_start(self.style_combo, True, False, 12)

        # comboboxentrycolour
        colours_store = Gtk.ListStore(GdkPixbuf.Pixbuf, str)
        for col in colours:
            if col.lower() in defaults:
                svg = colour_svg.replace("replacecolour",
                                         defaults[col.lower()][0])
                loader = GdkPixbuf.PixbufLoader()
                loader.write(svg.encode())
                loader.close()
                pixbuf = loader.get_pixbuf()
            else:
                pixbuf = None
            colours_store.append([pixbuf, "  " + col])
        self.colours_combo = Gtk.ComboBox.new_with_model(colours_store)
        renderer_pix = Gtk.CellRendererPixbuf()
        self.colours_combo.pack_start(renderer_pix, True)
        self.colours_combo.add_attribute(renderer_pix, "pixbuf", 0)
        renderer_text = Gtk.CellRendererText()
        self.colours_combo.pack_start(renderer_text, True)
        self.colours_combo.add_attribute(renderer_text, "text", 1)
        if colour and colour in [x.lower() for x in colours]:
            ind = [x.lower() for x in colours].index(colour)
            self.colours_combo.set_active(ind)
        hboxcombo.pack_start(self.colours_combo, True, False, 12)

        # colourchooser widgets
        self.colourbuttons = []
        self.colourentries = []
        self.colourlabels = []
        for i in range(number_colours):
            hboxcolour.append(Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=12))
            self.colourbuttons.append(Gtk.ColorButton())
            self.colourbuttons[i].set_color(Gdk.color_parse(self.colour[i]))
            self.colourentries.append(Gtk.Entry())
            self.colourentries[i].set_text(self.colour[i])
            self.colourentries[i].set_max_length(7)
            if Gtk.get_major_version() >= 3 and Gtk.get_minor_version() >= 12:
                self.colourentries[i].set_width_chars(7)
                self.colourentries[i].set_max_width_chars(7)
                self.colourlabels.append(Gtk.Label())
                self.colourlabels[i].set_text(colour_labels[i])
            self.colourentries[i].modify_font(Pango.FontDescription('monospace'))
            hboxcolour[i].pack_end(self.colourentries[i], False, False, 0)
            hboxcolour[i].pack_end(self.colourbuttons[i], False, False, 0)
            if Gtk.get_major_version() >= 3 and Gtk.get_minor_version() >= 12:
                hboxcolour[i].pack_end(self.colourlabels[i], False, False, 6)

        for hbox in hboxcolour[::-1]:
            vboxcolours.pack_end(hbox, False, False, 5)
        hboxcolours.pack_start(vboxcolours, False, False, 30)

        # buttons
        buttonok = Gtk.Button("_Apply", use_underline=True)
        buttonok.get_style_context().add_class("suggested-action")
        buttonclose = Gtk.Button("_Cancel", use_underline=True)
        buttonclose.get_style_context().add_class("destructive-action")

        # header bar
        if Gtk.get_major_version() >= 3 and Gtk.get_minor_version() >= 14:
            headerbar = Gtk.HeaderBar()
            headerbar.props.title = "Numix Folders"
            left_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
            right_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)

            left_box.add(buttonclose)
            right_box.add(buttonok)

            headerbar.pack_start(left_box)
            headerbar.pack_end(right_box)
            self.win.set_titlebar(headerbar)
        else:
            hboxbuttons = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
            hboxbuttons.set_margin_left(80)
            hboxbuttons.set_margin_right(20)

            hboxbuttons.pack_end(buttonok, True, True, 6)
            hboxbuttons.pack_end(buttonclose, True, True, 6)
            hboxbuttons.set_margin_top(18)
            vboxall.pack_end(hboxbuttons, False, False, 6)


        # packing
        vboxall.pack_start(vboxmain, False, False, 0)
        vboxmain.pack_start(hboxpreview, True, True, 15)
        vboxmain.pack_start(hboxcombo, False, False, 25)
        vboxmain.pack_start(hboxcolours, False, False, 0)

        # connect signals
        self.colours_combo.connect("changed", self.combo_changed_colour)
        self.style_combo.connect("changed", self.combo_changed_style)
        for j, but in enumerate(self.colourbuttons):
            but.connect("color_set", self.colourbutton_changed, j)
        for j, ent in enumerate(self.colourentries):
            ent.connect("changed", self.entry_changed, j)
        buttonok.connect("clicked", self.on_ok_clicked)
        buttonclose.connect("clicked", self.exit)

        # a little bit of initializing
        self.combo_changed_style(self.style_combo)

        # for if default colour is style because thats nothing else than custom
        if colour == "custom":
            colour = get_default_colour(tuple(self.colour))
            indcol = [x.lower() for x in colours].index(colour)
            self.update_preview(self.style, self.colour)
            self.update_small_preview()
            self.colours_combo.handler_block_by_func(self.combo_changed_colour)
            self.colours_combo.set_active(indcol)
            self.colours_combo.handler_unblock_by_func(self.combo_changed_colour)
        self.win.show_all()
        self.add_window(self.win)


    def set_sensitive(self, style):
        for i in range(1, number_colours):
            if style_fixed[style][1][i]:
                self.colourbuttons[i].set_sensitive(True)
                self.colourentries[i].set_sensitive(True)
            else:
                self.colourbuttons[i].set_sensitive(False)
                self.colourentries[i].set_sensitive(False)

    def combo_changed_colour(self, widget):
        ind = widget.get_active()
        colour = colours[ind].lower()
        self.global_colour = colour
        if colour == "custom":
            return
        elif colour == "default":
            self.colour = list(defaults["style %s" % (self.style)])
            self.update_preview(self.style, defaults["style "+str(self.style)])
            self.update_small_preview()
        elif not colour.startswith("style"):
            self.colour = list(defaults[colour])
            col = self.colour[:]
            for j in range(number_colours):
                if style_fixed[self.style][0][j]:
                    col[j] = defaults["style %s" % (self.style)][j]
                else:
                    col[j] = self.colour[j]
            for j in range(number_colours):
                if style_fixed[str(self.style)][0][j]:
                    self.colour[j] = defaults["style %s" % (self.style)][j]
            self.update_preview(self.style, self.colour)
            self.update_small_preview()
        else:
            self.colour = list(defaults[colour])
            self.update_preview(self.style, self.colour)
            self.update_small_preview()
        for j, but in enumerate(self.colourbuttons):
            but.handler_block_by_func(self.colourbutton_changed)
            but.set_color(Gdk.color_parse(self.colour[j]))
            but.handler_unblock_by_func(self.colourbutton_changed)
        for j, ent in enumerate(self.colourentries):
            ent.handler_block_by_func(self.entry_changed)
            ent.set_text(self.colour[j])
            ent.handler_unblock_by_func(self.entry_changed)

    def combo_changed_style(self, widget):
        ind = widget.get_active()
        style = int(ind)+1
        self.style = str(style)
        self.set_sensitive(self.style)
        self.combo_changed_colour(self.colours_combo)
        if self.global_colour == "custom":
            self.update_preview(self.style, self.colour)

    def colourbutton_changed(self, widget, arg):
        colour = widget.get_color()
        self.colour[arg] = gdk_to_hex(colour)
        self.colourentries[arg].handler_block_by_func(self.entry_changed)
        self.colourentries[arg].set_text(self.colour[arg])
        self.colourentries[arg].handler_unblock_by_func(self.entry_changed)
        colour = get_default_colour(tuple(self.colour))
        self.global_colour = colour
        if not colour.startswith('style'):
            colour = "custom"
        ind = [x.lower() for x in colours].index(colour)
        self.update_preview(self.style, self.colour)
        self.update_small_preview()
        self.colours_combo.handler_block_by_func(self.combo_changed_colour)
        self.colours_combo.set_active(ind)
        self.colours_combo.handler_unblock_by_func(self.combo_changed_colour)

    def entry_changed(self, widget, arg):
        entry = widget.get_text()
        match = check_hex(entry)
        if not match:
            return
        try:
            colour = Gdk.color_parse(entry)
        except:
            return
        self.colour[arg] = entry
        self.colourbuttons[arg].handler_block_by_func(self.colourbutton_changed)
        self.colourbuttons[arg].set_color(colour)
        self.colourbuttons[arg].handler_unblock_by_func(self.colourbutton_changed)

        colour = get_default_colour(tuple(self.colour))
        self.global_colour = colour
        if not colour.startswith('style'):
            colour = "custom"
        ind = [x.lower() for x in colours].index(colour)
        self.update_preview(self.style, self.colour)
        self.update_small_preview()
        self.colours_combo.handler_block_by_func(self.combo_changed_colour)
        self.colours_combo.set_active(ind)
        self.colours_combo.handler_unblock_by_func(self.combo_changed_colour)

    def update_preview(self, style, colours):
        svg_path = path.split(path.abspath(__file__))[0] + "/../styles/"
        svg_path += str(style) + "/Numix/48/places/custom-user-home.svg"
        with open(svg_path, "r") as svgfile:
            self.svg = svgfile.read()
        if not hasattr(colours, '__contains__'):
            colours = [colours]
        svg = self.svg.replace("replacecolour1", colours[0])
        for k, col in enumerate(colours):
            if k != 0:
                svg = svg.replace("replacecolour%s" % (k+1), col)
        loader = GdkPixbuf.PixbufLoader()
        loader.write(svg.encode())
        loader.set_size(96,96)
        loader.close()
        pixbuf = loader.get_pixbuf()
        self.image.set_from_pixbuf(pixbuf)

    def update_small_preview(self):
        colours = self.colour
        for i in range(number_styles):
            if self.global_colour == "default":
                colours = defaults["style "+str(i+1)]
            elif self.global_colour == "custom" or self.global_colour.startswith("style"):
                colours = self.colour
            else:
                colours = list(defaults[self.global_colour])
                for j in range(number_colours):
                    if style_fixed[str(i+1)][0][j]:
                        colours[j] = defaults["style %s" % str(i+1)][j]
            svg = self.preview_svgs[int(i)].replace("replacecolour1",
                                                    colours[0])
            for k, col in enumerate(colours):
                if k != 0:
                    svg = svg.replace("replacecolour%s" % (k+1), col)
            loader = GdkPixbuf.PixbufLoader()
            loader.write(svg.encode())
            loader.close()
            pixbuf = loader.get_pixbuf()
            if len(self.style_store) <= i:
                if i != default_style-1:
                    self.style_store.append([pixbuf, "  Style %s" % int(i+1)])
                else:
                    self.style_store.append([pixbuf, "  Style %s *" % int(i+1)])
            else:
                self.style_store[int(i)][0] = pixbuf

    def on_ok_clicked(self, button):
        colour = self.global_colour
        if colour.startswith("style"):
            colour = "custom"
        print(self.style)
        print(colour)
        for i in range(number_colours):
            print(self.colour[i].replace("#", ""))
        self.quit()


win = NumixFoldersGUI(style, colour, colour_list)
win.run(None)
