#!/usr/bin/env python

import subprocess
import sys
import time

""" Shuts down VDR, performs a scan, then updates VDR's channels.conf with
	Freeview numbering. """

INVOKE_RCD = "invoke-rc.d vdr"
STOP_VDR = INVOKE_RCD + " stop"
START_VDR = INVOKE_RCD + " start"
SCAN_COMMAND = "scan -q -o vdr -e 4 -u " \
		+ "/usr/share/doc/dvb-utils/examples/scan/dvb-t/uk-Rowridge"
VDR_CHANNELS_FILE = "/var/lib/vdr/channels.conf"
OUTPUT_FILE = VDR_CHANNELS_FILE 

def scan():
	""" Runs SCAN_COMMAND and returns result as a list of lines. """
	print "Scanning"
	scan_proc = subprocess.Popen(SCAN_COMMAND, 0, None,
			None, subprocess.PIPE, None,
			None, False, True)
	result = scan_proc.wait()
	if result:
		raise Exception("scan failed with exit code %d" % result)
	return scan_proc.stdout.readlines()

def load_channels_as_lines(filename):
	fp = file(filename, 'r')
	lines = fp.readlines()
	fp.close()
	return lines

def lines_to_dict(lines):
	""" Processes the lines and creates a dictionary keyed by channel name.
		Each value is [line, channel_number]. """
	dict = {}
	number = 1
	for l in lines:
		if l.startswith(':@'):
			number = int(l[2:].rstrip())
		else:
			name = l.split(':', 1)[0]
			if ';' in name:
				name = name.split(';', 1)[0]
			dict[name] = [l, number]
			number += 1
	return dict

def dict_to_sorted_lines(dict):
	""" Convert the dictionary back to lines, including :@n where necessary,
		all in the correct order. """
	# Create an intermediate list of [line, channel_number] for sorting
	sortable = []
	for v in dict.values():
		sortable.append(v)
	sortable.sort(key = lambda x: x[1])
	# Now generate lines in output format
	number = -1
	lines = []
	for l in sortable:
		if l[1] != number:
			number = l[1]
			lines.append(":@%d\n" % number)
		lines.append(l[0])
		number += 1
	return lines

def renumber_old_from_new(old, new):
	""" For each entry in the old dict, this looks up the same channel name in
		the new dict and replaces the old channel number with the new one, but
		preserves all the other details from old. No return value; alters old
		in place. """
	for [k, old_val] in old.items():
		new_val = new.get(k)
		if new_val:
			old_val[1] = new_val[1]

def generate_new_lines():
	""" Call the various other functions to generate a nice new list of lines
		to save as VDR's channels.conf. """
	scan_lines = scan()
	vdr_lines = load_channels_as_lines(VDR_CHANNELS_FILE)
	scan_dict = lines_to_dict(scan_lines)
	vdr_dict = lines_to_dict(vdr_lines)
	renumber_old_from_new(vdr_dict, scan_dict)
	return dict_to_sorted_lines(vdr_dict)

def main():
	start_stop_vdr = "-s" in sys.argv
	if start_stop_vdr:
		print "Stopping VDR"
		subprocess.call(STOP_VDR.split())
		print "Pausing"
		time.sleep(5)
	new_lines = generate_new_lines()
	fp = file(OUTPUT_FILE, 'w')
	fp.writelines(new_lines)
	fp.close()
	if start_stop_vdr:
		print "Starting VDR"
		subprocess.call(START_VDR.split())

if __name__ == '__main__':
	main()
