#!/usr/bin/env python

#
#Copyright (C) 2007 Nemanja Jovicic
##From v0.6 added new stuff and fixed several bugs, improved looks... look in CHANGELOG
##Version 0.6 was created by Helder Fraga
#
#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.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with this program; if not, write to the Free Software
#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
import screenlets
from screenlets import Screenlet
from screenlets.options import FloatOption, BoolOption, StringOption, FontOption, ColorOption, IntOption
import cairo
import pango
import gobject
import commands
import gtk
import datetime
import os
from sys import argv
#use gettext for translation
import gettext

_ = screenlets.utils.get_translator(__file__)

def tdoc(obj):
	obj.__doc__ = _(obj.__doc__)
	return obj

@tdoc
class NetmonitorScreenlet(screenlets.Screenlet):
   """A Screenlet that displays net traffic , and month or day totals"""
   
   # default meta-info for Screenlets
   __name__ = 'NetmonitorScreenlet'
   __version__ = '0.9.2'
   __author__ = 'Jovicic Nemanja aka drxnele based on Netmonitor 0.6 by Helder Fraga'
   __desc__ =__doc__

   __timeout = None
   p_layout = None
   update_interval = 1
   __buffer = None
   dev = 'eth0'
   unit_d = _('KB')
   unit_u = _('KB')
   u1 = 0
   n1 = 0
   u2 = 0
   n2 = 0
   xo = 0
   mini = True
   deviceExist = True
   showDevice = False
   download_total = 0
   upload_total = 0
   dlt = 0
   text_color = (1,1,1, 1)
   dev_choices = []
   data = commands.getoutput("cat /proc/net/dev |grep :")
   for f in data.split(':'):
      f = f[::-1]
      f = f[:f.find(' ') ].strip()
      f = f[::-1]
      print f
      if f != None    and f != '0':  dev_choices.append(str(f))



   mypath = argv[0][:argv[0].find('NetmonitorScreenlet.py')].strip()
   coded_day = '0'
   day = '0'
   day_true = False
   custom_day = 0
   
   def __init__(self, **keyword_args):
      screenlets.Screenlet.__init__(self, width=230, height=120, uses_theme=True, **keyword_args) 
      
      self.theme_name = "ModernBlack"
      self.add_menuitem("toggle", _("Toggle mini view"))  
      self.add_menuitem("showDev", _("Show/hide device"))  
      self.add_menuitem("customDay",_("Change reset day")) 
      self.add_default_menuitems()
      self.update_interval = self.update_interval
      #self.disable_updates = True

      self.add_options_group(_('Options'), '')
      self.add_option(StringOption(_('Options'), 'dev', self.dev,_('Select Device'), '',choices = self.dev_choices))
      self.add_option(StringOption(_('Options'), 'download_total',str( self.download_total),_('Download total'), _('Here you can change your total download value for this month in KB'),))      
      self.add_option(StringOption(_('Options'), 'upload_total', str(self.upload_total),_('Upload total'), _('Here you can change your total upload value for this month in KB'),))
      self.add_option(BoolOption(_('Options'), 'mini', self.mini,_('Use mini mode'), '',))
      self.add_option(BoolOption(_('Options'), 'showDevice', self.showDevice,_('Show device'), '',))
      self.add_option(BoolOption(_('Options'), 'day_true', self.day_true,_('Reset counter every day'), '',))
      
      #self.add_option(IntOption(_('Options'), 'custom_day', self.custom_day, _('The Reset day of the month'), _('The day of the month in which reset will occur'),min=1, max=28, increment=1))
      
      self.add_option(ColorOption(_('Options'),'text_color', self.text_color, _('Text color'), _('Text color')))

      self.__timeout = gobject.timeout_add(1000, self.update)

   def __setattr__(self, name, value):
      # call Screenlet.__setattr__ in baseclass (ESSENTIAL!!!!)
   #   if name == 'download_total' or name == 'upload_total' :
   #      value = str(value)
      if name != 'xo' or  name != 'download' or  name != 'upload' or  name != 'unit1' or name != 'unit2' or name != 'u2' or name != 'u1' or name != 'n2' or name != 'n1'  or  name != 'p_layout' or name != 'download_total' or name != 'upload_total':   
      
         screenlets.Screenlet.__setattr__(self, name, value)   
      return True

   
   def menuitem_callback(self, widget, id):
      screenlets.Screenlet.menuitem_callback(self, widget, id)

      if id == "toggle":
         self.mini = not self.mini
      
      if id == "showDev":
         self.showDevice = not self.showDevice
         
      if id == "customDay":
         self.show_edit_dialog()
         
   def get_load(self):
      data = commands.getoutput("cat /proc/net/dev")
      #data = data[data.find(self.dev + ":")+5:]
      #added to fix wlan0 bug (thanks to mrmorris)
      try:
         data = data[data.find(self.dev + ":"):]
         data = data.split(':')[1];      
      
         #---------------------------------------------------
         self.u1 = float( data.split()[0] )
         self.n1 = float( data.split()[8] )
         self.deviceExist = True
         
      except: 
         #print "error device"
         self.deviceExist = False

