#    PyNetMony Netmonitor for S60 3rd Edition phones
#
#    Copyright (C) 2007  Carsten Knuetter, Georg Lukas
#
#    email: netmonitor.s80@o2online.de
#
#    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/>.


import appuifw
import e32
import location
import sysinfo
import time
import positioning
import sys
import audio
from audio import *
from graphics import *




index=0
running=1
light=True
tab=0
s = None


font=u"normal"
color=(255,255,255)
linecol=(255,128,128)
border=(255,0,0)
bg=(0,0,60)

rxl_log = []
rxl_last = 0

loc_log = []
logging = 0
logname = "e:/test.txt"
toggle = 2

class Logger:
	def __init__(self, log_name):
		self.logfile = log_name
	def write(self, obj):
		log_file = open(self.logfile, 'a')
		log_file.write(obj)
		log_file.close()
	def writelines(self, obj):
		self.write(''.join(list))
	def flush(self):
		pass
		
class MyFormView( object ):
    
    ## The constructor.
    def __init__( self ):
        ## Bool
        self._iIsSaved = False
        ## Model list.
        self._iSound = [u'OFF', u'Sound', u'Voice']
        ## Model list.
        self._iLight = [u'OFF', u'Cell change on', u'Always on']
	self._iVoice = [u'Cell only', u'Band & Cell', u'Band & Cell & LAC', u'Cell & LAC & NET']
        ## Form fields.
        self._iFields = [( u'CellNotify', 'combo', ( self._iSound, 0 ) ),
                         ( u'Light', 'combo', ( self._iLight, 0 ) ),
                         ( u'Refresh','float', 0.5 ),
			 ( u'Volume','number', 5 ),
                         ( u'VoiceText','combo', (self._iVoice, 0) )]
 
 
    ## Displays the form.
    def setActive( self ):
        self._iIsSaved = False
        #self._iForm = appuifw.Form(self._iFields, appuifw.FFormEditModeOnly)
        self._iForm.save_hook = self._markSaved
        self._iForm.flags = appuifw.FFormEditModeOnly
        self._iForm.execute( )
		
    def setActiveFirst( self ):
        self._iIsSaved = False
        self._iForm = appuifw.Form(self._iFields, appuifw.FFormEditModeOnly)
        self._iForm.save_hook = self._markSaved
        self._iForm.flags = appuifw.FFormEditModeOnly
        #self._iForm.execute( )
 
    ## save_hook send True if the form has been saved.
    def _markSaved( self, aBool ):
        self._iIsSaved = aBool
 
                
    ## _iIsSaved getter.
    def isSaved( self ):
        return self._iIsSaved
 
    # here you can put for example all the getters you need:
    #---------------------------------------------------------
 
    ## Return mobile field value.
    def getSound( self ):
        ## This returns the mobile; In one case I needed to have UTF-8 encoding
        return self._iSound[self._iForm[0][2][1]].encode( "utf-8" )
 
 
    ## Return model field value..
    def getLight( self ):
        ## This would return the index
        #return self._iForm[1][2][1]
        ## This returns the model
        return self._iLight[self._iForm[1][2][1]].encode( "utf-8" )
 
 
    ## Return amount field value.
    def getAmount( self ):
        return self._iForm[2][2]
 
 
    ## Return date field value.
    def getVolume( self ):
        return self._iForm[3][2]
 
 
    ## This returns the model
    def getVoice( self ):
        return self._iVoice[self._iForm[4][2][1]].encode( "utf-8" )    

img=Image.new((800,352))

def screen_setup():
	global img
	size,offset = appuifw.app.layout(appuifw.EMainPane)

	img.rectangle((0,0)+size,outline=border,fill=bg)
	img.text((50,20), u'PyNetMony 0.2.14',fill=color)
	img.text((75,40), u'(c) 2007 by',fill=color)
	img.text((10,60), u'Carsten Knütter, Georg Lukas',fill=color)
	img.text((10,90), u'netmonitor.s80@o2online.de',fill=color)
	img.text((5,110), u'This program comes with',fill=color)
	img.text((5,130), u'ABSOLUTELY NO WARRANTY',fill=color)
	img.text((5,160), u'This is free software, and you',fill=color)
	img.text((5,180), u'are welcome to redistribute',fill=color)
	img.text((5,200), u'it under certain conditions',fill=color)
	#img.text((2,220), u'RES: ',fill=(255,255,255), font=(None,40))
	#img.text((2,210), u'certain conditions',fill=color)
	#img.text((35,230), u'Press Options to start... ',fill=color)

def menus_setup():
	global tab, menu
	appuifw.app.menu = menu
	appuifw.app.set_tabs([u"NetMon", u"Graph", u"History", u"GPS", u"About"], set_tab)
	appuifw.app.activate_tab(tab)
	
