#!/usr/bin/env python

# View events and jpg images

import pygtk
pygtk.require('2.0')
import gtk
#import pango  #cell renderer alignment, couldn't get this to work
import glob
import os.path
import re
import datetime

GMOTION_DIR = "/usr/local/var/gmotion"
GROUP_DIR = "default"
JPG_WINDOW_COLS = 5
EVENT_END_GAP = 60  # seconds


class MainWindow:

    def delete_event(self, widget, event):
        return False
    
    def destroy(self, widget):
        gtk.main_quit()

    def get_motion_events(self):
        self.event_list_motion = list()  # List of events each coded as a tuple
        jpgs = [os.path.basename(fi) for fi in glob.glob(self.image_dir + '/*.jpg')]
        if jpgs:
            jpgs.sort()
            # YYYYMMDDHHMMSS, thread, event, frame, camera location if set ('[a-zA-Z0-9_]' chars)
            regexp = re.compile(r"(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})-(\d+)-(\d+)-(\d+)-{0,1}(\w*).jpg")
            curr_jpg = jpgs[0]
            while jpgs:
                matchobj = regexp.match(curr_jpg)
                # TODO raise an exception here if match returns None
                curr_motion_thread = matchobj.group(7)
                curr_motion_event = matchobj.group(8)
                event_key = matchobj.group(1), matchobj.group(2), matchobj.group(3), matchobj.group(4), matchobj.group(5), matchobj.group(6), matchobj.group(7), matchobj.group(10)
                self.event_list_motion.append(event_key)
                self.event_jpg[event_key] = []
                while True:
                    jpg = jpgs.pop(0)
                    self.event_jpg[event_key].insert(0, jpg)
                    if jpgs:
                        curr_jpg = jpgs[0]
                        matchobj = regexp.match(curr_jpg)
                        motion_thread = matchobj.group(7)
                        motion_event = matchobj.group(8)
                        if motion_thread != curr_motion_thread or motion_event != curr_motion_event:
                            break  # new event
                    else:  # no more images to process, exit
                        break
            self.event_list_motion.reverse()

    def concat_motion_events(self):
        gap = datetime.timedelta(0, EVENT_END_GAP)
        self.event_list_concat = self.event_list_motion[:]
        if self.event_list_concat:
            i = 0
            if i + 1 <= len(self.event_list_concat) - 1:
                more_events = True
            else:
                more_events = False
            while more_events:
                year, mnth, day, hh, mm, ss, thread, location = self.event_list_concat[i]
                date1 = datetime.datetime(int(year), int(mnth), int(day), int(hh), int(mm), int(ss))
                year, mnth, day, hh, mm, ss, thread, location = self.event_list_concat[i+1]
                date2 = datetime.datetime(int(year), int(mnth), int(day), int(hh), int(mm), int(ss))
                if date1 - date2 <= gap:
                    self.event_jpg[self.event_list_concat[i+1]][0:0] = self.event_jpg[self.event_list_concat[i]]
                    self.event_list_concat.pop(i)
                else:
                    i += 1
                if i + 1 <= len(self.event_list_concat) - 1:
                    more_events = True
                else:
                    more_events = False

    def create_event_treeview(self):  # combobox avail. PyGTK v2.4
        list_store = gtk.ListStore(str, gtk.gdk.Pixbuf)
        for row in range(len(self.event_list)):
            event_key = self.event_list[row]
            jpg_list = self.event_jpg[event_key]
            jpg_count = len(jpg_list)
            year, mnth, day, hh, mm, ss, thread, location = event_key
            chrono = datetime.datetime(int(year), int(mnth), int(day), int(hh), int(mm), int(ss))
            # %I hours in 12 hour format, %p AM/PM
            cell_markup = '<big>'+chrono.strftime("%H:%M")+' ('+str(jpg_count)+')'+'</big>'+"\n"+'<small>'+chrono.strftime("%a %d %b %Y")+'</small>'+"\n"
            cell_pix = gtk.gdk.pixbuf_new_from_file_at_size(self.image_dir + '/' + jpg_list[jpg_count-1], 100, 100)
            list_store.append((cell_markup, cell_pix,))
        col0 = gtk.TreeViewColumn()
        cell0 = gtk.CellRendererText()
        col0.pack_end(cell0, False)
        #col0.add_attribute(cell0, 'alignment', pango.ALIGN_CENTER)  # could not get this to work
        col0.add_attribute(cell0, 'markup', 0)
        col1 = gtk.TreeViewColumn()
        cell1 = gtk.CellRendererPixbuf()
        cell1.set_fixed_size(100, 100)
        col1.pack_end(cell1, False)
        col1.add_attribute(cell1, 'pixbuf', 1)
        self.event_treeview = gtk.TreeView(list_store)
        self.event_treeview.set_headers_visible(False)
        self.event_treeview.append_column(col0)
        self.event_treeview.append_column(col1)

    def create_jpg_table(self, idx):

        def create_image(jpg_offset, row, col):
            eventbox = gtk.EventBox()
            eventbox.connect_object("event", self.image_event_cb, eventbox)
            self.jpg_window_filenames[eventbox] = (EVENT_KEY, jpg_offset)
            image = gtk.Image()
            pix = gtk.gdk.pixbuf_new_from_file_at_size(self.image_dir + '/' + JPG_LIST[jpg_offset], 100, 100)
            image.set_from_pixbuf(pix)
            eventbox.add(image)
            image.show()
            self.jpg_table.attach(eventbox, col, col+1, row, row+1, gtk.SHRINK, gtk.SHRINK)
            eventbox.show()

        self.jpg_window_filenames = dict()  # tuple of event_list and jpg offset referencing jpg file
        EVENT_KEY = self.event_list[idx]
        JPG_LIST = self.event_jpg[EVENT_KEY]
        packed_rows_count, last_row_count = divmod(len(JPG_LIST), JPG_WINDOW_COLS)
        if not last_row_count:
            last_row_offset = packed_rows_count - 1
        else:
            last_row_offset = packed_rows_count
        self.jpg_table = gtk.Table(last_row_offset+1, JPG_WINDOW_COLS)
        self.jpg_table.set_row_spacings(20)
        self.jpg_table.set_col_spacings(20)
        self.jpg_table.set_border_width(20)
        for row in range(packed_rows_count):
            row_offset = row * JPG_WINDOW_COLS
            for col in range(JPG_WINDOW_COLS):
                create_image(row_offset + col, row, col)
        row_offset = packed_rows_count * JPG_WINDOW_COLS
        for col in range(last_row_count):
            create_image(row_offset + col, last_row_offset, col)

    def cursor_changed_cb(self, obj):
        selection = self.event_treeview.get_selection()
        model, iter = selection.get_selected()
        path_arry = model.get_path(iter)  # seems to default to return an array
        self.box.remove(self.jpg_window)
        self.jpg_window = gtk.ScrolledWindow()
        self.jpg_window.set_border_width(20)
        self.jpg_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self.create_jpg_table(path_arry[0])
        self.jpg_window.add_with_viewport(self.jpg_table)
        self.jpg_table.show()
        self.box.pack_start(self.jpg_window)
        self.jpg_window.show()
        # TODO change the jpg dialog image if open

    def image_viewer_response_cb(self, widget, response):
        # TODO add code to disable appropriate dialog button when at start or end
        if response == 1:  # '<' button
            jpg_list = self.event_jpg[self.image_viewer_eventkey]
            if self.image_viewer_offset < len(jpg_list) - 1:
                self.image_viewer_offset += 1
                self.image_viewer_reset_image(jpg_list[self.image_viewer_offset])
        elif response == 2:  # '>' button
            if self.image_viewer_offset > 0:
                self.image_viewer_offset -= 1
                self.image_viewer_reset_image(self.event_jpg[self.image_viewer_eventkey][self.image_viewer_offset])
        elif response == gtk.RESPONSE_DELETE_EVENT:
            self.image_viewer_dialog.destroy()
            self.image_viewer_dialog = self.image_viewer_image = self.image_viewer_eventkey = self.image_viewer_offset = None

    def image_event_cb(self, eventbox, event):
        t = getattr(event, 'type')
        if t == gtk.gdk.BUTTON_PRESS:
            self.image_viewer_eventkey, self.image_viewer_offset = self.jpg_window_filenames[eventbox]
            jpg = self.event_jpg[self.image_viewer_eventkey][self.image_viewer_offset]
            if not self.image_viewer_dialog:  # create the dialogue window
                self.image_viewer_dialog = gtk.Dialog(jpg, self.window, buttons = ("<", 1, ">", 2))
                self.image_viewer_dialog.connect_object('response', self.image_viewer_response_cb, self.image_viewer_dialog)
                self.image_viewer_image = gtk.Image()
                self.image_viewer_image.set_from_file(self.image_dir + '/' + jpg)
                self.image_viewer_dialog.vbox.pack_start(self.image_viewer_image)
                # TODO add jpg n out of num. jpgs label to vbox
                self.image_viewer_image.show()
                self.image_viewer_dialog.show()
            else:  # reset the image in the dialogue window
                self.image_viewer_reset_image(jpg)

    def image_viewer_reset_image(self, jpg):
        self.image_viewer_image.set_from_file(self.image_dir + '/'+jpg)
        self.image_viewer_dialog.set_title(jpg)
        self.image_viewer_dialog.show()

    def __init__(self):
        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.window.set_default_size(1000, 600)
        self.window.connect("delete_event", self.delete_event)
        self.window.connect("destroy", self.destroy)
        self.image_dir = GMOTION_DIR + "/Group/" + GROUP_DIR + "/Image"
        self.event_jpg = dict()  # lists of jpgs for events using the above tuple as a hash key
        self.get_motion_events()
        if not self.event_list_motion:
            lbl = gtk.Label("NO IMAGES TO SHOW")
            self.window.add(lbl)
            lbl.show()
        else:
            self.concat_motion_events()
            self.event_list = self.event_list_concat
            self.box = gtk.HBox()
            self.event_window = gtk.ScrolledWindow()
            self.event_window.set_border_width(20)
            self.event_window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
            self.create_event_treeview()
            self.event_treeview.connect_object("cursor-changed", self.cursor_changed_cb, self.event_treeview)
            self.event_window.add(self.event_treeview)
            self.event_treeview.show()
            self.box.pack_start(self.event_window, False)
            self.event_window.show()
            self.jpg_window = gtk.ScrolledWindow()  # initialise with null value!! (cursor_changed callback called at some point and needs this)
            self.image_viewer_dialog = None  # no image viewer dialogue open
            self.box.pack_start(self.jpg_window, False)
            self.window.add(self.box)
            self.box.show()
        self.window.show()

    def main(self):
        gtk.main()


print __name__
if __name__ == "__main__":
    base = MainWindow()
    base.main()
