#!/usr/bin/env python3

import sys
import os, site
import icu
from re import sub, escape
import struct

import gi
gi.require_version('Gtk', "3.0")
from gi.repository import Gtk

class Trainer:

    def __init__(self):
        self.gladefile = os.path.join(os.path.dirname(__file__), 'sort_trainer.glade')
        self.builder = Gtk.Builder.new_from_file(self.gladefile)
        self.wTree = self.builder.get_object("window1")

        dic = {
            "on_window1_destroy" : Gtk.main_quit,
            "on_bt_sort_clicked" : self.on_sort,
            "on_open_order1_activate" : self.on_open_sort,
            "on_open_sort_list1_activate" : self.on_open_src,
            "on_save_order1_activate" : self.on_save_sort,
            "on_save_sort_list1_activate" : self.on_save_src,
            "on_bt_source_clicked" : self.on_set_src,
            "on_bt_keys_clicked" : self.on_sort_keys,
            "on_about1_activate": self.do_nothing,
            "on_font1_activate": self.do_nothing,
            "on_delete1_activate": self.do_nothing,
            "on_paste1_activate": self.do_nothing,
            "on_copy1_activate": self.do_nothing,
            "on_cut1_activate": self.do_nothing,
            "on_quit1_activate": Gtk.main_quit,
            "on_save_all1_activate": self.do_nothing,
            "on_new_sort_list1_activate": self.do_nothing,
            "on_new_order1_activate": self.do_nothing
            }
        self.tdia = TextDialog(self.builder)
        dic.update(self.tdia.signals)
        self.builder.connect_signals(dic)

    def do_nothing(self, widget):
        pass

    def on_sort(self, widget):
        lb_error = self.builder.get_object("lb_status")
        lb_error.set_text('')
        buf_order = self.builder.get_object("txt_order").get_buffer()
        try:
            sort = icu.RuleBasedCollator(buf_order.get_text(buf_order.get_start_iter(), buf_order.get_end_iter(), False))
        except icu.ICUError as val:
            lb_error.set_text(str(val))
            return
        buf_src = self.builder.get_object("txt_src").get_buffer()
        l = buf_src.get_text(buf_src.get_start_iter(), buf_src.get_end_iter(), False).splitlines()
        l.sort(key=sort.getSortKey)
        buf_srt = self.builder.get_object("txt_srt").get_buffer()
        buf_srt.set_text("\n".join(l))

    def on_sort_keys(self, widget):
        lb_error = self.builder.get_object("lb_status")
        lb_error.set_text('')
        buf_order = self.builder.get_object("txt_order").get_buffer()
        txt_order = buf_order.get_text(buf_order.get_start_iter(), buf_order.get_end_iter(), False)
        try:
            sort = icu.RuleBasedCollator(txt_order)
        except icu.ICUError as val:
            lb_error.set_text(str(val))
            return
        text = sub(r'(?m)#.*$', u'\ufdd0', txt_order)
        text = sub(r'\\[uU]([0-9a-fA-F]{4,6})', lambda x: chr(int(x.group(1), 16)), text)
        text = sub(r'(?<!\\)\[.*?\]', u'\ufdd0', text)
        text = sub(r'(?<!\\)[\s&<=;,|/]', u'\ufdd0', text)
        text = sub(r'\\(.)', lambda x: x.group(1), text)
        text = sub('\ufdd0{2,}', '\ufdd0', text)
        char_list = text.split(u'\ufdd0')
        buf_src = self.builder.get_object("txt_src").get_buffer()
        char_list += buf_src.get_text(buf_src.get_start_iter(), buf_src.get_end_iter(), False).splitlines()
        chars_dict = dict.fromkeys(char_list, 1)
        chars = list(chars_dict.keys())
        chars.sort(key=sort.getSortKey)
        textout = ''
        for char in chars:
            if char == '': continue
            keyinfo = list()
            keyinfo_size = 0
            st = sort.getCollationKey(char).getByteArray()
            # import pdb; pdb.set_trace()
            for b in st.rstrip(b'\000').split(b'\001'):
                if len(b) % 2: b += b"\000"
                keyinfo.append([x*256 + y for (x, y) in zip(b[::2], b[1::2])])
                if len(keyinfo[-1]) > keyinfo_size: keyinfo_size = len(keyinfo[-1])
            line = char + "\t"
            for k in range(keyinfo_size):
                line += '['
                s = list()
                for e in keyinfo:
                    if (len(e) <= k):
                        s.append("0000")
                    else:
                        s.append("%04X" % e[k])
                line += ".".join(s) + "]"
            textout = textout + line + "\n"
        self.tdia.set_text(textout)

    def get_file_open(self):
        dialog = gtk.FileChooserDialog("Open..", None, gtk.FILE_CHOOSER_ACTION_OPEN,
                 (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK))
        dialog.set_default_response(gtk.RESPONSE_OK)
        response = dialog.run()
        if response == gtk.RESPONSE_OK:
            res = dialog.get_filename()
        else:
            res = ''
        dialog.destroy()
        return res

    def get_file_save(self):
        dialog = gtk.FileChooserDialog("Open..", None, gtk.FILE_CHOOSER_ACTION_SAVE,
                 (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK))
        response = dialog.run()
        dialog.set_default_response(gtk.RESPONSE_OK)
        if response == gtk.RESPONSE_OK:
            res = dialog.get_filename()
        else:
            res = ''
        dialog.destroy()
        return res

    def on_save_src(self, widget):
        buf_src = self.builder.get_object("txt_src").get_buffer()
        fname = self.get_file_save()
        if fname:
            fileo = file(fname, "w")
            fileo.write(buf_src.get_text(buf_src.get_start_iter(), buf_src.get_end_iter(), False))
            fileo.close()

    def on_save_sort(self, widget):
        buf_srt = self.builder.get_object("txt_order").get_buffer()
        fname = self.get_file_save()
        if fname:
            fileo = file(fname, "w")
            fileo.write(buf_srt.get_text(buf_srt.get_start_iter(), buf_srt.get_end_iter(), False))
            fileo.close()

    def on_open_src(self, widget):
        fname = self.get_file_open()
        if fname:
            fileo = file(fname, "rU")
            buf_src = self.builder.get_object("txt_src").get_buffer()
            buf_src.set_text("".join(fileo.readlines()))
            fileo.close()
        
    def on_open_sort(self, widget):
        fname = self.get_file_open()
        if fname:
            fileo = file(fname, "rU")
            buf_srt = self.builder.get_object("txt_order").get_buffer()
            buf_srt.set_text("".join(fileo.readlines()))
            fileo.close()

    def on_set_src(self, widget):
        buf_srt = self.builder.get_object("txt_srt").get_buffer()
        buf_src = self.builder.get_object("txt_src").get_buffer()
        buf_src.set_text(buf_srt.get_text(buf_srt.get_start_iter(), buf_srt.get_end_iter(), False))

    def on_src_new(self, widget):
        self.builder.get_object("txt_src").get_buffer().set_text('')
        self.builder.get_object("txt_srt").get_buffer().set_text('')

    def on_srt_new(self, widget):
        self.builder.get_object("txt_order").get_buffer().set_text('')


class TextDialog:
    def __init__(self, builder):
        self.builder = builder
        self.signals = {
            "on_bt_ok_clicked" : self.quit,
            "on_sort_keys_delete_event" : lambda x: self.quit(x)
        }
        self.root = builder.get_object("sort_keys")
        self.root.hide()

    def set_text(self, text):
        tx_box = self.builder.get_object("txt_keys")
        buf = tx_box.get_buffer()
        buf.delete(buf.get_start_iter(), buf.get_end_iter())
        buf.set_text(text)
        self.root.show()

    def quit(self, widget):
        self.root.hide()
        return 1

if __name__ == "__main__":
    trainer = Trainer()
    Gtk.main()