def rotate():
	if appuifw.app.orientation == 'landscape':
		appuifw.app.orientation = 'portrait'
	else:
		appuifw.app.orientation = 'landscape'
		
def setup():
    SetupForm.setActive( )

def set_tab(newtab):
	global tab
	tab = newtab
	handle_redraw(())

def startlog():
	global menu, logging, logname
	menu = [(u"Netmonitor", netmonitor),(u"Stop Logging", stoplog),(u"Orientation", rotate),(u"Settings", setup)]
	appuifw.app.menu = menu
	logname = "e:/NetMonLog_"+time.strftime("%Y%m%d_%H%M%S")+".txt"
	my_log = Logger(logname)
	sys.stderr = sys.stdout = my_log
	print "Date	Time	CID	LAC	MCC	MNC	RNC	RXL	LON	LAT"
	logging = 1

def stoplog():
	global menu, logging
	logging = 0
	menu = [(u"Netmonitor", netmonitor),(u"Start Logging", startlog),(u"Orientation", rotate),(u"Settings", setup)]
	appuifw.app.menu = menu
	
def writelog(Date, Time, CID, LAC, MCC, MNC, RNC, RXL, LON, LAT):
	my_log = Logger(logname)
	sys.stderr = sys.stdout = my_log
	print unicode(Date)+u"	"+unicode(Time)+u"	"+unicode(CID)+u"	"+unicode(LAC)+u"	"+unicode(MCC)+u"	"+unicode(MNC)+u"	"+unicode(RNC)+u"	-"+unicode(RXL)+u"	"+unicode(LON)+u"	"+unicode(LAT)
	
def settings():
	global index
	L = [u'Light on']
	index = appuifw.multi_selection_list(L , style='checkmark', search_field=0)
	#light = (index == (0,))
	handle_redraw(())

def sound_play():
		global s
		try:
			s.set_volume(SetupForm.getVolume())
			s.play()
		except:
			appuifw.note(u"Sound Error",'error')
			
def decode_cid(mcc, mnc, cid):
	if (mnc == 7) and (mcc == 262) and (cid > 65535):
		cidhex=hex(cid)
		rnc=int(cidhex[2:4],16)
		cid=int(cidhex[-4:],16)
		return (cid, rnc)
	else:
		return (cid, 'n/a')


def log_rxl(t, rxl):
	global rxl_log, rxl_last
	if rxl_last == 0:
		rxl_last = t - 1
	while t > rxl_last:
		# rescue last 1000 entries
		rxl_log = rxl_log[-999:] + [rxl]
		rxl_last += 1

def log_loc(t, gsmloc):
	global loc_log
	if len(loc_log) > 0 and gsmloc == loc_log[-1:][0][1]:
		return
	loc_log += [[t, gsmloc]]
	

def draw_netmon(lac, mcc, mnc, rnc, rxl, ver, imei):
	bars = sysinfo.signal_bars()
	batty = sysinfo.battery()
	ram = sysinfo.free_ram()/1024
	totram = sysinfo.total_ram()/1024
	x = appuifw.app.layout(appuifw.EScreen)
	img.text((20,40), u'LAC: '+unicode(lac),fill=color)
	img.text((20,80), u'NET: '+unicode(mcc)+u" - "+unicode(mnc),fill=color)
	img.text((20,60), u'RNC: '+unicode(rnc),fill=color)
	img.text((20,100), u'RXL: -'+unicode(rxl)+u" dBm ("+unicode(bars)+u")",fill=color)
	img.text((20,120), u'BAT: '+unicode(batty)+u" %",fill=color)
	#img.text((20,160), u'RAM: '+unicode(ram)+u" KB",fill=color)
	img.text((20,140), u'RAM: '+unicode(ram)+u" / "+unicode(totram)+u" KB",fill=color)
	img.text((20,160), u'VER: '+unicode(ver),fill=color)
	img.text((20,180), u'IMEI: '+imei,fill=color)
	img.text((20,200), u'RES: '+unicode(x),fill=color)
	#img.text((20,220), unicode(index),fill=color)

def draw_rxl_line(size, pos, text):
	sz = (size[1]-2, 14)
	i = Image.new(sz, '1')
	i.rectangle((0,0)+sz, fill=0x000000)
	i.text((2,11), text, 0xffffff)
	irot = i.transpose(ROTATE_90)
	img.blit(irot, target=pos, mask=irot)
	#img.text((0,200), unicode(sz)+unicode(pos)+text, color)

def headline(size, cid):
	w = size[0]
	h = size[1]
	# CLK and CID always on top
	img.text((3,18), unicode(time.strftime("%H:%M:%S")),fill=color)
	if logging == 1:
		img.text((w/2-37,18), u'L CID: '+unicode(cid),fill=color)
	else:
		img.text((w/2-37,18), u'CID: '+unicode(cid),fill=color)
		
		
