#!/usr/bin/env python2.7

from gi.repository import Gtk as gtk
from gi.repository import GLib
from gi.repository import AppIndicator3 as appindicator
from gi.repository import Notify as notifyclass
#import appindicator
import os
import time
import math
from time import gmtime, strftime
import time
import subprocess
from array import *
from math import *
from copy import deepcopy

#define mode_warn 1

mode_status = 0
mode_warning = 1
mode_error = 2
TPSTATE_NONE=0
TPSTATE_PAPEROUT=1 
TPSTATE_INKOUT=2
TPSTATE_PRINTING=4 
TPSTATE_ERROR=8
TPSTATE_COVEROPEN=16 
TPSTATE_INKWARN=32
TPSTATE_DISCONNECTED=64
TPSTATE_CDERROR=128
TPSTATE_WARNING=8192


icons_idle=["prt_standard.svg"]
icons_printing=["prt_print1.svg","prt_print2.svg","prt_idle.svg"]
icons_paperout=["prt_nopaper.svg", "prt_idle.svg"]
icons_inkout=["prt_noink.svg", "prt_idle.svg"]
icons_inkwarn=["prt_inkwarn.svg", "prt_idle.svg"]
icons_error=["prt_error.svg", "prt_idle.svg"]
icons_cderror=["prt_cderror.svg", "prt_idle.svg"]
icons_disconnected=["prt_notconnected.svg", "prt_idle.svg"]
icons_warning=["prt_warning.svg", "prt_idle.svg"]

timeout_source = 0

class nstruct:
	def __init__(self,aprinter, amessage, alevel, apointer):
	   self.printer=aprinter
	   self.message=amessage
	   self.level=alevel
	   self.notification=apointer

class notifies:
	def __init__(self):
	    self.notifies = []
	    self.newlist = []

	def cleanup(self):
	   for data in self.notifies:
		data.notification.close()
	   self.notifies=[]
	   self.newlist =[]

	def setNotify(self,printer,message,level):
	   found = 0
	   # check if printer already present in notifies list
	   for data in self.newlist:
		if data.printer == printer:
   		   found = 1
		   if data.level<level:
			data.message=message
			data.level=level
			break
	   if found<1:
		self.newlist.append(nstruct(printer,message,level,0))
		
	def mergeNotifies(self):
	   # mark all entries as unchanged
	   for old in self.notifies:
		old.level = 0;

	   for data in self.newlist:
                found=0
		for note in self.notifies:
		   if note.printer == data.printer:
			note.level=1
   		        found=1
			if note.message == data.message:
			   break
			else:
			   note.message=data.message
			   result = note.notification.update("%s"%(data.printer), data.message, None)
			   note.notification.show()
			break
		if found==0:
		   newnotify=nstruct(data.printer,data.message,1,0)
		   newnotify.notification=notifyclass.Notification.new("%s"%(newnotify.printer), newnotify.message, None)
		   newnotify.notification.show()
		   self.notifies.append(newnotify)
	   for old in self.notifies:
	      if old.level ==0:
		 old.notification.close()
		 self.notifies.remove(old)
	   self.newlist = []


