#!/usr/bin/env python

__author__ = 'Miroslav Bauer'


import os
import sys
import zmq
import atexit
import logging
from daemon              import runner
from datamorph.logger    import Logger
from datamorph.resman    import ResourceManager
from datamorph.rhandler  import RequestHandler
from datamorph.scheduler import Scheduler
from datamorph.constants import LOG_FILE, ERRORLOG_FILE, SAGA_LOG_LEVEL

l = Logger('dmorph')

class App():

	def __init__(self):
		atexit.register(self.terminate)

		self.stdin_path      = '/dev/null'
		self.stdout_path     = LOG_FILE
		self.stderr_path     = ERRORLOG_FILE
		self.pidfile_path    = '/var/run/datamorph.pid'
		self.pidfile_timeout = 5
		dirpaths = [os.path.dirname(x) for x in [self.stdout_path, self.stderr_path]]
		for dirpath in dirpaths:
			if not os.path.exists(dirpath) or not os.path.isdir(dirpath):
				os.makedirs(dirpath)

		self._context              = zmq.Context()
		self._threads              = {}
		self._threads['resman']    = ResourceManager(self._context)
		self._threads['scheduler'] = Scheduler(self._context)
		self._threads['rhandler']  = RequestHandler(self._context)

	def run(self):
		''' Main daemon thread '''
		notifications_in = self._context.socket(zmq.SUB)
		notifications_out = self._context.socket(zmq.PUB)
		notifications_in.setsockopt(zmq.SUBSCRIBE, '')
		notifications_in.bind('inproc:///notifications_in')
		notifications_out.bind('inproc:///notifications_out')

		self._threads['resman'].start()
		self._threads['scheduler'].start()
		self._threads['rhandler'].start()

		zmq.device(zmq.FORWARDER, notifications_in, notifications_out)

		[thr.join() for tname, thr in self._threads.items()]

	def terminate(self):
		''' Terminates all application threads and then exits '''
		l.info('datamorph terminating')
		[thr.terminate() for tname, thr in self._threads.items()]
		sys.exit(0)


daemon = App()

os.environ['SAGA_VERBOSE'] = str(SAGA_LOG_LEVEL)

# Set up daemon logging
lform = logging.Formatter("%(asctime)s:[%(levelname)s] %(message)s")
fhandle = logging.FileHandler(LOG_FILE)
fhandle.setFormatter(lform)
l.addHandler(fhandle)

# Daemonize datamorph app
daemon_runner = runner.DaemonRunner(daemon)
daemon_runner.daemon_context.files_preserve=[fhandle.stream]
daemon_runner.do_action()
