import animate

from gi.repository import GObject, Gtk, Pango, Gdk
from xml.etree import ElementTree as ET

class Section(Gtk.VBox):
    def __init__(self, section):
        super(Section, self).__init__()
        self.name = section.get('id')
        self.get_style_context().add_class('section-body')
        self.title = Gtk.EventBox()
        self.label = Gtk.Label('Section %s' % self.name)
        self.label.get_style_context().add_class('section-title')
        self.title.add(self.label)
        self.title.connect('button-press-event', self.clicked)
        self.handler = None
        #cursor = Gdk.Cursor(Gdk.CursorType.HAND1)
        #self.label.get_window().set_cursor(cursor)
        self.pack_start(self.title, True, True, 5)
        self.sequences = []

        num = 1
        for sequence in section.findall('./sequence'):
            self.sequences.append(Sequence(sequence, section.get('id') + '.' + str(num)))
            self.pack_start(self.sequences[-1], True, True, 5)
            num += 1

    def highlight(self, active=True):
        if active:
            self.label.get_style_context().remove_class('section-title')
            self.label.get_style_context().add_class('selected-section-title')
            self.get_style_context().add_class('selected-section-body')
            self.get_style_context().remove_class('section-body')
        else:
            self.label.get_style_context().remove_class('selected-section-title')
            self.label.get_style_context().add_class('section-title')
            self.get_style_context().remove_class('selected-section-body')
            self.get_style_context().add_class('section-body')

    def clicked(self, widget, event):
        if self.handler:
            self.handler(int(self.name) - 1)

    def set_handler(self, handler):
        self.handler = handler


class Sequence(Gtk.VBox):
    def __init__(self, sequence, name):
        super(Sequence, self).__init__()
        self.name = name
        self.get_style_context().add_class('sequence-body')
        self.label = Gtk.Label('Sequence %s' % name)
        self.label.get_style_context().add_class('sequence-title')
        self.pack_start(self.label, True, True, 5)

        self.lines = []
        elements = []
        for line in sequence.text.split('\n'):
            line = line.strip()
            if line != '':
                elements.append(Text(line))
            if len(elements) > 0:
                self.lines.append(Line(elements))
                self.pack_start(self.lines[-1], True, True, 5)
            elements = []
        for node in sequence:
            if node.tag == 'keyword':
                text = str(node.text).strip()
                if node.get('action').strip() != '':
                    elements.append(Keyword(text, node.get('action'), node.get('lang')))
                else:
                    elements.append(Text(text))
            for line in node.tail.split('\n'):
                line = line.strip()
                if line != '':
                    elements.append(Text(line))
                if len(elements) > 0:
                    self.lines.append(Line(elements))
                    self.pack_start(self.lines[-1], True, True, 5)
                elements = []
        if len(elements) > 0:
            self.lines.append(Line(elements))
            self.pack_start(self.lines[-1], True, True, 5)

class Line(Gtk.HBox):
    def __init__(self, elements):
        super(Line, self).__init__()
        self.pack_start(Gtk.Label('   '), False, False, 0)
        for element in elements:
            self.pack_start(element, False, False, 0)
        self.elements = elements
        self.get_style_context().add_class('text-line')
    
    def set_handler(self, handler):
        for element in self.elements:
            if hasattr(element, 'set_handler'):
                element.set_handler(handler)

    def highlight(self, active=True):
        if active:
            self.label.get_style_context().add_class('highlighted')
        else:
            self.label.get_style_context().remove_class('highlighted')

class Keyword(Gtk.Label):
    def __init__(self, text, action, lang):
        super(Keyword, self).__init__()
        self.action = action
        self.lang = lang
        text = '\n'.join([x.strip() for x in text.split('\n')])
        self.set_markup(text + ' [<a href="%s">%s</a>] ' % (action, action))
        self.get_style_context().add_class('keyword')
        self.connect('activate-link', self.link_clicked)
        self.handler = None

    def set_handler(self, handler):
        self.handler = handler

    def link_clicked(self, widget, uri):
        if self.handler:
            self.handler(uri)
        return True

class Text(Gtk.Label):
    def __init__(self, text):
        super(Text, self).__init__()
        text = '\n'.join([x.strip() for x in text.split('\n')])
        self.set_text(text + ' ')
        self.get_style_context().add_class('text')

class XmlView(Gtk.ScrolledWindow):
    def __init__(self, filename):
        super(XmlView, self).__init__()
        self.sections = []
        self.words = []

        self.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.ALWAYS)

        self.vbox = self.parse_xml(filename)
        self.add_with_viewport(self.vbox)

        self.last_section = None
        self.connect('scroll-event', lambda widget, event: animate.cancel())

    def get_view(self):
        return self

    def parse_xml(self, filename):
        self.sections = []
        root = ET.parse(filename)
        vbox = Gtk.VBox()
        vbox.get_style_context().add_class('xmlview')
        for section in root.findall(".//section"):
            self.sections.append(Section(section))
            vbox.pack_start(self.sections[-1], True, True, 5)
        return vbox

    def set_action_clicked_handler(self, handler):
        for line in self.get_line_iterator():
            line.set_handler(handler)

    def get_line_iterator(self):
        for section in self.sections:
            for sequence in section.sequences:
                for line in sequence.lines:
                    yield line

    def highlight_section(self, section):
        if section < 1 or section > len(self.sections):
            print "invalid section", section
        else:
            for current in range(len(self.sections)):
                self.sections[current].highlight(current == section - 1)
            animate.scroll_to(self, self.sections[section - 1])