#!/usr/bin/env python
# -*- coding: UTF-8 -*-
'''
 Copyright (C) 2004 jan gerber <j@reboot.fm>

 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
'''

# xmlrpc interface for re_codec: config and status
# no xmlrpc for now. only the functions
#
import sys,os,time,re
import jack
import thread
import syslog
from xml.dom.minidom import parse, parseString,getDOMImplementation

#the config file that hold all the options
config_file="/etc/reboot.fm/re_codec.xml"

#read basics from xml
class confClass:
	def __init__(self):
		if self.read_conf():
			print("could not parse config file: %s" % config_file)

	def read_conf(self):
		try:
			newxml=parse(config_file)
		except:
			return 1
		self.xml=newxml
		self.StreamDecoderURL=self.xml.getElementsByTagName("stream_decoder_url")[0].firstChild.data
		self.FallbackPlaylist=self.xml.getElementsByTagName("fallback_playlist")[0].firstChild.data
		self.jackplumbing_rc=self.xml.getElementsByTagName("jackplumbingrc")[0].firstChild.data
		self.jackmixerStatusFile=self.xml.getElementsByTagName("re_jackmixer_status")[0].firstChild.data
		
		#self.re_ics_cache_file=self.xml.getElementsByTagName("ics_cache_file")[0].firstChild.data
		self.ics_url=self.xml.getElementsByTagName("ics_url")[0].firstChild.data
		self.channels=int(self.xml.getElementsByTagName("channels")[0].firstChild.data)
		
		self.Mode=self.xml.getElementsByTagName("mode")[0].firstChild.data
		
		self.StreamSwitchMode=self.xml.getElementsByTagName("streamswitch")[0].firstChild.data
		self.StreamSwitchStatusfile=self.xml.getElementsByTagName("switch_status")[0].firstChild.data
		self.StreamSwitchDefaultURL=self.xml.getElementsByTagName("switch_default_url")[0].firstChild.data.encode()
		self.StreamSwitchFallbackURL=self.xml.getElementsByTagName("switch_fallback_url")[0].firstChild.data.encode()
		if self.xml.getElementsByTagName("switch_overwrite_url")[0].firstChild:
			self.StreamSwitchOverwriteURL=self.xml.getElementsByTagName("switch_overwrite_url")[0].firstChild.data.encode().strip()
		else:
			self.StreamSwitchOverwriteURL=""
		self.switch_shout_user=self.xml.getElementsByTagName("switch_shout_user")[0].firstChild.data.encode()
		self.switch_shout_password=self.xml.getElementsByTagName("switch_shout_password")[0].firstChild.data.encode()
		self.switch_shout_host=self.xml.getElementsByTagName("switch_shout_host")[0].firstChild.data.encode()
		self.switch_shout_port=int(self.xml.getElementsByTagName("switch_shout_port")[0].firstChild.data)
		self.switch_shout_format=self.xml.getElementsByTagName("switch_shout_format")[0].firstChild.data.encode()
		self.switch_shout_mount=self.xml.getElementsByTagName("switch_shout_mount")[0].firstChild.data.encode()
		self.switch_shout_protocol=self.xml.getElementsByTagName("switch_shout_protocol")[0].firstChild.data.encode()
		return 0


