import pygtk
pygtk.require('2.0')
import gtk, gobject, glib, cairo, pango

import erapp
from sheet import *
import erutils

#gtk.pygtk_version
#gtk.gtk_version

class CommandArea(gtk.HBox):
    def __init__(self):
        gtk.HBox.__init__(self)
        self.homogeneous = False
        self.spacing = 0
        #hdr = gtk.Label("")
        #hdr.set_markup("<b><span size='xx-large'>Command Area</span></b>")
        #self.pack_start(hdr, True, True, 10)

        # HOME
        self.btn_home = gtk.Button()
        self.btn_home.set_relief(gtk.RELIEF_NONE)
        image = gtk.Image()
        image.set_from_stock(gtk.STOCK_HOME, gtk.ICON_SIZE_LARGE_TOOLBAR)
        self.btn_home.set_image(image)
        self.btn_home.connect("clicked", lambda w: app.go_home())
        self.pack_start(self.btn_home, False, False, 0)

        # LEFT
        self.btn_left = gtk.Button()
        self.btn_left.set_relief(gtk.RELIEF_NONE)
        image = gtk.Image()
        image.set_from_stock(gtk.STOCK_GO_BACK, gtk.ICON_SIZE_LARGE_TOOLBAR)
        self.btn_left.set_image(image)
        self.btn_left.connect("clicked", lambda w: app.go_left(1))
        self.pack_start(self.btn_left, False, False, 0)

        # RIGHT
        self.btn_right = gtk.Button()
        self.btn_right.set_relief(gtk.RELIEF_NONE)
        image = gtk.Image()
        image.set_from_stock(gtk.STOCK_GO_FORWARD, gtk.ICON_SIZE_LARGE_TOOLBAR)
        self.btn_right.set_image(image)
        self.btn_right.connect("clicked", lambda w: app.go_right(1))
        self.pack_start(self.btn_right, False, False, 0)

        # DOWN
        self.btn_down = gtk.Button()
        self.btn_down.set_relief(gtk.RELIEF_NONE)
        image = gtk.Image()
        image.set_from_stock(gtk.STOCK_GO_DOWN, gtk.ICON_SIZE_LARGE_TOOLBAR)
        self.btn_down.set_image(image)
        self.btn_down.connect("clicked", lambda w: app.go_down(1))
        self.pack_start(self.btn_down, False, False, 0)

        # UP
        self.btn_up = gtk.Button()
        self.btn_up.set_relief(gtk.RELIEF_NONE)
        image = gtk.Image()
        image.set_from_stock(gtk.STOCK_GO_UP, gtk.ICON_SIZE_LARGE_TOOLBAR)
        self.btn_up.set_image(image)
        self.btn_up.connect("clicked", lambda w: app.go_up(1))
        self.pack_start(self.btn_up, False, False, 0)

        # LOAD
        self.btn_load = gtk.Button()
        self.btn_load.set_relief(gtk.RELIEF_NONE)
        image = gtk.Image()
        image.set_from_stock(gtk.STOCK_OPEN, gtk.ICON_SIZE_LARGE_TOOLBAR)
        self.btn_load.set_image(image)
        self.btn_load.connect("clicked", lambda w: app.do_load())
        self.pack_start(self.btn_load, False, False, 0)

        # CLOSE
        self.btn_close = gtk.Button()
        self.btn_close.set_relief(gtk.RELIEF_NONE)
        image = gtk.Image()
        image.set_from_stock(gtk.STOCK_STOP, gtk.ICON_SIZE_LARGE_TOOLBAR)
        self.btn_close.set_image(image)
        self.btn_close.connect("clicked", lambda w: app.do_close())
        self.pack_end(self.btn_close, False, False, 0)


