# -*- coding: utf-8 -*-

import logging
from threading import Timer, Lock, Event
from time import sleep
from sjrpc.client import SimpleRpcClient
from sjrpc.utils import ConnectionProxy
from sjrpc.core import RpcError
import handlers

class CCNode(object):
    '''
    Handle node initialization, connection to server, and authentication
    '''
    def __init__(self, server, port, hypervisor, exec_cmd, force_xen=False,
                                                                    cert=None):
        '''
        '''
        self._scheduler_timer = None
        self._scheduler_mutex = Lock()
        self._scheduler_stopped = Event()
        self._is_hv = hypervisor # hugly
        self._is_xen = force_xen # hugly
        self._exec_cmd = exec_cmd # hugly
        self._handler = None
        self._manager = SimpleRpcClient.from_addr(server, port, enable_ssl=True,
                                                default_handler=self._handler)
        self._server = ConnectionProxy(self._manager)
    
    def run(self):
        '''
        '''
        try:
            self._manager.run()
        except:
            raise
        finally:
            self._scheduler_stopped.set()
    
    def authentify(self, login, password):
        '''
        '''
        logging.debug('Authenticating user `%s` on connection `%i`' % (login,
                                                        id(self._server)))
        try:
            role = self._server.authentify(login, password)
        except RpcError as err:
            if err.exception == 'AuthenticationError':
                logging.warning('Authentication error')
            else:
                logging.warning('Unknown error while authenticating: %s' % err)
            return False
        except Exception as err:
            logging.debug('Unhandled exception: `%s`' % err)
        else:
            if role == 'hv':
                self._handler = handlers.NodeHandler(self,
                                                     self._is_hv,
                                                     self._exec_cmd,
                                                     self._is_xen)
            elif role == 'host':
                self._handler = handlers.NodeHandler(self,
                                                     False,
                                                     self._exec_cmd,
                                                     self._is_xen)
            else:
                logging.warning('Bad role affected by server: %s' % role)
                raise Exception()
            
            self._manager.all_connections().pop().set_handler(self._handler)
            self._scheduler_rearm()
            return True
    
    def _scheduler_rearm(self):
        '''
        '''
        self._scheduler_timer = Timer(5, self._scheduler_run)
        self._scheduler_timer.start()
    
    def _scheduler_run(self):
        '''
        '''
        with self._scheduler_mutex:
            if not self._scheduler_stopped.is_set():
                self._handler.scheduler_run()
                sleep(0.1)
                self._scheduler_rearm()
    
    def get_server(self):
        '''
        '''
        return self._server
    
    def get_manager(self):
        '''
        '''
        return self._manager
    
    def get_handler(self):
        '''
        '''
        return self._handler