"""


"""

import time
import logging
import os
from configobj import ConfigObj
from validate import Validator

from .exceptions import HeatmiserControllerSetupInitError

"""class HeatmiserControllerSetup

User interface to setup the contoller.

The settings attribute stores the settings of the hub. It is a
dictionary with the following keys:

        'controller': a dictionary containing general settings
        'serial': a dictionary containing the serial port settings
        'devices': a dictionary containing the configuration of each remote device
        'setup': 

        The controller settings are:
        'loglevel': the logging level
        
        ###interfacers and reporters are dictionaries with the following keys:
        ###'Type': class name
        ###'init_settings': dictionary with initialization settings
        ###'runtimesettings': dictionary with runtime settings
        ###Initialization and runtime settings depend on the interfacer and
        ###reporter type.

The run() method is supposed to be run regularly by the instantiator, to
perform regular communication tasks.

The check_settings() method is run regularly as well. It checks the settings 
and returns True is settings were changed.

This almost empty class is meant to be inherited by subclasses specific to
each setup.

"""

class HeatmiserControllerSetup(object):

    def __init__(self):
        
        # Initialize logger
        self._log = logging.getLogger("HeatmiserController")
        
        # Initialize settings
        self.settings = None

    def run(self):
        """Run in background. 
        
        To be implemented in child class.

        """
        pass

    def check_settings(self):
        """Check settings
        
        Update attribute settings and return True if modified.
        
        To be implemented in child class.
        
        """

class HeatmiserControllerFileSetup(HeatmiserControllerSetup):

    def __init__(self, filename):
        
        # Initialization
        super(HeatmiserControllerFileSetup, self).__init__()

        self._module_path = os.path.abspath(os.path.dirname(__file__))
        specpath = os.path.join(self._module_path, "hmcontroller.spec")
        
        # List of expected sections
        self._sections = ['controller', 'serial', 'devices', 'setup']
            
        # Initialize attribute settings as a ConfigObj instance
        logging.debug("Loading %s and checking against %s"%(filename, specpath))
        try:
            self.settings = ConfigObj(filename, file_error=True, configspec=specpath)
            self._validator = Validator()
        except IOError as e:
            raise HeatmiserControllerSetupInitError(e)
        except SyntaxError as e:
            raise HeatmiserControllerSetupInitError(
                'Error parsing config file \"%s\": ' % filename + str(e))
        except KeyError as e:
            raise HeatmiserControllerSetupInitError(
                'Configuration file error - section missing: ' + str(e))
        
        #check settings and add any default values
        self._check_settings()
        
        # Initialize update timestamps
        self._settings_update_timestamp = 0
        
        # Load use configured variables
        for name, value in self.settings['setup'].iteritems():
            setattr(self, '_c_'+name, value)

        # create a timeout message if time out is set (>0)
        self.retry_msg = " Retry in " + str(self._c_retry_time_interval) + " seconds" if self._c_retry_time_interval <= 0 else ""

    def reload_settings(self):
        """Reload and check settings

        Update attribute settings and return True if modified. Return False if failed to load new settings. Return None if nothing new or not checked

        """
        
        # Check settings only once per second
        now = time.time()
        if now - self._settings_update_timestamp < 0:
            return
        # Update timestamp
        self._settings_update_timestamp = now + self._c_check_time_interval
        
        # Backup settings
        settings = dict(self.settings)
        
        # Get settings from file
        try:
            self.settings.reload()
        except IOError as e:
            self._log.warning('Could not get settings: ' + str(e) + self.retry_msg)
            self._settings_update_timestamp = now + self._c_retry_time_interval
            return
        except SyntaxError as e:
            self._log.warning('Could not get settings: ' + 
                              'Error parsing config file: ' + str(e) + self.retry_msg)
            self._settings_update_timestamp = now + self._c_retry_time_interval
            return
        except Exception:
            import traceback
            self._log.warning("Couldn't get settings, Exception: " +
                              traceback.format_exc() + self.retry_msg)
            self._settings_update_timestamp = now + self._c_retry_time_interval
            return

        if self.settings != settings:
            try:
                self._check_settings()
            except (ValueError, KeyError):
                self.settings = settings
                return False
            return True
            
    def _check_settings(self):
        try:
            # Validate the configuration file and copy any missing defaults
            returnval = self.settings.validate(self._validator, preserve_errors=True, copy=True)
            if not returnval is True:
                raise ValueError("failed validation of config file %s"%str(returnval))

            # Check the settings file sections exist
            for name in self._sections:
                self.settings[name]
        except (ValueError, KeyError) as e:
            logging.warning("Configuration parse failed : " + str(e))
            raise


            