class CellArea(gtk.DrawingArea):
    # Signal handlers
    __gsignals__ = { "configure-event": "override",
                     "expose-event": "override",
                     "button-press-event": "override"}

    def __init__(self):
        gtk.DrawingArea.__init__(self)
        self.set_double_buffered(False)
        self.set_app_paintable(True)
        self.add_events(gtk.gdk.BUTTON_PRESS_MASK)
        self.col_width_list = None
        self.row_height_list = None
        self.start_x = 0
        self.start_y = 0
        self.erutils = erutils.ErUtils()

    def do_configure_event(self, ev):
        self.width = ev.width
        self.height = ev.height
        return True

    def do_expose_event(self, ev):
        ctx = self.window.cairo_create()
        ctx.set_source_rgb(1.0, 1.0, 1.0)
        ctx.set_operator(cairo.OPERATOR_SOURCE)
        ctx.paint()
        # get sheet
        sheet = app.get_sheet(0)
        # draw the headers
        ## width of left size header and height of top header
        header_height = sheet.get_col_properties().find_property('header-height')
        self.header_height = header_height
        header_width = sheet.get_row_properties().find_property('header-width')
        self.header_width = header_width
        
        ## get column sizes
        col_width_list = sheet.get_col_widths(header_width, self.width)
        self.nr_cols = len(col_width_list)
        if self.col_width_list != None:
            del self.col_width_list
        self.col_width_list = col_width_list
        
        ## get row sizes
        row_height_list = sheet.get_row_heights(header_height, self.height) 
        self.nr_rows = len(row_height_list)
        if self.row_height_list != None:
            del self.row_height_list
        self.row_height_list = row_height_list
        print "cols=%d rows=%d" %(self.nr_cols, self.nr_rows)
        
        # and draw them
        self.draw_col_header(ctx, header_width, 0,
                             self.width-header_width, header_height,
                             col_width_list, self.start_x)
        self.draw_row_header(ctx, 0, header_height,
                             header_width, self.height-header_height,
                             row_height_list, self.start_y)
        self.draw_cell_borders(ctx, header_width, header_height,
                               self.width-header_width, self.height-header_height,
                               col_width_list, row_height_list)
        self.draw_cells(ctx, header_width, header_height,
                        self.width-header_width, self.height-header_height,
                        col_width_list, row_height_list, sheet,
                        self.start_x, self.start_y)
        return True

    def do_button_press_event(self, ev):
        #print "Position: %dx%d" % (ev.x, ev.y)
        x = self.header_width
        col = -1
        if x <= ev.x:
            col = 0
            for col_w in self.col_width_list:
                if x + col_w > ev.x:
                    break
                col += 1
                x += col_w

        y = self.header_height
        row = -1
        if y <= ev.y:
            row = 0
            for row_h in self.row_height_list:
                if y + row_h > ev.y:
                    break
                row += 1
                y += row_h

        print "Cell (%d,%d)" % (col, row)
        return True
    
    def draw_col_header(self, ctx, x, y, w, h, col_width_list, start):
        # draw properties
        ctx.set_source_rgb(0.0, 0.0, 0.0)
        ctx.set_line_width(2.0)
        ctx.set_line_join(cairo.LINE_JOIN_ROUND)
        ctx.select_font_face("Times",
            cairo.FONT_SLANT_NORMAL)
        ctx.set_font_size(16)
        # determine number of columns that fit
        col = start
        col_names = "ABCDEFGHIJKLMNOPQRSTUVW"
        sum_width = 0
        for col_w in col_width_list:
            ctx.rectangle(x + sum_width, y, col_w, h)
            ctx.stroke()
            x_bearing, y_bearing, width, height = ctx.text_extents(col_names[col])[:4]
            # position: center of cell: x + sum_width + col_w / 2, h/2
            ctx.move_to(x + sum_width + col_w / 2 - width/2 - x_bearing,
                        h/2 - height/2 - y_bearing)
            ctx.show_text(col_names[col])
            sum_width += col_w
            col += 1

    def draw_row_header(self, ctx, x, y, w, h, row_height_list, start):
        # draw properties
        ctx.set_source_rgb(0.0, 0.0, 0.0)
        ctx.set_line_width(2.0)
        ctx.set_line_join(cairo.LINE_JOIN_ROUND)
        ctx.select_font_face("Times",
            cairo.FONT_SLANT_NORMAL)
        ctx.set_font_size(16)
        # determine number of rows that fit
        row = start
        sum_height = 0
        for row_h in row_height_list:
            ctx.rectangle(x, y + sum_height, w, row_h)
            ctx.stroke()
            row_name = str(row+1)
            x_bearing, y_bearing, width, height = ctx.text_extents(row_name)[:4]
            # position: center of cell: x + w/2, y + sum_height + row_h/2
            ctx.move_to(x + w/2 - width/2 - x_bearing,
                        y + sum_height + row_h/2 - height/2 - y_bearing)
            ctx.show_text(row_name)
            sum_height += row_h
            row += 1
            
    def draw_cell_borders(self, ctx, x, y, w, h, col_width_list, row_height_list):
        # draw properties
        ctx.set_source_rgb(0.5, 0.5, 0.5)
        ctx.set_line_width(1.0)
        # columns
        sum_width = x
        for col_w in col_width_list:
            sum_width += col_w
            ctx.move_to(sum_width, y)
            ctx.line_to(sum_width, y+h)
        ctx.stroke()
        # rows
        sum_height = y
        for row_h in row_height_list:
            sum_height += row_h
            ctx.move_to(x, sum_height)
            ctx.line_to(x+w, sum_height)
        ctx.stroke()

    def draw_cells(self, ctx, x, y, w, h, col_width_list, row_height_list, sheet, start_x, start_y):
        # draw properties
        ctx.set_source_rgb(0.0, 0.0, 0.0)
        ctx.set_line_width(2.0)
        ctx.set_line_join(cairo.LINE_JOIN_ROUND)
        ctx.select_font_face("Times",
            cairo.FONT_SLANT_NORMAL)
        ctx.set_font_size(16)
        # determine number of rows that fit
        sum_height = y
        row_nr = start_y
        for row_h in row_height_list:
            sum_width = x
            col_nr = start_x
            for col_w in col_width_list:
                cell = sheet.get_cell(col_nr, row_nr)
                if cell != None:
                    text = cell.get_value()
                    x_bearing, y_bearing, width, height = ctx.text_extents(text)[:4]
                    # position: left of cell:
                    ctx.move_to(x + sum_width + 1 - width/2 - x_bearing,
                                y + sum_height + row_h/2 - height/2 - y_bearing)
                    ctx.show_text(text)
                sum_width += col_w
                col_nr += 1
            sum_height += row_h
            row_nr += 1
                    
    def do_left(self, step):
        self.start_x -= step
        if self.start_x < 0:
            self.start_x = 0
        self.update()

    def do_right(self, step):
        self.start_x += step
        if self.start_x > 20:
            # limit scrolling
            self.start_x = 20
        self.update()

    def do_up(self, step):
        self.start_y -= step
        if self.start_y < 0:
            self.start_y = 0
        self.update()

    def do_down(self, step):
        self.start_y += step
        if self.start_y > 1000:
            # limit scrolling
            self.start_y = 1000
        self.update()

    def do_goto(self, x, y):
        self.start_x = x
        self.start_y = y
        self.update()

    def update(self):
        #if not self.get_realized():
        #    print "Not yet realized"
        #    return
        self.do_expose_event(None)
        
        # update display
        self.erutils.display_gain_control()
        self.erutils.display_update_return_control(1) # DM_HINT_FULL