class xmlrpcFunctions:
	# status framework
	def	jackmixerStatus(self):
		try:
			file=open(conf.jackmixerStatusFile,"r")
			jackmixerStatusValue=file.read()
			file.close()
			return jackmixerStatusValue
		except:
			return "unknown"
		
	def	jackmixerLog(self):
		#not implementet in jackmixer right now
		#return array(timestamp : status)
		return []
		
	def	pppdLog(self):
		#not implementet in pppkeepalive right now
		#return array(timestamp : reconnect)
		return []
		
	def	switchStatus(self):
		try:
			file=open(conf.StreamSwitchStatusfile,"r")
			switch_status_value=file.read()
			file.close()
			return switch_status_value
		except:
			return "unknown"
	
	def	switchLog(self):
		#not implementet in switche right now
		#return array(timestamp : status)
		return []  
	
	def	uptime(self):
		f = os.popen('uptime', 'r')
		uptime = f.read()
		f.close()
		return uptime.strip()
	
	# config framework
	def  setStreamDecoderUrl(self,url):
		xml=parse(config_file)
		xml.getElementsByTagName("re_stream_url")[0].firstChild.replaceWholeText(url)
		config_f=open(config_file,"w")
		config_f.write(xml.toxml())
		config_f.close
		return url
	
	def  getStreamDecoderUrl(self):
		return conf.StreamDecoderURL
		
	def	getFallbackPlaylist(self):
		pls_file=open(conf.FallbackPlaylist,"r")
		pls_value=pls_file.read()
		pls_file.close
		return pls_value
	
	def	setFallbackPlaylist(self,pls):
		pls_file=open(conf.FallbackPlaylist,"w")
		pls_file.write(pls)
		pls_file.close
		return 0
	
	def	getJackCapturePorts(self):
		jack.attach('re_config')
		all_ports=jack.get_ports()
		capture_ports= []
		for x in all_ports:
			if (jack.get_port_flags(x) & jack.IsOutput) == 2:
				capture_ports.append(x)
		jack.detach()
		return capture_ports
	
	def	getJackPlaybackPorts(self):
		jack.attach('re_config')
		all_ports=jack.get_ports()
		playback_ports= []
		for x in all_ports:
			if (jack.get_port_flags(x) & jack.IsInput) == 1:
				playback_ports.append(x)
		jack.detach()
		return playback_ports
	
	def	_getJackConnectedPorts(self,port):
		jack.attach('re_config')
		out_ports=[]
		try:
			for y in (jack.get_connections(port)):
				out_ports.append(y)
		except:
			out_ports=[]	
		jack.detach()
		return out_ports
	
	# internal function, not for public use
	def  _updateJackPlumbing(self,replace,new):
		rc_data_out=''
		replaced=0
		rc=open(conf.jackplumbing_rc,'r')
		rc_data=rc.read()
		rc.close()
		for line in rc_data.split('\n'):
			# alter rc_data here
			re_line= re.search(replace,line)
			if re_line:
				rc_data_out +=new +'\n'
				replaced=1
			else:
				rc_data_out +=line +'\n'
		if not replaced:
			rc_data_out +=new +'\n'
		rc=open(conf.jackplumbing_rc,'w')
		rc.write(rc_data_out.strip())
		rc.write('\n')
		rc.close()
		
	def  _resetJackPort(self,port):
		jack.attach('re_config')
		try:
			for y in (jack.get_connections(port)):
				jack.disconnect(port,y)
		except:
			failed=1
		jack.detach()
	
	def	setJackmixerIn(self,portnum,port):
		self._updateJackPlumbing(	're_jackmixer:in_%s'%portnum,
												'(connect "%s" "re_jackmixer:in_%s")'%(port,portnum)
											)
		xml=parse(config_file)
		xml.getElementsByTagName("re_jackmixer_in_%s"%portnum)[0].firstChild.replaceWholeText(port)
		config_f=open(config_file,"w")
		config_f.write(xml.toxml())
		config_f.close
		time.sleep(1)
		self._resetJackPort('re_jackmixer:in_%s'%portnum)
		self._resetJackPort(port)
		return 0
		
	def	getStatusJackmixerIn(self,portnum):
		cannel1=self._getJackConnectedPorts('re_jackmixer:in_1')
		cannel2=self._getJackConnectedPorts('re_jackmixer:in_2')
		return (cannel1,cannel2)

	def	getJackmixerIn(self,portnum):
		return conf.xml.getElementsByTagName("re_jackmixer_in_%s"%portnum)[0].firstChild.data.encode().strip()
		
	def	setJackmixerFallback(self,portnum,port):
		self._updateJackPlumbing(	're_jackmixer:fallback_%s'%portnum,
												'(connect "%s" "re_jackmixer:fallback_%s")'%(port,portnum)
											)
		xml=parse(config_file)
		xml.getElementsByTagName("re_jackmixer_fallback_%s"%portnum)[0].firstChild.replaceWholeText(port)
		config_f=open(config_file,"w")
		config_f.write(xml.toxml())
		config_f.close
		time.sleep(1)
		self._resetJackPort('re_jackmixer:fallback_%s'%portnum)
		self._resetJackPort(port)
		return 0

	def  getStatusJackmixerFallback(self,portnum):
		cannel1=self._getJackConnectedPorts('re_jackmixer:fallback_1')
		cannel2=self._getJackConnectedPorts('re_jackmixer:fallback_2')
		return (cannel1,cannel2)


	def  getJackmixerFallback(self,portnum):
		return conf.xml.getElementsByTagName("re_jackmixer_fallback_%s"%portnum)[0].firstChild.data.encode().strip()
	
	def	setJackmixerOut(self,portnum,port):
		self._updateJackPlumbing(	're_jackmixer:out_%s'%portnum,
												'(connect "re_jackmixer:out_%s" "%s")'%(portnum,port)
											)
		xml=parse(config_file)
		xml.getElementsByTagName("re_jackmixer_out_%s"%portnum)[0].firstChild.replaceWholeText(port)
		config_f=open(config_file,"w")
		config_f.write(xml.toxml())
		config_f.close
		time.sleep(1)
		self._resetJackPort('re_jackmixer:out_%s'%portnum)
		self._resetJackPort(port)
		return 0

	def 	getStatusJackmixerOut(self,portnum):
		cannel1=self._getJackConnectedPorts('re_jackmixer:out_1')
		cannel2=self._getJackConnectedPorts('re_jackmixer:out_2')
		return (cannel1,cannel2)


	def 	getJackmixerOut(self,portnum):
		return conf.xml.getElementsByTagName("re_jackmixer_out_%s"%portnum)[0].firstChild.data.encode().strip()
	
	def	setStreamSwitchIcsURL(self,ics_url):
		conf.ics_url=ics_url
		xml=parse(config_file)
		xml.getElementsByTagName("ics_url")[0].firstChild.replaceWholeText(ics_url)
		config_f=open(config_file,"w")
		config_f.write(xml.toxml())
		config_f.close
		return 0
	
	def	getStreamSwitchIcsURL(self):
		return conf.ics_url

	def	setStreamSwitchOverwriteURL(self,url):
		conf.StreamSwitchOverwriteURL=url
		xml=parse(config_file)
		xml.getElementsByTagName("switch_overwrite_url")[0].firstChild.replaceWholeText(url)
		config_f=open(config_file,"w")
		config_f.write(xml.toxml())
		config_f.close
		return 0

		
	def	getStreamSwitchOverwriteURL(self):
		return conf.StreamSwitchOverwriteURL
	
	def	setStreamSwitchDefaultURL(sel,url):
		conf.StreamSwitchDefaultURL=url
		xml=parse(config_file)
		xml.getElementsByTagName("switch_default_url")[0].firstChild.replaceWholeText(url)
		config_f=open(config_file,"w")
		config_f.write(xml.toxml())
		config_f.close
		return conf.StreamSwitchDefaultURL
		
	def	getStreamSwitchDefaultURL(self):
		return conf.StreamSwitchDefaultURL

	def	setStreamSwitchFallbackURL(sel,url):
		conf.StreamSwitchFallbackURL=url
		xml=parse(config_file)
		xml.getElementsByTagName("switch_fallback_url")[0].firstChild.replaceWholeText(url)
		config_f=open(config_file,"w")
		config_f.write(xml.toxml())
		config_f.close
		return conf.StreamSwitchFallbackURL
		
	def	getStreamSwitchFallbackURL(self):
		return conf.StreamSwitchFallbackURL
		
	def	setStreamSwitchMode(mode):
		conf.StreamSwitchMode=mode
		xml=parse(config_file)
		xml.getElementsByTagName("switchswitch")[0].firstChild.replaceWholeText(url)
		config_f=open(config_file,"w")
		config_f.write(xml.toxml())
		config_f.close
		return conf.StreamSwitchMode
		
	def	getStreamSwitchMode(self):
		return conf.StreamSwitchMode

	def	setMode(mode):
		conf.Mode=mode
		xml=parse(config_file)
		xml.getElementsByTagName("mode")[0].firstChild.replaceWholeText(url)
		config_f=open(config_file,"w")
		config_f.write(xml.toxml())
		config_f.close
		return conf.Mode
		
	def	getMode(self):
		return conf.Mode





conf = confClass()

def print_log(string):
	syslog.syslog(syslog.LOG_NOTICE, string)


def configfileUpdateThread():
	stat=os.stat(config_file)
	while 1:
		
		stat_n=os.stat(config_file)
		if stat_n.st_mtime > stat.st_mtime:
			if conf.read_conf()==0:
				print_log("config file reloaded")
				stat=stat_n
		time.sleep(1)

def startConfigfileUpdateThread():
	thread.start_new(configfileUpdateThread, ())	

if __name__ == '__main__':
	print "this is not a program\n"
	print "use it as a lib\n"