def draw_rxlgraph(size):
	global rxl_log, loc_log
	t = time.time()
	w = size[0]
	h = size[1]
	sublog = rxl_log[-w:]
	xcoord = range(w-len(sublog)+1, w+1)
	line = zip(xcoord, sublog)
	img.line(line, outline=linecol)
	x = w
	l = len(loc_log)-1
	#img.text((0,h-36),unicode(loc_log),linecol)
	while x > -60 and l >= 0:
		offset = t - loc_log[l][0]
		(mcc, mnc, lac, cid) = loc_log[l][1]
		(cid, rnc) = decode_cid(mcc, mnc, cid)
		x -= offset
		img.line((x,0,x,h),outline=linecol)
		draw_rxl_line(size, (x+1, 1), unicode(mcc)+"-"+unicode(mnc)+u"  CID: "+unicode(cid)+u"  LAC: "+unicode(lac))
		l-=1
	img.text((w-70, 18), u"-" + unicode(rxl_log[-1:][0]) + u"dBm", color)
		
def draw_history_line(x, y, tstamp, net, lac, cid, rnc):
	img.text((5+x, y), unicode(tstamp), color)
	img.text((85+x, y), unicode(cid), color)
	img.text((140+x, y), unicode(lac), color)
	img.text((200+x, y), unicode(rnc), color)
	#if rnc != 'n/a':
	img.text((250+x, y), unicode(net), color)

def draw_history(size):
	global loc_log
	y = 64
	count = (size[1]-y)/16
	if size[0] > 320:
		count = 2 * count
		draw_history_line(400, y-16, "Time", "Net", "LAC", "CID", "RNC")
	#img.text((0, 10), unicode(count), color)
	draw_history_line(0, y-16, "Time", "Net", "LAC", "CID", "RNC")
	x = 0
	i = 0
	for v in loc_log[-count:]:
		t = time.strftime("%H:%M:%S ", time.localtime(v[0]))
		(mcc, mnc, lac, cid) = v[1]
		(cid, rnc) = decode_cid(mcc, mnc, cid)
		if (i == (count/2)) and (size[0] > 320):
			x = 400
			y = 64
		draw_history_line(x, y, t, unicode(mcc)+"-"+unicode(mnc), \
			lac, cid, rnc)
		y += 16
		i += 1
		

def gps():
	positioning.modules()
	img.text((10,60), u'GPS: '+unicode(positioning.modules()),fill=color)
	img.text((10,80), u'GPS: '+unicode(positioning.module_info(positioning.default_module())),fill=color)
	img.text((10,100), u'Light: '+unicode(SetupForm.getVoice()),fill=color)
	
