html_cal.py

'''\
HTML TABLE Calendar class.

classes:
    html_cal <<object>>
        .dotw       - "Sun", "Mon",..
        .days       - "Sunday", "Monday",..
        .curr_dt()
        .curr_weekday()

functions:
    make_web_calendar (props)

Developer@Sonnack.com
April 2016
'''
####################################################################################################
from sys import stdinstdoutstderrargv
from os import path
from datetime import datedatetimetimedelta
from htmlpage import htmlpage
####################################################################################################

##------------------------------------------------------------------------------------------------##
DefaultProperties = {
    'year':2000,
    'filename': '%04d.html',

    'title': 'Calendar',
    'h1' : 'Sonnack.com',
    'h2' : 'Publications',
    'css': ['/basic.css','calendar.css'],
    'js' : None,

    'cb:year' : lambda x: x.dt1.strftime('%Y'),
    'cb:month': lambda x: x.dt1.strftime('%b'),
    'cb:day'  : lambda x: x.dt1.strftime('%d'),
    'cb:prev' : None,
    'cb:next' : None,
}


##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~##
class html_cal (object):
    '''\
HTML TABLE Calender class.

Emits an HTML <TABLE> version of a calender.
'''
    dotw = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']
    days = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday']

    def __init__ (selfyr):
        self.dt0 = date(yr11)
        self.dt1 = date(yr11)
        self.fmt = '%Y'
        self.one_day = timedelta(1)
        self.cal_head = '<th colspan="3">%d days</th>' % len(self)
        self.cal_foot = '<th colspan="3">&copy; cjsonnack</th>'
        self.month_head = reduce(lambda acc,n: '%s<th>%s</th>' % (acc,self.dotw[n]), range(7), '')
        self.month_foot = self.month_head
        self.properties = {'caption':str(self.dt0.year), 'cb:day':None,'cb:month':None,'cb:year':None'cb:prev':None,'cb:next':None}

    def curr_dt (self):
        return self.dt1

    def curr_weekday (self):
        '''Returns {Su=0,M=1,Tu=2,W=3,Th=4,F=5,Sa=6} on cursor date.'''
        return ((self.dt1.weekday() + 1) % 7)

    def writepage (selffp):
        cap = self._callback_year(self.properties['caption'])
        cb_prev = self.properties['cb:prev']
        cb_next = self.properties['cb:next']
        ht_prev = cb_prev(self.dt0.year - 1if cb_prev else ''
        ht_next = cb_next(self.dt0.year + 1if cb_next else ''
        print >> fp
        print >> fp'<table class="CalendarBody">'
        print >> fp'<caption>%s%s%s</caption>' % (ht_prevcapht_next)   
        print >> fp'<thead><tr>%s</tr></thead>' % self.cal_head
        print >> fp'<tfoot><tr>%s</tr></tfoot>' % self.cal_foot
        self._write_body(fp)
        print >> fp'</table>'
        print >> fp

    def _write_body (selffp):
        print >> fp'<tbody>'
        # Each year row has three months...
        for row in [0369]:
            print >> fp'<tr>'
            for col in [123]:
                print >> fp'<td>'
                self._write_month(fprow+col)
                print >> fp'</td>'
            print >> fp'</tr>'
        print >> fp'<tr><th colspan="3">&nbsp;</th></tr>'
        print >> fp'</tbody>'

    def _write_month (selffpm):
        self.dt1 = date(self.dt0.yearm1)
        cap = self._callback_month(self.dt1.strftime('%B'))
        print >> fp'<table class="CalendarMonth">'
        print >> fp'<caption>%s</caption>' % cap
        print >> fp'<thead><tr>%s</tr></thead>' % self.month_head
        print >> fp'<tfoot><tr>%s</tr></tfoot>' % self.month_foot
        self._month_body(fpm)
        print >> fp'</table>'
        print >> fp

    def _month_body (selffpm):
        start_day = self.curr_weekday()
        start_flag = False
        print >> fp'<tbody>'
        # A month has six weeks...
        for row in range(6):
            print >> fp'<tr>'
            # Each row has seven days...
            for d in range(7):
                if start_flag:
                    if m == self.dt1.month:
                        self._month_day(fp)
                    else:
                        print >> fp'<td>&nbsp;</td>'
                else:
                    if d < start_day:
                        print >> fp'<td>&nbsp;</td>'
                    else:
                        start_flag = True
                        self._month_day(fp)
            print >> fp'</tr>'
        print >> fp'</tbody>'

    def _month_day (selffp):
        cls = self.days[self.curr_weekday()]
        txt = self._callback_day(str(self.dt1.day))
        print >> fp'<td class="%s">%s</td>' % (clstxt)
        # bump to next day...
        self.dt1 = self.dt1 + self.one_day

    def _callback_year (selfs):
        if 'cb:year' in self.properties:
            cb = self.properties['cb:year']
            if cb:
                try:
                    return cb(self)
                except Exception as e:
                    print >> stderre
        return s

    def _callback_month (selfs):
        if 'cb:month' in self.properties:
            cb = self.properties['cb:month']
            if cb:
                try:
                    return cb(self)
                except Exception as e:
                    print >> stderre
        return s

    def _callback_day (selfs):
        if 'cb:day' in self.properties:
            cb = self.properties['cb:day']
            if cb:
                try:
                    return cb(self)
                except Exception as e:
                    print >> stderre
        return s

    def __len__ (self):
        '''Returns number of days in the year.'''
        this_year = date(self.dt0.year  , 11)
        next_year = date(self.dt0.year+111)
        td = next_year - this_year
        return td.days

    def __str__ (self):
        return self.dt0.strftime(self.fmt)

    def __repr__ (self):
        s = '{html_cal:{date:%s, format:%s}}'
        t = (self.dt0self.fmt)
        return s % t

##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~##
class html_cal_pw (object):
    def __init__ (selfcal):
        self.cal = cal

    def writepage (selffp):
        print >> fp
        self.cal.writepage(fp)
        print >> fp


##================================================================================================##
def make_web_calendar (props):
    '''\
Make Web Calendar.

input properties:
    year            - calendar year
    filename        - filename (requires embedded %s or %d)
    title h1, h2    - HTML Title and H1 & H2 banner
    css, js         - HTML CSS & Javascript links
    cb:year         - callback function to print calendar Year
    cb:month        - callback function to print calendar Month
    cb:day          - callback function to print calendar Date
    cb:prev         - callback function to print "previous year" link
    cb:next         - callback function to print "next year" link

returns:
    [calendar-object, "file-name"]

'''
    # New Calendar instance...
    cal = html_cal(props['year'])
    cal.properties['cb:year']  = props['cb:year']
    cal.properties['cb:month'] = props['cb:month']
    cal.properties['cb:day']   = props['cb:day']
    cal.properties['cb:prev']  = props['cb:prev']
    cal.properties['cb:next']  = props['cb:next']

    # Generate HTML page...
    filename = props['filename'] % props['year']
    fp = open(filename'w')
    try:
        ttl  = props['title']
        hdr1 = props['h1']
        hdr2 = props['h2']
        css  = props['css']
        # Create page...
        pg = htmlpage(ttlh1=hdr1h2=hdr2csspages=css)
        pg.writepage(fphtml_cal_pw(cal))
        print 'wrote: %s' % filename
    except:
        raise
    finally:
        fp.close()
    return [calfilename]


##================================================================================================##
def do_test (*args):
    print 'test/parameters: %d' % len(args)
    DefaultProperties['year'] = 1955
    return make_web_calendar(DefaultProperties)
##================================================================================================##
def do_demo (*args):
    print 'demo/parameters: %d' % len(args)
    a = []
    for yr in range(20002017):
        DefaultProperties['year'] = yr
        g = make_web_calendar(DefaultProperties)
        a.append(g[1])
    return a
##================================================================================================##
def do_main (*args):
    print 'main/parameters: %d' % len(args)
    yr = int(args[0]) if 0 < len(argselse 2017
    DefaultProperties['year'] = yr
    return make_web_calendar(DefaultProperties)
####################################################################################################
def dispatch (cmd, *args):
    print 'command: %s' % cmd
    print 'arguments: %d' % len(args)
    if cmd == 'test': return do_test(*args)
    if cmd == 'demo': return do_demo(*args)
    if cmd == 'main': return do_main(*args)
    return [Nonecmdargs]
####################################################################################################
if __name__ == '__main__':
    print 'autorun: %s' % argv[0]
    cmd = argv[1if 1 < len(argvelse 'test'
    etc = argv[2:]
    obj = dispatch(cmd, *etc)
    print ''
    print 'exit/type: %s (length: %d)' % (type(obj), len(obj))
####################################################################################################
    #print 'autorun: %s' % argv[0]
    #Log.start('app.log')
    #cmd = argv[1] if 1 < len(argv) else 'main'
    #etc = argv[2:]
    #try:
    #    obj = dispatch(cmd, *etc)
    #    Log.debug('exit/type: %s (length: %d)' % (type(obj), len(obj)))
    #    Log.debug('exit/repr: %s' % repr(obj))
    #    print 'exit/type: %s (length: %d)' % (type(obj), len(obj))
    #except Exception as e:
    #    print >> stderr, 'ERROR! "%s"' % e
    #    Log.error(e)
    #    raise
    #finally:
    #    Log.end()
####################################################################################################
'''eof'''