#!/usr/bin/python

import os
import sys
import pwd
import errno
import argparse
import time
import configobj
import validate
import subprocess
import threading
import daemon
import daemon.pidlockfile

class Thread(threading.Thread):

	def __init__(self):
		threading.Thread.__init__(self)
		self.setDaemon(True)


class FetcherThread(Thread):
	""" Run py-i2phosts-fetcher periodically """

	def run(self):
		while True:
			run_prog('py-i2phosts-fetcher')
			time.sleep(float(config['fetch_interval']))


class CheckerThread(Thread):
	""" Run py-i2phosts-checker, py-i2phosts-maint, py-i2phosts-builder periodically """

	def run(self):
		while True:
			run_prog('py-i2phosts-checker')
			run_prog('py-i2phosts-maint')
			run_prog('py-i2phosts-builder')
			time.sleep(float(config['check_interval']))


def run_prog(prog):
	try:
		log.info('launching %s', prog)
		sp_args = [prog]
		if args.debug or args.verbose:
			sp_args.append('-d')
		p = subprocess.Popen(sp_args, shell=False)
	except OSError, e:
		log.error('failed to exec %s: %s', prog, e)
		if e.errno == errno.ENOENT:
			log.error('   maybe it isn\'t in PATH')
	else:
		p.wait()
		log.info('%s finished', prog)


def main():
	def run_fetcher():
		fetcher = FetcherThread()
		fetcher.start()
		return fetcher

	def run_checker():
		checker = CheckerThread()
		checker.start()
		return checker

	# if we're just started, wait while fetcher get some new hosts
	fetcher = run_fetcher()
	fetcher.join(300) # wait for 5 mins
	# start checker and other
	checker = run_checker()

	while True:
		if fetcher.isAlive() == False:
			fetcher = run_fetcher()
		if checker.isAlive() == False:
			checker = run_checker()
		# do check every 30 mins
		time.sleep(1800)

# parse command line options
parser = argparse.ArgumentParser(
		description='Master daemon for py-i2phosts.',
		epilog='Report bugs to http://zzz.i2p/topics/733')
parser.add_argument('-d', '--debug', action='store_true',
		help='run in debug mode without detaching from terminal'),
parser.add_argument('-v', '--verbose', action='store_true',
		help='run in verbose mode without detaching from terminal'),
parser.add_argument('-c', '--config', default='/etc/py-i2phosts/master.conf', dest='config_file',
		help='config file to use')
args = parser.parse_args()

# read and validate config
spec = '''
	log_file = string(default='/var/log/py-i2phosts/master.log')
	log_level = option('debug', 'info', 'warning', 'error', 'critical', default='info')
	pid_file = string(default='/var/run/py-i2phosts/master.pid')
	runas = string(default='_pyi2phosts')
	run_fetcher = boolean(default=True)
	run_checker = boolean(default=True)
	run_maint = boolean(default=True)
	run_builder = boolean(default=True)
	check_interval = integer(default=43200)
	fetch_interval = integer(default=1800)
	'''
spec = spec.split('\n')
config = configobj.ConfigObj(args.config_file, configspec=spec)
if 'include' in config:
	config_included = configobj.ConfigObj(config['include'])
	config.merge(config_included)

# django setup
DJANGO_SETTINGS_MODULE = 'settings'
if 'DJANGO_PROJECT_PATH' in config:
	DJANGO_PROJECT_PATH = config['DJANGO_PROJECT_PATH']
else:
	DJANGO_PROJECT_PATH = os.path.dirname(sys.argv[0]) + '/web'
sys.path.insert(1, DJANGO_PROJECT_PATH)
os.environ['DJANGO_SETTINGS_MODULE'] = DJANGO_SETTINGS_MODULE
from web.lib.utils import get_logger

# configure logger
if args.debug == True:
	log_level = 'debug'
	log_file = None
elif args.verbose == True:
	log_level = 'info'
	log_file = None
else:
	log_level = config['log_level']
	log_file = config['log_file']

if not args.debug and not args.verbose:
	# get pid object for daemon
	pid = daemon.pidlockfile.TimeoutPIDLockFile(config['pid_file'], 10)
	# create daemon context
	d = daemon.DaemonContext(pidfile=pid, umask=077)
	# write stderr to logfile # FIXME: and how we will deal with log rotation?
	logfile = open(config['log_file'], 'a')
	d.stderr = logfile
	d.stdout = logfile
	# drop privileges when started as root
	if os.getuid() == 0:
		runas = config['runas']
		pw_entry = pwd.getpwnam(runas)
		d.uid = pw_entry[2]
		d.gid = pw_entry[3]
	d.open() # become daemon
log = get_logger(filename=log_file, log_level=log_level)
main()