#!/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.
'''	
import os,string,re
from sys import exit,stdout
from ogg import OggSyncState, vorbis
from shout import Shout,ShoutException
from types import NoneType
from urllib2 import urlopen,HTTPError
from urlparse import urlparse
import urllib2
import socket
from math import *
import syslog
import thread
import base64

#aptitude install python-pdi
from pdi.icalendar import VCalendar,ICalendar
import pdi.parser

#aptitude install python-dateutil
from dateutil.parser import *
import time,datetime

#config
pidfile="/tmp/replay.pid"
playlist="/dev/shm/reboot.fm_replay.m3u"
local_host = ['rbfm.reboot.fm','8000']
icecast_auth = ['admin','hack4me']
mainstream="/reboot.fm.ogg"
StreamSwitchDefaultURL="http://rbfm.reboot.fm:8000/line-in.ogg"
ics="http://www.reboot.fm/vcal/current.ics"

ices_config="./ices.xml"
icecast_config="./icecast.xml"
ices="ices2 %s" % ices_config
archive_folder="/data/recording/streamswitch2"

stream="http://%s:%s%s" %(local_host[0],local_host[1],mainstream)
#end of config

#might be a good idea to get the stuff from the icecast and ices config file.
#pidfile,playlist,local_host,icecast_auth
#
calendar=None

def print_log(string):
	print string

def ping_auth_url(url, username, password):
    request = urllib2.Request(url)
    b64 = base64.encodestring('%s:%s' % (username, password))[:-1]
    request.add_header('Authorization', 'Basic %s' % b64)
    try:
        urllib2.urlopen(request)
    except urllib2.HTTPError:
        return False
    return True

def check_for_new():
	global calendar, StreamSwitchDefaultURL
	(url, title, eid) = (StreamSwitchDefaultURL,'','')
	date_now=parse(time.strftime("%Y%m%dT%H%M%S"))
	last_show=date_now
	#allow undefined parts in the ical file, and go with the defaults:
	show_time=(date_now,date_now+datetime.timedelta(minutes=5))
	archive=False

	for show in calendar.components:
		try:
			next_show=parse(show.properties['DTSTART'].getContent().strip())
			next_show_end=parse(show.properties['DTEND'].getContent().strip())
		except:
			continue
		date_now=parse(time.strftime("%Y%m%dT%H%M%S"))

		if next_show-last_show < datetime.timedelta(0) and next_show_end>= date_now:
			last_show=next_show
			show_time=(next_show,next_show_end)
			if show.properties['LOCATION'].getContent().strip():
				location=show.properties['LOCATION'].getContent().strip()
				# the "play files on the same system not over http" hack
				#FIXME: need a more powerful of the url2local regexp, should go into config/own function
				if re.search("http://archive.reboot.fm/",location):
					url=location.replace("http://archive.reboot.fm/","/data/archive/")
				else:
					url=location
			else:
				url=StreamSwitchDefaultURL
			title = show.properties['SUMMARY'].getContent().strip().replace("\,",",")
			eid = show.properties['UID'].getContent().strip().replace("emission_id-","")
			categories=show.properties['CATEGORIES'].getContent().strip().split("\,")
			archive=False
			for categorie in categories:
				if categorie == 'archive':
					archive=True
			#print (last_show,next_show,title)

	return (url,show_time,title,eid,archive)

def get_new_ical_from_url(url):
	global calendar
	try:
		ics_fh=urlopen(url)
	except:
		print_log("coudn't open ical url: %s"%url)
		return None
	try:
		new_calendar = pdi.parser.fromFileObject(ics_fh, ICalendar())
	except:
		print_log("coudn't get the ical file")
		ics_fh.close
		return None
	ics_fh.close
	calendar=new_calendar

def update_fallback(fallback):	
	url="http://%s:%s/admin/fallbacks?mount=%s&fallback=%s" % (local_host[0],local_host[1],mainstream,fallback)
	ping_auth_url(url,icecast_auth[0], icecast_auth[1])
	print url

def string2filename(string):
	return string.replace(" ","_").replace('/','.').replace('\\','.').replace("'",'-').replace("`",'-').replace("\"",'-').replace("!",".")

def format_filename(title,emission_id):
	return "%s_%s.%s.ogg" % (time.strftime("%Y-%m-%d_%H.%M"),string2filename(title),emission_id)

def switch_next(next,show_time,title,emission_id,archive):
	global current_show_url
	if current_show_url!=next:
		if next !='' and re.search("http:",next)==None: #start a new file from playlist.
			cmd="echo \"%s\" > %s;test -e %s && kill -USR1 `cat %s ` || { %s & }" % (next,playlist,pidfile,pidfile,ices)
			print cmd
			print title
			f = os.popen(cmd, 'r')
			#f.read()
			f.close()
			#FIXME: set special fallback stream for archived/preproduced shows
			#needs a timeout before this is called
			update_fallback("/reboot.fm.fallback.ogg")
	
		elif next!='': #relay stream & save file.
			# create relay stream object
			url=urllib2.Request(next)
			host=url.get_host().split(':')
			if len(host)==1: 
				host.append('80')
			if host==local_host: 
				print "just  set fallback of mainstream and stop a possible running ices. now move clients from old fallback to new."
				# update fallback
				update_fallback(url.get_selector())
				#FIXME: will clients connected to the old fallback be moved to new one? have to try that out.
				# kill ices
				cmd="test -e %s && kill `cat %s ` &" % (pidfile,pidfile)
				print cmd
				f = os.popen(cmd, 'r')
				#f.read()
				f.close()
	
			else: #relay a stream, 
			#FIXME:  this still needs adding the relay-blurb to the icecast config and reloading
				print "<relay>\n<server>%s</server>\n<port>%s</port>\n<mount>%s<mount>\n<local-mount>%s</local-mount>\n</relay>" % (host[0],host[1],url.get_selector(),url.get_selector().replace("/","/relay_"))
	
			# add relay to icecast, set it as fallback to mainstream and stop a possible running ices.
			# now move clients from old fallback to new.
	
	#FIXME: start the archive process, might be good to know the length of the show here to 
	#FIXME: dispatch the archive program with an end time.
	#FIXME: need endtime, need save rutines etc. pp.
	if archive:
		filename=format_filename(title,emission_id)
		time_diff=show_time[1]-parse(time.strftime("%Y%m%dT%H%M%S"))
		curl="nohup curl --silent \"%s\" -o \"%s/%s\" -m %s &" % (stream,archive_folder,filename,time_diff.seconds)
		print curl
		f = os.popen(curl, 'r')
		f.close()


if __name__ == '__main__':
	get_new_ical_from_url(ics)
	(next,show_time,title,emission_id,archive)=check_for_new()
	#print (next,title,emission_id)
	last=show_time[0]
	current_show_url=''
	switch_next(next,show_time,title,emission_id,archive)
	while 1:
		(next,show_time,title,emission_id,archive)=check_for_new()
		if show_time[0] != last:
			last=show_time[0]
			switch_next(next,show_time,title,emission_id,archive)
		time.sleep(1)
		if not int(time.time()) % 60:
			get_new_ical_from_url(ics)