def netmonitor():
	global index, toggle
	imei=sysinfo.imei()
	ver = sysinfo.os_version()
	oldcid = 0
	oldlac = 0
	while running:
		umts = 0
		size,offset = appuifw.app.layout(appuifw.EMainPane)
		#clear(color=(0,0,60))
		#img.line((20,20,20,120),0xff00ee)
		#img.rectangle((0,0,240,235),border,fill=bg)
		#img.rectangle((0,0)+size,border,fill=bg)
		#img.point((50.,150.),border,width=40)
		#img.ellipse((100,150,150,180),0x0000ff)
		#img.text((100,80), u'hello')
		img.rectangle((0,0)+size,outline=border,fill=bg)
		rnc="n/a"
		t = time.time()
		gsmloc = location.gsm_location()
		rxl = sysinfo.signal_dbm()
		if gsmloc is None:
			mcc = mnc = lac = cid = rnc = cid = "n/a"
		else:
			log_loc(t, gsmloc)
			(mcc, mnc, lac, cid) = gsmloc
			if cid > 65535:
				umts = 1
			(cid, rnc) = decode_cid(mcc, mnc, cid)
			if cid != oldcid:
				oldcid = cid
				if unicode(SetupForm.getLight())==u'Cell change on':
					e32.reset_inactivity()
				if unicode(SetupForm.getSound())==u'Sound':
					sound_play()
				if unicode(SetupForm.getSound())==u'Voice':
					#sound.set_volume(SetupForm.getVolume())
					try:
						if unicode(SetupForm.getVoice())==u'Cell only':
							audio.say(unicode(cid))
						elif unicode(SetupForm.getVoice())==u'Band & Cell':
							if umts == 1:
								audio.say(u'U M T S   '+unicode(cid))
								#audio.say(u'Oh tuh U M T S  40041 test '+unicode(cid)+u' L A C '+unicode(lac))
							else:
								audio.say(u'G S M   '+unicode(cid))
						elif unicode(SetupForm.getVoice())==u'Band & Cell & LAC':
							if umts == 1:
								if oldlac != lac:
									audio.say(u'U M T S   '+unicode(cid)+u' L A C '+unicode(lac))
								else:
									audio.say(u'U M T S   '+unicode(cid))
							else:
								if oldlac != lac:
									audio.say(u'G S M '+unicode(cid)+u' L A C '+unicode(lac))
								else:
									audio.say(u'G S M '+unicode(cid))
						elif unicode(SetupForm.getVoice())==u'Cell & LAC & NET':
							if umts == 1:
								if oldlac != lac:
									if (mcc == 262) and (mnc == 7):
										audio.say(u'Oh tuh U M T S   '+unicode(cid)+u' L A C '+unicode(lac))
									elif (mcc == 262) and (mnc == 1):
										audio.say(u'D 1 U M T S   '+unicode(cid)+u' L A C '+unicode(lac))
									elif (mcc == 262) and (mnc == 3):
										audio.say(u'E plus U M T S   '+unicode(cid)+u' L A C '+unicode(lac))
									elif (mcc == 262) and (mnc == 2):
										audio.say(u'D 2 U M T S   '+unicode(cid)+u' L A C '+unicode(lac))
									else:
										audio.say(u'M C C '+unicode(mcc)+u' M N C '+unicode(mnc)+u' U M T S   '+unicode(cid)+u' L A C '+unicode(lac))										
								else:
									audio.say(u'U M T S   '+unicode(cid))
							else:
								if oldlac != lac:
									if (mcc == 262) and (mnc == 7):
										audio.say(u'Oh tuh G S M   '+unicode(cid)+u' L A C '+unicode(lac))
									elif (mcc == 262) and (mnc == 1):
										audio.say(u'D 1 G S M   '+unicode(cid)+u' L A C '+unicode(lac))
									elif (mcc == 262) and (mnc == 3):
										audio.say(u'E plus G S M   '+unicode(cid)+u' L A C '+unicode(lac))
									elif (mcc == 262) and (mnc == 2):
										audio.say(u'D 2 G S M   '+unicode(cid)+u' L A C '+unicode(lac))
									else:
										audio.say(u'M C C '+unicode(mcc)+u' M N C '+unicode(mnc)+u' G S M   '+unicode(cid)+u' L A C '+unicode(lac))										
								else:
									audio.say(u'G S M   '+unicode(cid))
					except:
						appuifw.note(u"Sound Error",'error')
				oldlac = lac
		log_rxl(t, rxl)
		if tab==0:
			#appuifw.app.body=canvas
			headline(size, cid)
			draw_netmon(lac, mcc, mnc, rnc, rxl, ver, imei)
		elif tab==1:
			#appuifw.app.body=canvas
			headline(size, cid)
			draw_rxlgraph(size)
		elif tab==2:
			#appuifw.app.body=canvas
			headline(size, cid)
			draw_history(size)
		elif tab==3:
			#appuifw.app.body=canvas
			gps()
		elif tab==4:
			#appuifw.app.body=canvas
			screen_setup()
		handle_redraw(())
		if logging == 1:
			if toggle == 2:
				writelog(time.strftime("%Y/%m/%d"), time.strftime("%H:%M:%S"), cid, lac, mcc, mnc, rnc, rxl, mnc, mnc)
				toggle = 0
			toggle = toggle +1 
		if unicode(SetupForm.getLight())==u'Always on':
			e32.reset_inactivity()
		#e32.ao_yield()
		e32.ao_sleep(0.5)
		
		
def handle_redraw(rect):
	canvas.blit(img)
	
def exit_key_handler():
	global script_lock, running, s
	script_lock.signal()
	#appuifw.app.set_exit()
	running=0
	s.close()
	appuifw.app.set_tabs([], None)
	
canvas=appuifw.Canvas(event_callback=None, redraw_callback=handle_redraw)
appuifw.app.screen='normal'
appuifw.app.title = u"PyNetMony"
appuifw.app.body=canvas
#appuifw.app.body = appuifw.Text(u"Press Options button below ...")

script_lock = e32.Ao_lock()
SetupForm = MyFormView( )
menu = [(u"Netmonitor", netmonitor),(u"Start Logging", startlog),(u"Orientation", rotate),(u"Settings", setup)]
screen_setup()
menus_setup()
appuifw.app.exit_key_handler = exit_key_handler
try:
	file = u"e:\\fanfare3.mp3"
	s = Sound.open(file)
except:
	appuifw.note(u"Sound Error",'error')
SetupForm.setActiveFirst()
#audio.say(u'test 123456789')
netmonitor()
script_lock.wait()
