#!/usr/bin/env python

#    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 3 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, see <http://www.gnu.org/licenses/>.

#RingSensorScreenlet (c) Whise <helder.fraga@hotmail.com>

import screenlets
from screenlets import sensors
from screenlets.options import FloatOption, BoolOption, StringOption, IntOption, ColorOption
import cairo
import pango
import sys
import gobject
import math
# use gettext for translation
import gettext

_ = screenlets.utils.get_translator(__file__)

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

@tdoc
class RingSensorsScreenlet(screenlets.Screenlet):
	"""Circle Sensors Screenlet."""

	# default meta-info for Screenlets
	__name__ = 'RingSensorsScreenlet'
	__version__ = '0.3.3'
	__author__ = 'Helder Fraga aka Whise based on ClockRing by Paul Ashton'
	__desc__ = __doc__

	# internals
	__timeout = None

	# settings
	update_interval = 2
	nb_points=50
	show_text = True
	show_graph = True
	text_prefix = '<span size="xx-small" rise="10000">% </span><b>'
	text_suffix = '</b>'
	loads=[]
	old_idle=0
	linear = ''
	hourMiddle = False
	color_back = (1,1,1,0.6)
	color_front =(1, 1, 1, 0.9)
	color_text = (1, 1, 1, 1)
	graph_type = 'Graph'
	thickness = 24.0
	ringSpacing = 26.0
	sensor_list = []
	sensor = 'CPU0'
	blockSpacing = 1.0
	load = 0
	size = 100
	old_cpu = 0
	new_cpu = 0
	wire_list = []
	wire_data = []
	big_bars = True

	down = 0
	download = 0
	old_down = 0
	max_download = 1000
	
	up = 0
	upload = 0
	old_up = 0
	max_upload = 100
	# constructor
	def __init__(self,**keyword_args):
		screenlets.Screenlet.__init__(self, width=200, height=200, 
			uses_theme=True, **keyword_args)
		self.loads=[]
		#self.old_somme=0
		self.old_idle=0
		for i in range(self.nb_points):
			self.loads.append(0)




		#call super (and not show window yet)
		#screenlets.Screenlet.__init__(self, uses_theme=True, **keyword_args)
		# set theme
		if self.sensor_list ==[]:
			for i in range (0,sensors.cpu_get_nb_cpu()+1): 
	
				self.sensor_list.append(_('CPU') + str(i))

			self.sensor_list.append(_('RAM'))
			self.sensor_list.append(_('Download'))
			self.sensor_list.append(_('Upload'))
			self.sensor_list.append(_('SWAP'))
			if sensors.bat_get_battery_list():
				self.sensor_list.append(str(sensors.bat_get_battery_list()[0]))
			for i in sensors.disk_get_disk_list():
				self.sensor_list.append(str(i))
			print sensors.sensors_get_sensors_list()
			if sensors.sensors_get_sensors_list():
				for i in sensors.sensors_get_sensors_list():
					self.sensor_list.append(str(i))	
					#print i.split(':')[0]
			self.wire_list = sensors.wir_get_interfaces()
			if self.wire_list !=[]:
				self.sensor_list.append(_('Wifi ')+ self.wire_list[0])		

		self.theme_name = "default"
		# add default menu items
		# add settings
		self.add_options_group(_('Sensors'), _('Specific options'))

		self.add_option(FloatOption(_('Sensors'), 'update_interval', self.update_interval, _('Update interval (sec)'), '',min=0.1, max=1000.0, increment=1))

		self.add_option(BoolOption(_('Sensors'), 'show_text',
			self.show_text, _('Show Text'), _('Show the text on the CPU-Graph ...')))



		self.add_option(StringOption(_('Sensors'), 'sensor',
			self.sensor, _('Sensor to Display'),
			'',choices=self.sensor_list))

		self.add_option(ColorOption(_('Sensors'),'color_back', 
			self.color_back, 'background color', ''))

		self.add_option(ColorOption(_('Sensors'),'color_front', 
			self.color_front, _('Front color'), 
			''))
		self.add_option(ColorOption(_('Sensors'),'color_text', 
			self.color_text, _('Text color'), 
			''))
		self.add_option(FloatOption(_('Sensors'), 'thickness', self.thickness, _('Ring Thickness'), '',min=0.0, max=500.0, increment=0.1))
		self.add_option(FloatOption(_('Sensors'), 'blockSpacing', self.blockSpacing, _('Block Spacing'), '',min=0.0, max=6.0, increment=0.1))
		self.add_option(BoolOption(_('Sensors'), 'big_bars',
			self.big_bars, _('Use Big bars'), ''))
		self.add_option(FloatOption(_('Sensors'), 'max_download', self.max_download, _('Max dl speed (kilobytes/s)'), '',min=0.0, max=1000000.0, increment=10))
		self.add_option(FloatOption(_('Sensors'), 'max_upload', self.max_upload, _('Max ul speed (kilobytes/s)'), '',min=0.0, max=1000000.0, increment=10))

		# init the timeout function
		self.update_interval = self.update_interval


	def on_init(self):
		self.add_default_menuitems()

	# attribute-"setter", handles setting of attributes
	def __setattr__(self, name, value):
		# call Screenlet.__setattr__ in baseclass (ESSENTIAL!!!!)
		screenlets.Screenlet.__setattr__(self, name, value)
		# check for this Screenlet's attributes, we are interested in:
		if name == "update_interval":
			if value > 0:
				self.__dict__['update_interval'] = value
				if self.__timeout:
					gobject.source_remove(self.__timeout)
				self.__timeout = gobject.timeout_add(int(value * 1000), self.update)
			else:
				# TODO: raise exception!!!
				self.__dict__['update_interval'] = 1
				pass
		elif name == "nb_points":
			if value > 1:
				if len(self.loads)> value:
					self.loads=self.loads[len(self.loads)-value:]
				elif len(self.loads)< value:
					for i in range(value-len(self.loads)):
						self.loads.insert(0,0)
				self.__dict__['nb_points'] = value
				
			else:
				# TODO: raise exception!!!
				self.__dict__['nb_points'] = 2
				pass

	# calculate cpu-usage by values from /proc/stat

	# timeout-function
	def update(self):
		if self.sensor.startswith(_('CPU')):
			self.new_cpu=sensors.cpu_get_load(int(self.sensor[3]))

			self.load = int(self.new_cpu-self.old_cpu)
			
			self.old_cpu = self.new_cpu

		elif self.sensor.startswith(_('Download')):
			'''it seems to be outputting in kilobytes/sec
			add a 3% error so it's not always hitting 100%'''

			self.down = sensors.net_get_updown()[1]
			self.download = (100*(self.down - self.old_down)/self.update_interval) /(self.max_download*1.03) 
			self.old_down = self.down
			
			if self.download < 0.9: #noise
				self.load = 0
			else:
				self.load = round (self.download , 1)


		elif self.sensor.startswith(_('Upload')):
			'''it seems to be outputting in kilobytes/sec
			add a 3% error so it's not always hitting 100%'''

			self.up = sensors.net_get_updown()[0]
			self.upload = (100*(self.up - self.old_up)/self.update_interval) /(self.max_upload*1.03)
			self.old_up = self.up
			
			if self.upload < 0.9: #noise
				self.load = 0
			else:
				self.load = round (self.upload , 1)


		elif self.sensor.startswith(_('RAM')):
			self.load = sensors.mem_get_usage()

		elif self.sensor.startswith(_('SWAP')):
			self.load = sensors.mem_get_usedswap()

		elif self.sensor.startswith(_('BAT')):
			bat_data = sensors.bat_get_data(self.sensor)
			try:
				self.load = (bat_data[1]*100)/bat_data[2]
			except: self.load = 0
		elif self.sensor.endswith('C'):

			self.sensor = str(self.sensor.split(':')[0]) + ':' + str(sensors.sensors_get_sensor_value(self.sensor.split(':')[0]))
			self.load = 0
		elif self.sensor.endswith('RPM'):
			self.sensor = str(self.sensor.split(':')[0]) + ':' +str(sensors.sensors_get_sensor_value(self.sensor.split(':')[0]))
			self.load = 0
		elif self.sensor.endswith('V'):
			self.sensor = str(self.sensor.split(':')[0]) + ':' +str(sensors.sensors_get_sensor_value(self.sensor.split(':')[0]))
			self.load = 0
		elif self.sensor.endswith(_('Custom Sensors')):
			pass			
		elif self.sensor.startswith(_('Wifi')):
			if self.wire_list != []:
				self.wire_data = sensors.wir_get_stats(self.wire_list[0])
				
				a = str(self.wire_data['essid']).find('off/any')
				if a != -1:
					self.sensor = _('Wifi ') + str(self.wire_list[0])
				else:
					self.sensor = _('Wifi ')  + str(self.wire_data['essid'])
				self.load = int(str(self.wire_data['percentage']).replace('%',''))
		elif self.sensor and self.sensor in sensors.disk_get_disk_list():
			# only get here when requested sensor is in the list of available disks
 			self.load = int(sensors.disk_get_usage(self.sensor)[4].replace('%',''))
		else:
			try:
				self.sensor = str(self.sensor.split(':')[0]) + ':' + str(sensors.sensors_get_sensor_value(self.sensor.split(':')[0]))
			except:			
				pass
			self.load = 0

		if self.load > 100:
			self.load = 100
		elif self.load < 0:
			self.load=0

		self.redraw_canvas()
		return True


	def on_draw(self, ctx):

		ctx.scale(self.scale, self.scale)
		# draw bg (if theme available)
		ctx.set_operator(cairo.OPERATOR_ADD)
		

		startrad = self.size-(self.thickness/2.0)		
		a = float(self.load*11)/100
				
		
		ctx.set_line_width( self.thickness )	
		if self.big_bars:
			for i in range(12):
				if i == a or (i<=a ): col = self.color_front
				else: col = self.color_back
				if self.hourMiddle: radius = startrad-(self.ringSpacing*2.0)
				else: radius = startrad
				pos = -90+(self.blockSpacing/2.0)+(i*30)
				
				ctx.arc( 100, 100, radius, math.radians(pos), math.radians(pos+30-self.blockSpacing) )
				ctx.set_source_rgba(col[0],col[1],col[2],col[3])
				ctx.stroke()
		else:
			a = float(self.load*59)/100
			for i in range(60):
				if i == a or (i<=a ): col = self.color_front
				else: col = self.color_back
				if self.hourMiddle: radius = startrad-(self.ringSpacing*2.0)
				else: radius = startrad
				pos = -90+(self.blockSpacing/2.0)+(i*6)
				
				ctx.arc( 100, 100, radius, math.radians(pos), math.radians(pos+6-self.blockSpacing) )
				ctx.set_source_rgba(col[0],col[1],col[2],col[3])
				ctx.stroke()
		if len(str(self.load))==1:
			self.load = "0" + str(self.load)
		ctx.set_source_rgba(self.color_text[0],self.color_text[1],self.color_text[2],self.color_text[3])
		if self.sensor.endswith('RPM') or self.sensor.endswith('C') or self.sensor.endswith('V') or self.sensor.find(':') != -1:
			text = '<small><small><small><small>' +str(self.sensor.split(':')[0]) +'</small></small></small></small>\n'+str(self.sensor.split(':')[1])	
		else:
			text = '<small><small><small><small>' +self.sensor +'</small></small></small></small>\n'+self.text_prefix + str(self.load) + self.text_suffix
		ctx.set_operator(cairo.OPERATOR_OVER)
		if self.show_text and self.theme:self.theme.draw_text(ctx,text, 0, 70, 'Free Sans', 25,  self.width,pango.ALIGN_CENTER)
			
			
	

	def on_draw_shape(self,ctx):
		self.on_draw(ctx)


# If the program is run directly or passed as an argument to the python
# interpreter then create a Screenlet instance and show it
if __name__ == "__main__":
	import screenlets.session
	screenlets.session.create_session(RingSensorsScreenlet)
