
__author__ = 'Miroslav Bauer'


import zmq
import time
import util
import pickle
import simplejson
from logger    import Logger
from objproxy  import RpcProxy
from zmqthread import RpcZmqThread
from resource  import ResourceAgent
from constants import RESOURCE_CONFIG, RES_STATE, HEARTBEAT_INTERVAL

log = Logger('dmorph.resman')


class ResourceManager(RpcZmqThread):
	''' This class is responsible for loading, starting or
	    stopping resources and periodically checking it's status.
	'''

	def __init__(self, context):
		super(ResourceManager, self).__init__(context, hasChildren=True)
		self.name       = 'resman'
		self._resources = {}
		self._resstates = {}
	
	def _loadResources(self):
		with open(RESOURCE_CONFIG) as res_json:
			resDict = simplejson.load(res_json)
		try:
			resDict = util.toResources(resDict, self._context)
			for name, res in resDict.items():
				resproxy = RpcProxy(self._context, ResourceAgent)
				self._resources[name] = resproxy
				self._resstates[name] = RES_STATE['online']
			
				res.parent = self.name
				self._threads[name] = res
							
		except TypeError, e:
			log.err('TypeError: %s' % e)
			self.terminate()

	def _startResourceAgents(self):
		for name, res in self._threads.items():
			self._threads[name].start()
		self._waitFor(self._threads.keys(), forChildren=True)
		
		for name, agent in self._resources.items():
			agent.connect('resource/%s' % name)
	
	def _stopResourceAgents(self):
		for name, agent in self._resources.items():
			agent.setStop()
			agent._terminate()
		for name, res in self._threads.items():
			res.join()
	
	def _checkResources(self):
		self._lastHbCheck = time.time()
		for name, agent in self._resources.items():
			res = agent.getState()
			self._resstates[name] = res
			if not res == RES_STATE['online']:
				log.warn('%s is %s!' % (name, util.stateToStr(res, RES_STATE)))
				
	def run(self):
		self._connect()
		self._bind('resman')
		self._loadResources()
		self._startResourceAgents()
		self._checkResources()
		self._signalReady()

		log.info('Resource manager started!')

		while not self.stop.is_set():
			try:
				if (self._lastHbCheck + HEARTBEAT_INTERVAL) < time.time():
					self._checkResources()
				self._handleMethodInvocation()
			except RuntimeError, e:
				log.err('RuntimeError: %s' % e)
				continue
			except TypeError, e:
				raise
				log.err('TypeError: %s' % e)
				continue

		self.stopResourceAgents()
		self._cleanup()

	def getResources(self):
		''' Returns list of names of all loaded resources '''
		return self._resources.keys()
	
	def getOnlineResources(self):
		''' Returns names of all available resources in online status'''
		return [ r for r in self._resources.keys() if self._resstates[r] == RES_STATE['online']]
	
	def reloadResources(self):
		''' Stop current resources and load new ones from config file '''
		log.info('Reloading resources from: %s' % RESOURCE_CONFIG)
		self._stopResourceAgents()
		self._resources.clear()
		self._resstates.clear()
		self._loadResources()
		self._startResourceAgents()
