#!/usr/bin/env python

#  Temperature2Screenlet (c) nomego (Patrik Kullman) 2007 <patrik@yes.nu>
#  Based on:
#  Temperature2Screenlet (c) fader (Ronald McCollam) 2007 <fader@hotpop.com>
#  CPUMeterScreenlet (c) RYX (aka Rico Pfaus) 2007 <ryx@ryxperience.com>
#  SystemStatusScreenlet (c) 2007 Hendrik Kaju <hendrik@kaju.pri.ee>
#
# INFO:
# - a simple CPU temperature meter
# 
# TODO:
# - beter graph/themes (my Inkscape-fu is weak)
# - support imperial units
# - clean up code
# - support for icons (cpu, gfx, hdd?)
# - don't make hddtemp screenlets dip to 0 when there's and error with the hddtemp daemon
#
# CHANGELOG:
# - initial conversion from Temperature2Screenlet
# - added support for changing title (modified svgs, added option)
# - added support for selecting the thermal zone to monitor
# - added support for monitoring the hddtemp daemon

import screenlets
from screenlets.options import FloatOption, BoolOption, StringOption
import cairo
import pango
import sys
import re
import gobject
import commands
import socket

class Temperature2Screenlet(screenlets.Screenlet):
	"""A simple Temperature Meter Screenlet."""
	
	# default meta-info for Screenlets
	__name__ = 'Temperature2Screenlet'
	__version__ = '0.1'
	__author__ = 'Patrik Kullman'
	__desc__ = 'A themeable temperature meter based on TemperatureScreenlet by fader (aka Ronald McCollam).'

	# internals
	__timeout = None
	__hddtemp = ""
	
	# settings
	update_interval = 1.0
	show_text = True
	show_graph = True
	text_prefix = '<b>'
	text_suffix = '<span size="xx-small" rise="10000">&#xB0;C</span></b>'
	temperature_location = "/proc/acpi/thermal_zone/THRM/temperature"
	trip_point_location = "/proc/acpi/thermal_zone/THRM/trip_points"
	low_temp = 25
	# FIXME: Find a safe way to get the high temperature trip point
	#high_temp = float(commands.getoutput("cat " + trip_point_location + " | cut -d ' ' -f 13"))
	high_temp = 105
	zone = ""
	title = "CPU"

	# constructor
	def __init__(self, **keyword_args):
		#call super (and not show window yet)
		screenlets.Screenlet.__init__(self, uses_theme=True, **keyword_args)
		self.zone = self.get_zones()[0]
		self.__hddtemp = self.get_hddtemp_data()
		# set theme
		self.theme_name = "default"
		# add default menu items
		self.add_default_menuitems()
		# add settings
		self.add_options_group('Temperature Meter', 'Temperature Meter specific options')
		self.add_option(StringOption('Temperature Meter', 'zone', self.zone,
			'Thermal Zone', 'Thermal zone to monitor',
			choices = self.get_zones()))
		self.add_option(StringOption('Temperature Meter', 'title', self.title,
			'Title', 'Title for the screenlet'))
		self.add_option(FloatOption('Temperature Meter', 'update_interval', 
			self.update_interval, 'Update-Interval', 
			'The interval for updating the temperature meter (in seconds) ...',
			min=0.1, max=60.0))
		self.add_option(BoolOption('Temperature Meter', 'show_text', 
			self.show_text, 'Show Text', 'Show the text on the temperature meter ...'))
		self.add_option(BoolOption('Temperature Meter', 'show_graph', 
			self.show_graph, 'Show Graph', 
			'Show the graph on the temperature meter ...'))
		self.add_option(FloatOption('Temperature Meter', 'low_temp',
			self.low_temp, 'Low Temperature',
			'The coldest expected running temperature ...',
			min=0.1, max=220.0))
		self.add_option(FloatOption('Temperature Meter', 'high_temp',
			self.high_temp, 'High Temperature',
			'The hottest expected running temperature ...',
			min=0.1, max=220.0))
		self.add_option(StringOption('Temperature Meter', 'text_prefix', 
			self.text_prefix, 'Text Prefix', 
			'Text (or Pango-Markup) that shall be placed before the load ...'), 
			realtime=False)
		self.add_option(StringOption('Temperature Meter', 'text_suffix', 
			self.text_suffix, 'Text Suffix', 
			'Text (or Pango-Markup) that shall be placed after the load ...'),
			realtime=False)
		# init the timeout function
		self.update_interval = self.update_interval
	
	# 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_graph)
			else:
				# TODO: raise exception!!!
				self.__dict__['update_interval'] = 1
				pass

	def get_hddtemp_data(self):
		s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		s.connect(('localhost', 7634))
		hddtemp_data = s.recv(1024)
		s.close()
		hddtemp = []
		for i in hddtemp_data.split("\n"):
			hddtemp.append(i.split("|"))
		return hddtemp

	def get_zones(self):
		output = commands.getoutput("acpi -tBS | cut -d ':' -f 1").split("\n")
		zones = ["ACPI: " + x.strip() for x in output]
		zones.append('GPU: nvidia')
		for i in self.__hddtemp:
			zones.append('HDD: ' + i[2])
		return zones
	
	def get_temp(self):
		typezone = self.zone.split(" ", 1)
		if typezone[0] == "ACPI:":
			return self.get_acpitemp(typezone[1])
		elif typezone[0] == "HDD:":
			return self.get_hddtemp(typezone[1])
		elif typezone[0] == "GPU:":
			return self.get_gputemp()
		else:
			return 0

	def get_acpitemp(self, zone):
		"""Get CPU temperature using the ACPI proc interface"""
		#temperature = commands.getoutput("cat " + self.temperature_location + " | cut -d ' ' -f 14")
		output = commands.getoutput("acpi -tBSc | grep '" + zone + "' | cut -d ' ' -f 9")
		return int(float(output))		

	def get_gputemp(self):
		"""Get GPU temperature from nvidia-settings"""
		#Attribute 'GPUCoreTemp' (arie-laptop:0.0): 58.
		output = commands.getoutput("nvidia-settings -q GPUCoreTemp | grep 'Attribute'")
		m = re.search('(\d+)\.$', output)
		output = m.group(0)
		return int(float(output))

	def get_hddtemp(self, disk):
		hddtemp_data = self.get_hddtemp_data()
		for i in hddtemp_data:
			if len(i) == 6 and i[2] == disk:
				return i[3]
		return 0
	
	# timeout-function
	def update_graph(self):
		self.redraw_canvas()
		return True	
	
	def on_draw(self, ctx):
		# get load
		#load = self.get_cpu_load()
		load = self.get_temp()
		#if load > :
		#	load = 99
		#elif load < 0:
		#	load=0
		# set size
		#ctx.scale(self.width/100.0, self.height/100.0)
		ctx.scale(self.scale, self.scale)
		# draw bg (if theme available)
		ctx.set_operator(cairo.OPERATOR_OVER)
		if self.theme:
			self.theme['cpumeter-bg.svg'].render_cairo(ctx)
			ctx.save()
			ctx.translate(15, 15)
			p_layout = ctx.create_layout()
			p_fdesc = pango.FontDescription("Free Sans 12")
			p_layout.set_font_description(p_fdesc)
			p_layout.set_width((self.width) * pango.SCALE)
			p_layout.set_markup(self.title)
			ctx.set_source_rgba(1, 1, 1, 0.8)
			ctx.show_layout(p_layout)
			ctx.restore()
		# draw cpu-graph
		if self.show_graph and self.theme:
			#self.theme['cpumeter-graph-bg.svg'].render_cairo(ctx)
			tmp = load
			if load > self.high_temp :
				tmp = self.high_temp
			elif load < self.low_temp :
				tmp = self.low_temp
			h = (float(tmp) / (self.high_temp - self.low_temp)) * 70.0
			h = h / 2.0
			#print "height: "+str(h)
			# get step
			#steps_height = 7
			#h = 40
			ctx.save()
			ctx.rectangle(20, 10+(70-h), 70, h)
			#ctx.rectangle(20, 15+(70-h), 60, h)
			ctx.clip()
			ctx.new_path()
			self.theme['cpumeter-graph.svg'].render_cairo(ctx)
			ctx.restore()
		# draw text
		if self.show_text:
			ctx.save()
			ctx.translate(15, 35)
			#ctx.set_operator(cairo.OPERATOR_OVER)
			p_layout = ctx.create_layout()
			p_fdesc = pango.FontDescription("Free Sans 20")
			#p_fdesc.set_family_static("Free Sans")
			#p_fdesc.set_size(25 * pango.SCALE)
			p_layout.set_font_description(p_fdesc)
			p_layout.set_width((self.width) * pango.SCALE)
			if len(str(load))==1:
				load = "0" + str(load)
			p_layout.set_markup(self.text_prefix + str(load) + self.text_suffix)
			ctx.set_source_rgba(1, 1, 1, 0.8)
			ctx.show_layout(p_layout)
			ctx.fill()
			ctx.restore()
		# draw glass (if theme available)
		if self.theme:
			self.theme['cpumeter-glass.svg'].render_cairo(ctx)
		
	def on_draw_shape(self,ctx):
		if self.theme:
			# set size rel to width/height
			#ctx.scale(self.width/100.0, self.height/100.0)
			ctx.scale(self.scale, self.scale)
			self.theme['cpumeter-bg.svg'].render_cairo(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__":
	#screenlet = Temperature2Screenlet()
	#screenlet.init_backend()
	#screenlet.main()
	import screenlets.session
	screenlets.session.create_session(Temperature2Screenlet)