class printerstatus:
    def __init__(self):
        self.name = ''
        self.average = 0.0
        self.values = None
        self.itemStatus=[]
        self.itemState=[]
        self.messageStore=[[],[]]
        self.numEntries=[0,0,0,0]
        self.sharepath = "/usr/share/turboprint"
        self.varpath = "/var/log"
        self.binpath = "/usr/share"
        self.language = "en"
        self.flagChanged = 0;
        self.curMode = 0
        self.printerstate=0
        self.animcounter=0
        self.anim_sequence=0
        self.curimgpath = ''
    	self.mynotifies = notifies()
	self.notifyThreshold = 2
 
        tplogpath=""
        animstate=0

    def cleanup(self):
	self.mynotifies.cleanup()

    def openTPMonitor(self,menuitem,myclass, queueName):
        if(len(queueName)>0):
            argument = "-P%s"%(queueName)
        else:
            argument = ''
        args = (self.binpath+"/turboprint-monitor", argument)
        popen = subprocess.Popen(args, stdout=subprocess.PIPE)
        popen.wait()

    def openTPControl(self,menuitem):
        popen = subprocess.Popen(self.binpath+"/turboprint", stdout=subprocess.PIPE)
        popen.wait()

    def animate_icon(self):
        global ind

        self.animcounter+=1
        if self.animcounter >= len(self.anim_sequence): self.animcounter=0
        newiconpath=self.sharepath+'/img/'+self.anim_sequence[self.animcounter]
        if ind.get_icon() != newiconpath:
            ind.set_icon(newiconpath)

    def readStatusFile(self):
        queuestate=0
        self.numEntries[0]=0;
        self.numEntries[1]=0;
        self.numEntries[2]=0;
        self.flagChanged =0
        try:
            f=open(self.varpath+"/turboprint/tpstatus", "r")
        except:
            self.messageStore[0][0]="ERROR"
            self.messageStore[1][0]="cannot load tpstatus"
            self.numEntries[0]=1
            self.flagChanged=1
            print("open error")
            return
        strings=f.readlines()

        inum=0
        num_entries=len(self.messageStore[0])
 
        for text in strings:
            if text.endswith('\n'): text = text[:-1]
            if "[Warnings]" in text:
                mode = mode_warning
            elif "[Status]" in text:
                mode= mode_status
            elif "[Errors]" in text:
                mode= mode_error
            else:
                position=text.find(':')
                if position > 0:
                      printername = text[0:position]
                      message = text[position+1:]
                      position2 = message.find('=')
                      if position2 > 0:
                               msgnumber = int(message[0:position2],16)
                               queuestate|=msgnumber
                               msgtext = message[position2+1:]
                               self.numEntries[mode]+=1;
                               
			       if self.notifyThreshold > 2-mode: self.mynotifies.setNotify(printername,msgtext,mode)

                               if(inum<num_entries):
                                   if self.messageStore[0][inum] != printername or self.messageStore[1][inum] != msgtext or self.itemState[inum]!=msgnumber:
                                       self.messageStore[0][inum]=printername
                                       self.messageStore[1][inum]=msgtext[:]
                                       self.itemState[inum]=msgnumber
                                       self.flagChanged=1
                               else:
                                   self.messageStore[0].append(printername)
                                   self.messageStore[1].append(msgtext)
                                   self.itemState.append(msgnumber)
                                   self.flagChanged=1
                               inum+=1
                               if self.curMode > mode: self.curMode=mode

        if inum<num_entries:
            self.messageStore[0]=self.messageStore[0][0:inum]
            self.messageStore[1]=self.messageStore[1][0:inum]
            self.itemState=self.itemState[0:inum]
            self.flagChanged=1
        if queuestate == TPSTATE_NONE and self.curMode> mode_warning:
            queuestate = TPSTATE_WARNING    
        self.printerstate=queuestate
	self.mynotifies.mergeNotifies()
        
        
    def load_tpcfg(self):
        self.sharepath = "/usr/share/turboprint"
        self.varpath = "/var/log"
        self.language = "en"


        f=open("/etc/turboprint/system.cfg","r")
        strings=f.readlines()

        for line in strings:
            if line.endswith('\0') or line.endswith('\n'): line=line[:-1]
            position=line.find('=')
            if position > 0:
                left = line[0:position]
                right = line[position+1:]
                if "TP_LANGUAGE" in left:
                    self.language=right
                elif "TPPATH_SHARE" in left:
                    self.sharepath=right
                elif "TPPATH_VAR" in left:
                    self.varpath=right
                elif "TPPATH_BIN" in left:
                    self.binpath=right
		elif "APPLET_NOTIFYLEVEL" in left:
		    self.notifyThreshold = int(right)
        f.close


