##
# This software was developed and / or modified by Raytheon Company,
# pursuant to Contract DG133W-05-CQ-1067 with the US Government.
# 
# U.S. EXPORT CONTROLLED TECHNICAL DATA
# This software product contains export-restricted data whose
# export/transfer/disclosure is restricted by U.S. law. Dissemination
# to non-U.S. persons whether in the United States or abroad requires
# an export license or other authorization.
# 
# Contractor Name:        Raytheon Company
# Contractor Address:     6825 Pine Street, Suite 340
#                         Mail Stop B8
#                         Omaha, NE 68106
#                         402.291.0100
# 
# See the AWIPS II Master Rights File ("Master Rights File.pdf") for
# further licensing information.
##
#
#    Name:
#       MessageBar.py
#       GFS1-NHD:A7804.0000-SCRIPT;1.3
#
#    Status:
#       DELIVERED
#    
#    History:
#       Revision 1.3 (DELIVERED)
#         Created:  07-MAY-2005 11:35:24      OBERFIEL
#           Added Item Header Block
#       
#       Revision 1.2 (DELIVERED)
#         Created:  15-FEB-2005 18:23:19      TROJAN
#           spr 6529
#       
#       Revision 1.1 (APPROVED)
#         Created:  01-JUL-2004 14:41:32      OBERFIEL
#           date and time created -2147483647/-2147483648/-2147481748
#           -2147483648:-2147483648:-2147483648 by oberfiel
#
#    Change Document History:
#       1:
#       	Change Document:   GFS1-NHD_SPR_6832
#       	Action Date:       07-JUN-2005 13:13:53
#       	Relationship Type: In Response to
#       	Status:           CLOSED
#       	Title:             AvnFPS: Add PVCS doc blocks
#       
#
# Class to display messages in an information line.
# code derived derived from Pmw.MessageBar
# implements blinking label, history display and logging capabilities
# last update: 02/01/05

import Tkinter
import Pmw
import logging, time
import Balloon

