#!/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/>.
#
#  ACPIBatteryScreenlet (c) JMDK 2007 
#
# This screenlets is heavily based on the CPUMeterScreenlet by RYX
#
# INFO:
# - a simple ACPI Battery meter
# 
# This screenlets is heavily based on the CPUMeterScreenlet by RYX

import screenlets
from screenlets.options import IntOption, BoolOption, StringOption, ColorOption
import cairo
import pango
import sys
import gobject
from os import listdir,path
#use gettext for translation
import gettext

_ = screenlets.utils.get_translator(__file__)

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

@tdoc

class ACPIBatteryScreenlet(screenlets.Screenlet):
	"""A simple ACPI Battery meter."""
	
	# default meta-info for Screenlets
	__name__ = 'ACPIBatteryScreenlet'
	__version__ = '0.2.2'
	__author__ = 'JMDK'
	__desc__ = __doc__

	# internals
	__timeout = None
	__flag=0
	
	# settings
	update_interval = 5
	file_auto = True
	file_path='/proc/acpi/battery/BAT0/'
	state_file='state'
	info_file='info'
	alarm_threshold = 5
	show_time = True
	show_percent = True
	show_background = True
	background_color = (0,0,0, 0.4)

	# constructor
	def __init__(self, **keyword_args):
		#call super (and not show window yet)
		screenlets.Screenlet.__init__(self, uses_theme=True,width=100,height=50, **keyword_args)
		
		# set theme
		self.theme_name = "default"
		
		# internals
		self.__timeout = None
		self.__flag=0
		
		# add options that can be changed with the option dialog and will autosave/load
		self.add_options_group(_('ACPI Battery'), _('ACPI Battery specific options'))
		
		self.add_option(IntOption(_('ACPI Battery'), 'update_interval', 
			5, _('Update interval'), _('The interval for updating the ACPI Battery meter in seconds.'),
			min=1, max=60))
		self.add_option(IntOption(_('ACPI Battery'), 'alarm_threshold', 
			5, _('Alarm threshold'), _('The threshold percent for triggering the low battery alarm.'),
			min=1, max=100))
		self.add_option(BoolOption(_('ACPI Battery'), 'file_auto', 
			True, _('Guess battery file'), _('Try to guess which battery to use.')))
		self.add_option(StringOption(_('ACPI Battery'), 'file_path', 
			'/proc/acpi/battery/BAT0/', _('Battery files path'), _('Path to the battery files.')),
			realtime=False)
		self.add_option(StringOption(_('ACPI Battery'), 'state_file', 
			'state', _('Battery state file'), _('Name of the battery state file.')),
			realtime=False)
		self.add_option(StringOption(_('ACPI Battery'), 'info_file', 
			'info', _('Battery info file'), _('Name of the battery info file.')),
			realtime=False)
		self.add_option(BoolOption(_('ACPI Battery'), 'show_time', 
			True, _('Display time'), _('Show remaining time on ACPI battery meter.')))
		self.add_option(BoolOption(_('ACPI Battery'), 'show_percent', 
			True, _('Display percentage'), _('Show percentage on ACPI battery meter.')))
		self.add_option(ColorOption(_('ACPI Battery'),'background_color', 
			(0,0,0, 0.4), _('Back color(only with default theme)'), _('Only works with default theme')))
		
		# create the right click menu
		self.add_default_menuitems()

		# init the timeout function
		self.update_interval = self.update_interval
		self.file_auto = self.file_auto
		self.file_path = self.file_path
	
	# attribute-"setter", handles setting of attributes
	def __setattr__(self, name, value):
		# important: call Screenlet.__setattr__ in baseclass
		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
				
		elif name == "file_auto":
			if value:
				try:
					dirs=listdir('/proc/acpi/battery/')
				except OSError:
					dirs=[]
				
				dirs.sort();
				try:
					self.__dict__['file_path']='/proc/acpi/battery/'+dirs[0]+'/'
				except IndexError:
					pass
					
		elif name == "file_path":
			if self.__flag>0:
				self.__dict__['file_auto']=0
			self.__flag+=1
	
	def get_value(self):
		present_rate = None
		charge_status='NA'
		ispresent='no'
		if path.exists(self.file_path+self.state_file):
			file=open(self.file_path+self.state_file,'r')
			while 1:
				line = file.readline()
				if ((not line)|(line.find('present') > -1)): break
			if line:
				linelist=line.rstrip('\n').split(' ')
				i=1
				while (i<len(linelist)):
					if ((linelist[i]=='yes')|(linelist[i]=='no')):
						ispresent=linelist[i]
						break
					else: i+=1
			if (ispresent=='yes'):
				while 1:
					line = file.readline()
					if ((not line)|(line.find('charging state') > -1)): break
				if line:
					linelist=line.rstrip('\n').split(' ')
					i=1
					while (i<len(linelist)):
						if ((linelist[i]=='charged')|(linelist[i]=='charging')|(linelist[i]=='discharging')):
							charge_status=linelist[i]
							break
						else: i+=1
				while 1:
					line = file.readline()
					if ((not line)|(line.find('present rate') > -1)): break
				linelist=line.split(' ')
				i=0
				while (i<len(linelist)):
					if (linelist[i].isdigit()):
						present_rate=linelist[i]
						break
					else: i+=1
				while 1:
					line = file.readline()
					if ((not line)|(line.find('remaining') > -1)): break
				linelist=line.split(' ')
				i=0
				while (i<len(linelist)):
					if (linelist[i].isdigit()):
						remaining=linelist[i]
						break
					else: i+=1
			else:
				present_rate=1
				remaining=1				
			file.close()
		else:
			present_rate=1
			remaining=1
		if (ispresent=='yes'):
			if path.exists(self.file_path+self.state_file):
				file=open(self.file_path+self.info_file,'r')
				while 1:
					line = file.readline()
					if ((not line)|(line.find('last full') > -1)): break
				linelist=line.split(' ')
				i=0
				while (i<len(linelist)):
					if (linelist[i].isdigit()):
						last_full=linelist[i]
						break
					else: i+=1
				file.close()
			else:
				last_full=1
		else:
			last_full=1
		if present_rate == None : present_rate = '1000'
		if int(present_rate)==0: present_rate='1000';
		return (charge_status,present_rate,remaining,last_full)
		
	# timeout-function
	def update_graph(self):
		self.redraw_canvas()
		return True
	
	def on_draw(self, ctx):
		(charge_status,present_rate,remaining,last_full)=self.get_value()
		percents="%3i" % ((100*int(remaining)) / int(last_full))
		# set size
		ctx.scale(self.scale, self.scale)
		# draw bg (if theme available)
		ctx.set_operator(cairo.OPERATOR_OVER)
		if self.theme :
			ctx.set_source_rgba(*self.background_color)
			if self.theme_name == 'default':self.draw_rounded_rectangle(ctx,0,0,9,96.6,46.5)
			self.theme.render(ctx,'acpibattery-bg')
		self.theme.render(ctx,'acpibattery-battery')
		if charge_status=='charged': 
			time_value='  Full'
		elif charge_status=='discharging':
			t=(60*int(remaining))/int(present_rate)
			time_value="%02i:%02i" % (int(t/60),int(t%60))
			if int(percents)<=self.alarm_threshold:
				self.theme.render(ctx,'acpibattery-alarm')
			else:
				self.theme.render(ctx,'acpibattery-using')
		elif charge_status=='charging':
			t=(60*(int(last_full)-int(remaining)))/int(present_rate)
			time_value="%02i:%02i" % (int(t/60),int(t%60))
			self.theme.render(ctx,'acpibattery-charging')
		else:
			time_value='   NA'
			percents='   0'
			self.theme.render(ctx,'acpibattery-alarm')
		if charge_status=='NA':
			# draw message
			ctx.save()
			ctx.translate(37,5)
			ctx.set_source_rgba(1, 0, 0, 1)
			self.draw_text(ctx,'   No',0,0,"FreeSans", 14,  self.width)
			ctx.fill()
			ctx.restore()							
			ctx.save()
			ctx.translate(37,26)
			ctx.set_source_rgba(1, 0, 0, 1)
			self.draw_text(ctx,' battery',0,0,"FreeSans", 12,  self.width)
			ctx.restore()									
		elif self.show_time and self.show_percent:
			# draw percent and time
			ctx.save()
			ctx.translate(37,5)
			if int(percents)<=self.alarm_threshold:
				ctx.set_source_rgba(1, 0, 0, 1)
			else:
				ctx.set_source_rgba(1, 1, 1, 1)
			self.draw_text(ctx,percents+"%",0,0,"FreeSans", 16,  self.width)
			ctx.restore()							
			ctx.save()
			ctx.translate(37,26)
			if int(percents)<=self.alarm_threshold:
				ctx.set_source_rgba(1, 0, 0, 1)
			else:
				ctx.set_source_rgba(1, 1, 1, 1)
			self.draw_text(ctx,time_value,0,0,"FreeSans", 14,  self.width)
			ctx.restore()							
		elif self.show_time:
			# draw time
			ctx.save()
			ctx.translate(37,13)
			if int(percents)<=self.alarm_threshold:
				ctx.set_source_rgba(1, 0, 0, 1)
			else:
				ctx.set_source_rgba(1, 1, 1, 1)
			self.draw_text(ctx,time_value,0,0,"FreeSans", 16,  self.width)
			ctx.restore()				
		else:
			# draw percent
			ctx.save()
			ctx.translate(37,13)
			if int(percents)<=self.alarm_threshold:
				ctx.set_source_rgba(1, 0, 0, 1)
			else:
				ctx.set_source_rgba(1, 1, 1, 1)
			self.draw_text(ctx,percents+"%",0,0,"FreeSans", 16,  self.width)
			ctx.restore()
		# draw glass (if theme available)
		if self.theme:
			self.theme.render(ctx,'acpibattery-glass')
		
	def on_draw_shape(self,ctx):
		if self.theme:
			ctx.scale(self.scale, self.scale)
			self.draw_rectangle(ctx,0,0,self.width,self.height)
			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(ACPIBatteryScreenlet)