#if self.deviceExist:-----------------
      # reseting every day
      if self.day == '0' and self.day_true == True:
         if not os.path.isfile(self.mypath + 'day'):
            f =  open( self.mypath + "day","w") #// open for for write
            f.close()

         f =  open( self.mypath + "day","r") #// open for for read
         self.day = f.read()
         f.close()

         if int(self.day) < 1 or int(self.day) > 31:
            print 'no day saving new day'
            self.day = str(datetime.datetime.now().day)
            f =  open( self.mypath + "day","w") #// open for for write
            f.write(self.day)
            f.close()
            self.reset() # added 0.9
            
      # custom reseting      
      elif (self.custom_day == 0 or self.coded_day == '0') and self.day_true == False:
         if not os.path.isfile(self.mypath + 'custom'):
            f =  open( self.mypath + "custom","w") #// open for for write
            f.close()

         f =  open( self.mypath + "custom","r") #// open for for read
         try:
            self.custom_day = int(f.read())
         except:
            self.custom_day = 0
         f.close()

         if self.custom_day < 1 or self.custom_day > 28:
            print 'no day saving new custom day'            
            self.custom_day = datetime.datetime.now().day
            f =  open( self.mypath + "custom","w") #// open for for write
            f.write(str(self.custom_day))
            f.close()
            self.reset() # added 0.9
            
         #read coded date  
         if not os.path.isfile(self.mypath + 'codedDay'):
            f =  open( self.mypath + "codedDay","w") #// open for for write
            f.close()

         f =  open( self.mypath + "codedDay","r") #// open for for read
         self.coded_day = f.read()
         f.close()

         if self.coded_day < '1': #dodati josh za is digit...##############################################################
            print 'no coded date'            
            self.coded_day = str(self.codeDate(datetime.datetime.now().month,self.custom_day))
            f =  open( self.mypath + "codedDay","w") #// open for for write
            f.write(self.coded_day)
            f.close()
            self.reset() # added 0.9
      
      #-----------------------------------------------------------

      # added because of fixing overflow bug v0.6.7----------------
      if self.u1<self.u2: self.u2=0
      if self.n1<self.n2: self.n2=0
      #-----------------------------------------------------
      self.download = str(long(self.u1 -self.u2))#/1024) measure in bytes
      self.upload = str(long(self.n1 -self.n2))#/1024)
      #printf for testing and debugging------------
      #print 'self.u1: '+str(self.u1)
      #print 'self.u2: '+str(self.u2)
      #print 'u1-u2: '+str(long(self.u1 -self.u2))
      #print 'download: ' +self.download+' B/s'
      #print 'upload: ' +self.upload+' B/s'
      #------------------------------------
      if self.u2 == 0 : self.download = '0'
      if self.n2 == 0 : self.upload = '0'


      if int(self.day) != datetime.datetime.now().day and self.day_true == True:
         self.reset()
         
      elif int(self.coded_day) <= self.codeDate(datetime.datetime.now().month,datetime.datetime.now().day) and self.day_true == False:

         self.reset()        
            
      else:
         #fixed bug with char in self.download_total and self.upload_total
         if str(self.download_total).isdigit()==True: self.download_total = long(self.download_total) + (long(self.download)/1024)
         else: self.download_total = 0
         if str(self.upload_total).isdigit()==True : self.upload_total = long(self.upload_total) + (long(self.upload)/1024)
         else: self.upload_total = 0

      # added because of fixing bug 0.6.1
      self.unit_d = _('KB') 
      self.unit_u = _('KB')
      #-------------------------------------------------------------------
      # added because of fixing bug 0.6.2 
      if long(self.download_total) < 0: 
          self.download_total=0-self.download_total
      #---------------------------------------
      #repaired because of fixing bug 0.6.3      
      elif long(self.download_total) >= (1024*1024*1024): 

         self.dlt = ((float(long(self.download_total)) / 1024)/1024)/1024
         self.unit_d = _('TB')

      elif  long(self.download_total) >= (1024*1024): 

         self.dlt = (float(long(self.download_total)) / 1024)/1024
         self.unit_d = _('GB')

      elif  long(self.download_total) >= (1024): 

         self.dlt = float(long(self.download_total)) /1024
         self.unit_d = _('MB')
      
      else:

         self.dlt = float(long(self.download_total))
      #--------------------------------------------------------------------------
      #added because of fixing bug 0.6.2
      if long(self.upload_total) < 0: 
          self.upload_total=0-self.upload_total
      #---------------------------------------
      #repaired because of fixing bug 0.6.3      
      elif long(self.upload_total) >= (1024*1024*1024): 

         self.ult = ((float(long(self.upload_total)) / 1024)/1024)/1024
         self.unit_u = _('TB')
      elif long(self.upload_total) >= (1024*1024): 

         self.ult = (float(long(self.upload_total)) / 1024)/1024
         self.unit_u = _('GB')

      elif  long(self.upload_total) >= (1024): 

         self.ult = float(long(self.upload_total)) /1024
         self.unit_u = _('MB')

      else:

         self.ult = float(long(self.upload_total))
      #--------------------------------------------------------------------------
      try:
         self.ult = str(self.ult)
         self.dlt = str(self.dlt)

         if self.ult.find('.') != 0 :
            self.ult = self.ult[:self.ult.find('.')+2 ].strip()
         if self.dlt.find('.')  != 0:
            self.dlt = self.dlt[:self.dlt.find('.')+2 ].strip()
         #print 'download total: '+ self.dlt+self.unit_d
         #print 'upload total: ' +self.ult+self.unit_u
         #print str(self.dev)
      except:
         pass
      self.u2 = self.u1
      self.n2 = self.n1
      screenlets.Screenlet.__setattr__(self, 'download_total', str(self.download_total))

      screenlets.Screenlet.__setattr__(self, 'upload_total', str(self.upload_total))
      
      #print 'download month: ' +self.download_total+' B'
      #print 'upload month: ' +self.upload_total+' B'
      #print 'download: ' +self.download+' B/s'
      #print 'upload: ' +self.upload+' B/s'

      self.session.backend.flush()
   


   def on_draw(self, ctx):

      #print str(datetime.datetime.now().date())
      ctx.scale(self.scale, self.scale)
      ctx.set_operator(cairo.OPERATOR_OVER)
      if self.theme:
         if self.mini == True or not self.deviceExist:
            self.theme['background-mini.svg'].render_cairo(ctx)
            self.theme.render(ctx, _('Network'))
         else:
            self.theme['background.svg'].render_cairo(ctx)
            self.theme.render(ctx, _('Network'))

      ctx.set_source_rgba(*self.text_color)

      ctx.translate(50, 8)
      if self.p_layout == None :
   
           self.p_layout = ctx.create_layout()
      else:
         
           ctx.update_layout(self.p_layout)
      p_fdesc = pango.FontDescription()
      p_fdesc.set_family_static("Free Sans")
      p_fdesc.set_size(16 * pango.SCALE)
      self.p_layout.set_font_description(p_fdesc)

      
      if len(self.session.instances) != 0:
         self.get_load()
      
         if self.deviceExist:
            if self.showDevice:
               ctx.save()
               ctx.translate(-40,12)
               self.p_layout.set_markup("<small><small><b>"+self.dev+"</b></small></small>")
               ctx.show_layout(self.p_layout)
               ctx.restore()
            
            # adding more precision in download 0.6.4-----------------------------      
            if  long(self.download) >= (1024*1024): 
            #if download MB
               text="<small><b> Download: " + str(long(self.download)/(1024*1024))  + " <small>MB/s</small></b></small>"
            elif  long(self.download) >= 1024: 
            #if download KB
               text="<small><b> Download: " + str(long(self.download)/1024)  + " <small>KB/s</small></b></small>"
            #id download B
            elif long(self.download)>=0:
               text="<small><b> Download: " + self.download  + " <small>B/s</small></b></small>"   
                      #-------------------------------------------------------------------------------------------
            text+="\n"
         
            #adding more precision in upload 0.6.4-----------------------------         
            if  long(self.upload) >= (1024*1024): 
            #if upload MB
               text+="<small><b> Upload: " + str(long(self.upload)/(1024*1024))  + " <small>MB/s</small></b></small>"
            elif  long(self.upload) >= 1024: 
            #if upload KB
               text+="<small><b> Upload: " + str(long(self.upload)/1024)  + " <small>KB/s</small></b></small>"
            #id download B
            elif long(self.upload)>=0:
               text+="<small><b> Upload: " + self.upload  + " <small>B/s</small></b></small>"

            self.p_layout.set_markup(text)
            ctx.show_layout(self.p_layout)
            #-------------------------------------------------------------------------------------------

            if self.mini == False:
               self.p_layout.alignment = pango.ALIGN_RIGHT
               #added text for each month 0.6.7 & fixed previous bug 0.6.8(.1)----------------------------
               ctx.translate(-20,50)
            
               if self.day_true == True:
                  text = _("Today's")
               else:
                  if self.custom_day> datetime.datetime.now().day:
                     text= self.get_month((datetime.datetime.now().month+11)%12)+" "+str(self.custom_day)+" - "+self.get_month(datetime.datetime.now().month)+" "+str(self.custom_day)
                  else:
                     text= self.get_month(datetime.datetime.now().month)+" "+str(self.custom_day)+" - "+self.get_month((datetime.datetime.now().month+1)%12)+" "+str(self.custom_day)

               self.p_layout.set_markup('<small><small><small>***'+text+' total:</small></small></small>')
               ctx.show_layout(self.p_layout)      
               #------------------------------------------------------------------------------------------
               self.p_layout.set_markup('<small>Download: ' + str(self.dlt) + ' '+ self.unit_d + '\nUpload: ' + str(self.ult)+ ' '+ self.unit_u+"</small>")
               ctx.translate(20,18)

         else:
             self.p_layout.set_markup('<small><small> Device '+self.dev+' not found\n<small> please check your connection</small></small></small>')
      ctx.show_layout(self.p_layout)   

   def get_month(self,m):
      if str(m)=='12' or str(m)=='0' : return _("December")
      if str(m)=='11': return _("November")
      if str(m)=='10': return _("October")
      if str(m)=='9': return _("September")
      if str(m)=='8': return _("August")
      if str(m)=='7': return _("July")
      if str(m)=='6': return _("June")
      if str(m)=='5': return _("May")
      if str(m)=='4': return _("April")
      if str(m)=='3': return _("March")
      if str(m)=='2': return _("February")
      if str(m)=='1': return _("January")

   def update (self):
   
      self.redraw_canvas()
         #except Exception, ex:
         #      print 'no value yet'         
      return True

   def on_draw_shape(self,ctx):
      ctx.scale(self.scale, self.scale)
      if self.theme:
         #self.theme['control-bg.svg'].render_cairo(ctx)
         ctx.set_source_rgba(1, 1, 1, 1)
         ctx.rectangle (0,0,self.width,self.height)
         ctx.fill()

   def reset(self):
      print 'reseting...'

      self.download_total = 0
      self.upload_total = 0

      if self.custom_day > datetime.datetime.now().day:
         self.coded_day = str(self.codeDate(datetime.datetime.now().month,self.custom_day))
      else:
         self.coded_day = str(self.codeDate(((datetime.datetime.now().month+1)%12),self.custom_day))

      f =  open( self.mypath + "codedDay","w") #// open for for write
      f.write(self.coded_day)
      f.close()

      self.day = str(datetime.datetime.now().day)
      f =  open( self.mypath + "day","w") #// open for for write
      f.write(self.day)
      f.close()


   def codeDate(self,m,d):
      d=int(d)
      m=int(m)
      #leap year - february 29 days, year 366
      if datetime.datetime.now().year%4==0:
         yearDays=366
         feb=29
      else:
         yearDays=365
         feb=28
         
      if m==1:
         dayCode= (datetime.datetime.now().year-2008)*yearDays+d
         
      elif m==2:
         dayCode= (datetime.datetime.now().year-2008)*yearDays+d+31
         
      elif m==3:
         dayCode= (datetime.datetime.now().year-2008)*yearDays+d+31+feb
      
      elif m==4:
         dayCode= (datetime.datetime.now().year-2008)*yearDays+d+62+feb
      
      elif m==5:
         dayCode= (datetime.datetime.now().year-2008)*yearDays+d+92+feb   
      
      elif m==6:
         dayCode= (datetime.datetime.now().year-2008)*yearDays+d+123+feb  
      
      elif m==7:
         dayCode= (datetime.datetime.now().year-2008)*yearDays+d+153+feb  
      
      elif m==8:
         dayCode= (datetime.datetime.now().year-2008)*yearDays+d+184+feb 
         
      elif m==9:
         dayCode= (datetime.datetime.now().year-2008)*yearDays+d+215+feb
      
      elif m==10:
         dayCode= (datetime.datetime.now().year-2008)*yearDays+d+245+feb
         
      elif m==11:
         dayCode= (datetime.datetime.now().year-2008)*yearDays+d+276+feb
         
      elif m==12 or m==0:
         dayCode= (datetime.datetime.now().year-2008)*yearDays+d+306+feb
         
      return dayCode


   def show_edit_dialog(self):
      # create dialog
      dialog = gtk.Dialog(_("Change reset day"), self.window)
      dialog.resize(300, 100)
      dialog.add_buttons(gtk.STOCK_OK, gtk.RESPONSE_OK, 
         gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
      label=gtk.Label()
      label.set_text(_("Change day of month when reset will occure"))
      dialog.vbox.add(label)
      label.show()
      entrybox = gtk.SpinButton(None, 1, 0)
      entrybox.set_range(1,28)
      entrybox.set_increments(1, 1)
      entrybox.set_value(self.custom_day)
      dialog.vbox.add(entrybox)
      entrybox.show()   
      # run dialog
      response = dialog.run()
      if response == gtk.RESPONSE_OK:
         self.custom_day = entrybox.get_value_as_int()
         self.reset()
      dialog.hide()
      self.update()


if __name__ == "__main__":
   import screenlets.session
   screenlets.session.create_session(NetmonitorScreenlet)