class MessageBar(Pmw.MegaWidget):
    def __init__(self, parent = None, **kw):

	# Define the megawidget options.
	INITOPT = Pmw.INITOPT
	defaultMessageTypes = {
			   # (priority, showtime, flash, loglevel)
	    'systemerror'  : (5, 20, 'red', logging.ERROR),
	    'usererror'    : (4, 12, 'orange', logging.WARNING),
	    'busy'         : (3, 0, None, 0),
	    'systemevent'  : (3, 8, 'green', logging.INFO),
	    'userevent'    : (2, 5, 'green', logging.INFO),
	    'help'         : (1, 5, None, 0),
	    'state'        : (0, 0, None, 0),
	}
	optiondefs = (
	    ('labelmargin',    0,                     INITOPT),
	    ('labelpos',       'w',                   INITOPT),
	    ('label_width',    2,                     INITOPT),
	    ('messagetypes',   defaultMessageTypes,   INITOPT),
	    ('silent',         0,                     None),
	    ('sticky',         'ew',                  INITOPT),
	    ('logname',        '',                    INITOPT),
	    ('history',        0,                     INITOPT),
	)
	self.defineoptions(kw, optiondefs)

	# Initialise the base class (after defining the options).
	Pmw.MegaWidget.__init__(self, parent)

	# Create the components.
	interior = self.interior()
	self._messageBarEntry = self.createcomponent('entry',
		(), None,
		Tkinter.Entry, (interior,))

        # somehow readonly background is not processed correctly
        bg = self._messageBarEntry.cget('background')
	self._messageBarEntry.configure(readonlybackground=bg, state='readonly')

        self._messageBarEntry.grid(column=2, row=2, sticky=self['sticky'])
        interior.grid_columnconfigure(2, weight=1)
        interior.grid_rowconfigure(2, weight=1)
        if self['history']:
            self._textDialog = Pmw.TextDialog(interior, \
                scrolledtext_labelpos = 'n', \
		label_text = 'Past messages', \
		defaultbutton=0, \
		)
            self._textDialog.withdraw()
            self._textDialog.configure(text_state='disabled')
            self._pushButton = self.createcomponent('button', \
                (), None, \
                Tkinter.Button, (interior,), \
                command=self._showHistory, \
                )
            self._pushButton.grid(column=3, row=2, sticky=self['sticky'])
            Balloon.Balloon().bind(self._pushButton, 'Show past messages')

	self.createlabel(interior)
        Balloon.Balloon().bind(self.component('label'), 'New message indicator')

	# Initialise instance variables.
	self._numPriorities = 0
	for info in self['messagetypes'].values():
	    if self._numPriorities < info[0]:
		self._numPriorities = info[0]

	self._numPriorities = self._numPriorities + 1
	self._timer = [None] * self._numPriorities
	self._messagetext = [''] * self._numPriorities
	self._activemessage = [0] * self._numPriorities
	self._activebackground = [0] * self._numPriorities
	self._flashtimer = None
	self._flash = {'off': self.component('label').cget('background')}
        if self['logname']:
            self._logger = logging.getLogger(self['logname'])
        else:
            self._logger = None

	# Check keywords and initialise options.
	self.initialiseoptions()

    def createlabel(self, parent, childCols = 1, childRows = 1):
	labelpos = self['labelpos']
	labelmargin = self['labelmargin']
	if labelpos is None:
	    return
	frame = Tkinter.Frame(parent, relief='groove', bd=2)
	label = self.createcomponent('label',
		(), None,
		Tkinter.Label, (frame,))
	label.pack()
	if labelpos[0] in 'ns':
	    # vertical layout
	    if labelpos[0] == 'n':
		row = 0
		margin = 1
	    else:
		row = childRows + 3
		margin = row - 1
	    frame.grid(column=2, row=row, columnspan=childCols, sticky=labelpos)
	    parent.grid_rowconfigure(margin, minsize=labelmargin)
	else:
	    # horizontal layout
	    if labelpos[0] == 'w':
		col = 0
		margin = 1
	    else:
		col = childCols + 3
		margin = col - 1
	    frame.grid(column=col, row=2, rowspan=childRows, sticky=labelpos)
	    parent.grid_columnconfigure(margin, minsize=labelmargin)

    def destroy(self):
	for timerId in self._timer:
	    if timerId is not None:
		self.after_cancel(timerId)
	self._timer = [None] * self._numPriorities
	Pmw.MegaWidget.destroy(self)

    def message(self, type, text):
        # Display a message in the message bar.

	(priority, showtime, flashbg, loglevel) = self['messagetypes'][type]

	self._activemessage[priority] = 1
	self._activebackground[priority] = flashbg
	if text is None:
	    text = ''
	self._messagetext[priority] = text.replace('\n', ' ')
	self._redisplayInfoMessage()

        if loglevel and self._logger:
            self._logger.log(loglevel, text)

        if self['history']:
            # FIXME: implement circular buffer
	    self._textDialog.appendtext('%s: %s\n' % \
		(time.strftime('%x %X'), text.rstrip()))

	if showtime > 0:
	    if self._timer[priority] is not None:
		self.after_cancel(self._timer[priority])

	    # Define a callback to clear this message after a time.
	    def _clearmessage(self=self, priority=priority):
		self._clearActivemessage(priority)

	    mseconds = int(showtime * 1000)
	    self._timer[priority] = self.after(mseconds, _clearmessage)

    def helpmessage(self, text):
        if text is None:
            self.resetmessages('help')
        else:
            self.message('help', text)

    def resetmessages(self, type):
	priority = self['messagetypes'][type][0]
	self._clearActivemessage(priority)
	for messagetype, info in self['messagetypes'].items():
	    thisPriority = info[0]
	    showtime = info[1]
	    if thisPriority < priority and showtime != 0:
		self._clearActivemessage(thisPriority)

    def _clearActivemessage(self, priority):
	self._activemessage[priority] = 0
	self._activebackground[priority] = None
	if self._timer[priority] is not None:
	    self.after_cancel(self._timer[priority])
	    self._timer[priority] = None
	self._redisplayInfoMessage()

    def _flashLabel(self):
        label = self.component('label')
        bg = label.cget('background')
        if bg == self._flash['off']:
            label.configure(background=self._flash['on'])
        else:
            label.configure(background=self._flash['off'])
        self._flashtimer = self.after(500, self._flashLabel)

    def _redisplayInfoMessage(self):
	text = ''
        for priority in range(self._numPriorities - 1, -1, -1):
	    if self._activemessage[priority]:
		text = self._messagetext[priority]
		flashbg = self._activebackground[priority]
	        break
	    else:
		flashbg = None
	self._messageBarEntry.configure(state = 'normal')
	self._messageBarEntry.delete(0, 'end')
	self._messageBarEntry.insert('end', text)

	if self._flashtimer is not None:
	    self.after_cancel(self._flashtimer)
	    self._flashtimer = None
	    self.component('label').configure(background=self._flash['off'])

	if not self['silent'] and flashbg:
	    self._flash['on'] = flashbg
	    self._flashtimer = self.after(100, self._flashLabel)
	else:
            self._flashtimer = None

        self._messageBarEntry.configure(state = 'readonly')

    def _showHistory(self):
        self._textDialog.show()

Pmw.forwardmethods(MessageBar, Tkinter.Entry, '_messageBarEntry')