def tick(args=None):
        global mystatus
        global counter
        global ind

        if counter%5==0:       
            mystatus.flagChanged=0
            mystatus.readStatusFile()
            old_pstate = mystatus.printerstate
            if mystatus.flagChanged==1:
                msgcode = mystatus.printerstate
                if msgcode & TPSTATE_PAPEROUT: mystatus.anim_sequence = icons_paperout
                elif msgcode & TPSTATE_CDERROR: mystatus.anim_sequence = icons_cderror
                elif msgcode & TPSTATE_INKOUT: mystatus.anim_sequence = icons_inkout
                elif msgcode & TPSTATE_ERROR: mystatus.anim_sequence = icons_error
                elif msgcode & TPSTATE_COVEROPEN: mystatus.anim_sequence = icons_error
                elif msgcode & TPSTATE_DISCONNECTED: mystatus.anim_sequence = icons_disconnected
                elif msgcode & TPSTATE_INKWARN: mystatus.anim_sequence = icons_inkwarn
                elif msgcode & TPSTATE_WARNING: mystatus.anim_sequence = icons_warning
                elif msgcode & TPSTATE_PRINTING: mystatus.anim_sequence = icons_printing
                else:
                    mystatus.anim_sequence = icons_idle
                    msgcode = TPSTATE_NONE
                mystatus.printerstate=msgcode
                if old_pstate != msgcode:
                    mystatus.anim_iter=0

                mymenu=ind.get_menu()
                children=mymenu.get_children()
                if(len(children)>2):
                    for i in range(0,len(children)-2):
                        mymenu.remove(children[i])
    
                messagecount = mystatus.numEntries[0]+mystatus.numEntries[1]+mystatus.numEntries[2]
                itemControl = gtk.MenuItem('TurboPrint Control')
                itemControl.connect('activate',mystatus.openTPControl)
                mymenu.prepend(itemControl)
#                mymenu.prepend(gtk.SeparatorMenuItem())

                item=[]
                if messagecount>0:
                    for i in range(0 , messagecount):
                        message = "%s: %s" %(mystatus.messageStore[0][i],mystatus.messageStore[1][i])
                        item.append(gtk.MenuItem(message))
                        item[i].connect('activate', mystatus.openTPMonitor,mystatus, mystatus.messageStore[0][i])
                        mymenu.prepend(item[i])
                else:
                    item = gtk.MenuItem('TurboPrint-Monitor')
                    item.connect('activate',mystatus.openTPMonitor,mystatus, '')
                    mymenu.prepend(item)
                mymenu.show_all()

        counter+=1
            
        mystatus.animate_icon()
        return True

def quit(source):
    global ind
    global timeout_source
    global mystatus
    mystatus.cleanup()
    notifyclass.uninit()
    ind.set_status(appindicator.IndicatorStatus.PASSIVE)
    GLib.source_remove(timeout_source)
    gtk.main_quit()
    

if __name__ == "__main__":
    
    APPINDICATOR_ID = 'turboprint'

    mystatus=printerstatus()
    mystatus.load_tpcfg()

    counter =0
    mystatus.anim_sequence = icons_idle
    mystatus.printerstate=TPSTATE_NONE
    
    
    ind = appindicator.Indicator.new(APPINDICATOR_ID, '', appindicator.IndicatorCategory.SYSTEM_SERVICES)
    ind.set_status (appindicator.IndicatorStatus.ACTIVE)

    menu = gtk.Menu()
    
    image = gtk.Image()
    image.set_from_icon_name("gtk-quit", 24)
    if(mystatus.language == 'de'):
        item_quit = gtk.ImageMenuItem('Beenden')
    elif(mystatus.language == 'es'):
        item_quit = gtk.ImageMenuItem('Dejar')
    else:
        item_quit = gtk.ImageMenuItem('Quit')
    item_quit.set_image(image)
    item_quit.set_always_show_image(True)
    item_quit.connect("activate", quit)
    
    menu.append(gtk.SeparatorMenuItem())
    menu.append(item_quit)
    
    menu.show_all()
    mystatus.messageStore[0].append('empty')
    mystatus.messageStore[1].append('empty')
    mystatus.itemState.append(0)
    ind.set_menu(menu)
    timeout_source = GLib.timeout_add(900, tick)
    notifyclass.init(APPINDICATOR_ID)
    tick()
    gtk.main()
