"""
Calendar Toplevel Window
"""
#  Copyright (C) 2004  Henning Jacobs <henning@srcco.de>
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  $Id: CalendarWindow.py 82 2004-07-11 13:01:44Z henning $

import sys
import os
import string
from Tkinter import *
import tkMessageBox
import Pmw
import debug
import broadcaster
import broker
import time

class CalendarWindow:

    from JournalListWidget import JournalListWidget
    from JournalEditWidget import JournalEditWidget
    
    def __init__(self, model, tkroot=None):
        if not tkroot:
            tkroot = Tk()
            tkroot.withdraw()
        self.tkroot = tkroot
        self.model = model
        # Handle to DateStart Mapping:
        self._journaldates = {}
        
        self.createWidgets()
        self.centerWindow()
    
        self.registerAtBroadcaster()
        self.onJournalsOpen()
    
    def registerAtBroadcaster(self):
        "Register our Callback Handlers"
        broadcaster.Register(self.onJournalsOpen,
            source='Journals', title='Opened')
        broadcaster.Register(self.onJournalsClose,
            source='Journals', title='Closed')
        broadcaster.Register(self.onJournalNew,
            source='Journal', title='Added')
        broadcaster.Register(self.onJournalDel,
            source='Journal', title='Deleted')
        broadcaster.Register(self.onJournalSave,
            source='Journal', title='Saved')
        # Broadcasted by JournalWindow:    
        broadcaster.Register(self.onJournalOpen,
            source='Journal', title='Opened')
    
    def createWidgets(self):
        "create the top level window"
        top = self.top = Toplevel(self.tkroot, class_='CalendarWindow')
        top.protocol('WM_DELETE_WINDOW', self.close)
        top.title('Calendar')
        top.iconname('PyCoCuMa')
        try:
            os.chdir(os.path.dirname(sys.argv[0]))
            if sys.platform == "win32":
                top.iconbitmap("pycocuma.ico")
            else:
                top.iconbitmap("@pycocuma.xbm")
                top.iconmask("@pycocuma_mask.xbm")
        except:
            debug.echo("Could not set TopLevel window icon")
        
        top.withdraw()

        from CalendarWidget import CalendarWidget
        
        self.monthdisp = CalendarWidget(top,
            selectcommand=self._daySelect,
            dblclickcommand=self._dayDblClick)
        self.monthdisp.grid()

    def centerWindow(self, relx=0.5, rely=0.3):
        "Center the Main Window on Screen"
        widget = self.top
        master = self.tkroot
        widget.update_idletasks() # Actualize geometry information
        if master.winfo_ismapped():
            m_width = master.winfo_width()
            m_height = master.winfo_height()
            m_x = master.winfo_rootx()
            m_y = master.winfo_rooty()
        else:
            m_width = master.winfo_screenwidth()
            m_height = master.winfo_screenheight()
            m_x = m_y = 0
        w_width = widget.winfo_reqwidth()
        w_height = widget.winfo_reqheight()
        x = m_x + (m_width - w_width) * relx
        y = m_y + (m_height - w_height) * rely
        if x+w_width > master.winfo_screenwidth():
            x = master.winfo_screenwidth() - w_width
        elif x < 0:
            x = 0
        if y+w_height > master.winfo_screenheight():
            y = master.winfo_screenheight() - w_height
        elif y < 0:
            y = 0
        widget.geometry("+%d+%d" % (x, y))
        widget.deiconify() # Become visible at the desired location

    def _daySelect(self, date, createnew=0):
        # This variable prevents a looping callback:
        self._indayselectcallback = 1
        datadict = {'date':date}
        if createnew: datadict['createnew'] = createnew
        broadcaster.Broadcast('Calendar', 'Date Selected', data=datadict)
        self._indayselectcallback = 0
        
    def _dayDblClick(self, date):
        self.top.event_generate('<<view-journal>>')
        if self.monthdisp.getmarks().has_key(date):
            self._daySelect(date, createnew=0)
        else:
            # Create New Journal Entry for a free day
            self._daySelect(date, createnew=1)
    
    
    def onJournalsOpen(self):
        "Callback, triggered on Broadcast"
        handles = self.model.ListJournalHandles()
        # take only the first 10 chars from dtstart, remainder could be time:
        dates = map(lambda x: x[:10],
            self.model.QueryJournalAttributes(handles, 'DateStart'))
        self._journaldates = dict(zip(handles, dates))
        self.monthdisp.setmarks(dict(zip(dates,[None]*len(dates))))
        
    def onJournalsClose(self):
        "Callback, triggered on Broadcast"
        self.monthdisp.setmarks({})

    _indayselectcallback = 0
    def onJournalOpen(self):
        "Callback, triggered on Broadcast by JournalWindow"
        if not self._indayselectcallback:
            # dtstart may include time, we take only the first 10 characters:
            year, month, day = tuple(map(int,
                broadcaster.CurrentData()['dtstart'][:10].split('-')))
            self.monthdisp.setmonth(year, month)
            self.monthdisp.setday(day)
     
    def onJournalNew(self):
        "Callback, registered at Broadcaster"
        handle = broadcaster.CurrentData()['handle']
        date = broadcaster.CurrentData()['dtstart'][:10]
        self._journaldates[handle] = date
        self.monthdisp.getmarks()[date] = 1
        self.monthdisp.update()
        
    def onJournalDel(self):
        "Callback, registered at Broadcaster"
        handle = broadcaster.CurrentData()['handle']
        date = self._journaldates[handle]
        del self._journaldates[handle]
        del self.monthdisp.getmarks()[date]
        self.monthdisp.update()
        
    def onJournalSave(self):
        "Callback, registered at Broadcaster"
        handle = broadcaster.CurrentData()['handle']
        # Maybe the entry's date changed:
        # we take only the first 10 chars, because dtstart may include time:
        date = self.model.QueryJournalAttributes([handle], 'DateStart')[0][:10]
        # this mapping is for onDel only:
        olddate = self._journaldates[handle]
        if olddate != date:
            self._journaldates[handle] = date
            del self.monthdisp.getmarks()[olddate]
            self.monthdisp.getmarks()[date] = 1
            self.monthdisp.update()
        
    def close(self, event=None):
        self.top.withdraw()
    
    def window(self):
        "Returns Tk's TopLevel Widget"
        return self.top
    
    def withdraw(self):
        "Withdraw: Forward to TopLevel Method"
        self.top.withdraw()
    
    def deiconify(self):
        "DeIconify: Forward to TopLevel Method"
        self.top.deiconify()

    def show(self):
        self.top.deiconify()
        self.top.lift()
        self.top.focus_set()
        