class StatusArea(gtk.HBox):
    def __init__(self):
        gtk.HBox.__init__(self)
        self.homogeneous = False
        self.spacing = 0
        self.set_size_request(-1, 20)
        hdr = gtk.Label("")
        hdr.set_markup("<b><span size='xx-large'>Status Area</span></b>")
        self.pack_start(hdr, True, True, 10)

class AppWindow(gtk.VBox):
    def __init__(self):
        gtk.VBox.__init__(self)
        self.homogeneous = False
        self.spacing = 0
        # Command Area
        self.command_area = CommandArea()
        self.pack_start(self.command_area, False, False, 0)
        # Cell Area
        self.cell_area = CellArea()
        self.pack_start(self.cell_area, True, True, 0)
        # Status Area
        self.status_area = StatusArea()
        self.pack_start(self.status_area, False, False, 0)

def on_send_startup_complete():
    win = app.window.xid
    app.ipc.send_startup_complete(win)
    return False

class AppCalc(erapp.DrApplication, gtk.Window):
    def __init__(self):
        gtk.Window.__init__(self)
        # trying to change the name of the window ...
        self.build_ui()
        self.build_dr()
        glib.idle_add(on_send_startup_complete)
        # create an empty sheet
        self.sheet = Sheet('Sheet1')

    def get_sheet(self, nr):
        return self.sheet
    
    def build_ui(self):
        self.set_title("calc")
        self.connect("destroy", self.on_quit)
        # Create content
        self.app_win = AppWindow()
        self.add(self.app_win)
        self.show_all()

    def on_quit(self, widget):
        print "Quiting"
        gtk.main_quit()
        pass

    def build_dr(self):
        # For the name no spaces are allowed, only use lower case characters
        self.ipc = erapp.DrIpc("calc", "1.0", self);
        menu_manager = erapp.MenuManager(self.ipc);
        self.menu_manager = menu_manager
        # menu
        menu_main = erapp.Menu(menu_manager, "menumain", "Calc");
        self.menu_main = menu_main
        group_main = menu_main.addGroup("groupmain", "Main Buttons");

        group_main.addItem("close",       "Close",        "close");
        group_main.addItem("load",        "Load",         "open");
	menu_main.realise();

        # toolbar
        menu_manager.add_toolbar_item("calc_menumain", "calc_groupmain",  "close");
        menu_manager.add_toolbar_item("calc_menumain", "calc_groupmain",  "open");
        
        menu_main.show();

    def onMenuClick(self, item, group, menu, state):
        print 'onMenuClick'
        # group in concatenation of ipc-name and group-name
        if group == "calc_groupmain":
            if item == "close":
                self.do_close()
            elif item == "load":
                self.do_load()

    def onFileOpen(self, filename):
        print 'onFileOpen'

    def onFileClose(self, filename):
        print 'onFileClose'

    def onWindowChange(self, xid, activated):
        print 'onWindowChange'
        if activated:
            self.menu_main.show()

    def onPrepareUnmount(self, device):
        print 'onPrepareUnmount'

    def onUnmounted(self, device):
        print 'onUnmounted'

    def onMounted(self, device):
        print 'onMounted'

    def onPrepareHibernate(self):
        print 'onPrepareHibernate'

    def onChangeLocale(self, locale):
        print 'onChangeLocale'

    def onChangedOrientation(self, orientation):
        print 'onChangedOrientation'

    def getMainWindow(self):
        return self

    def go_left(self, step):
        self.app_win.cell_area.do_left(step)
        
    def go_right(self, step):
        self.app_win.cell_area.do_right(step)

    def go_up(self, step):
        self.app_win.cell_area.do_up(step)

    def go_down(self, step):
        self.app_win.cell_area.do_down(step)
        
    def go_home(self):
        self.app_win.cell_area.do_goto(0, 0)
        
    def do_close(self):
        self.on_quit(None)
        
    def do_load(self):
        filename = self.run_open_dialog2()
        if filename != None:
            self.sheet.load_from_csv(filename)
        self.app_win.cell_area.update()

    def dialog_size_changed(self, widget, dialog):
        width = 700
        height = 700
        dialog.set_size_request(width, height)
        dialog.set_resizable(True)

    def run_open_dialog(self):
        dialog = gtk.FileChooserDialog( "Open..", None,
                                        gtk.FILE_CHOOSER_ACTION_OPEN,
                                        (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
                                         gtk.STOCK_OPEN, gtk.RESPONSE_OK),
                                        None)
        dialog.set_default_response(gtk.RESPONSE_OK)
        dialog.set_default_size(500, 500)
        #dialog.set_size_request(700, 500)
        #dialog.set_resizable(True)

        #dialog.connect("default-size-changed", lambda w: self.dialog_size_changed(w, dialog))
        
        filter = gtk.FileFilter()
        filter.set_name("csv files")
        filter.add_pattern("*.csv")
        dialog.add_filter(filter)
        filter = gtk.FileFilter()
        filter.set_name("All files")
        filter.add_pattern("*")
        dialog.add_filter(filter)

        response = dialog.run()
        if response == gtk.RESPONSE_OK:
            filename = dialog.get_filename()
        elif response == gtk.RESPONSE_CANCEL:
            filename = None
        dialog.destroy()

        return filename

    def dialog_default_size_changed_cb(self, widget, dialog):
        width = 700
        height = 700
        dialog.set_size_request(width, height)
        dialog.set_resizable(True)

    def dialog_response_requested_cb(self, widget, dialog):
        print "dialog_response_requested_cb"
    
    def dialog_file_activated_cb(self, widget, dialog):
        if dialog.activate_default():
            return
        print  'dialog_file_activated_cb: no default'
    
    def run_open_dialog2(self):
        dialog = gtk.Dialog( "Open..", None,
                             gtk.DIALOG_DESTROY_WITH_PARENT,
                             (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
                              gtk.STOCK_OPEN, gtk.RESPONSE_OK))
        dialog.set_has_separator(False)
        dialog.set_border_width(5)
        dialog.vbox.set_spacing(2)
        dialog.action_area.set_border_width(5)
        dialog.set_default_response(gtk.RESPONSE_OK)

        #dialog.connect("response", self.dialog_response_cb)
        widget = gtk.FileChooserWidget()
        widget.connect("file-activated", lambda w: self.dialog_file_activated_cb(w, dialog))
        widget.connect("default-size-changed", lambda w: self.dialog_default_size_changed_cb(w, dialog))
        widget.connect("response-requested", lambda w: self.dialog_response_requested_cb(w, dialog))

        widget.set_border_width(5)
        dialog.vbox.pack_start(widget, True, True, 0)

        filter = gtk.FileFilter()
        filter.set_name("csv files")
        filter.add_pattern("*.csv")
        widget.add_filter(filter)
        filter = gtk.FileFilter()
        filter.set_name("All files")
        filter.add_pattern("*")
        widget.add_filter(filter)

        widget.set_action(gtk.FILE_CHOOSER_ACTION_OPEN)

        widget.show()

        if dialog.run() != gtk.RESPONSE_OK:
            dialog.destroy()
            return None

        filename = widget.get_filename()
        dialog.destroy()

        return filename

        
app = AppCalc()
gtk.main()
