# -*- coding: utf-8 -*-
import ConfigParser
from os import path, access, W_OK, environ
from twisted.python import log
import logging, sys, os
from airi import report

DEFAULTS={
    "dongles": {
        "default": True,
    },
    "pin": {
        "default": 1234,
    }
}

def resolvehome():
    paths = [ path.expanduser("~") ]
    for i in ["HOME", "HOMEPATH", "DATA_PATH"]:
        if i in os.environ:
            print "Has", i
            paths.append(os.environ[i])
    for i in paths:
        if access(i, W_OK):
            return i

class Settings():
    instance = None

    def __init__(self, name=None):
        if not name:
            parent = resolvehome()
            if not parent:
                if access(path.dirname(path.realpath(__file__)), W_OK):
                    print "Using path.realpath"
                    parent = path.dirname(path.realpath(__file__))
                else:
                    raise RuntimeException("Can't find suitable path to store settings")
            if not sys.platform.startswith("win"):
                name=path.join(parent, ".AIRi")
            else:
                name=path.join(parent, "AIRi.cfg")
        print "configuration file", name
        self.name = name
        self.reload()


    def reload(self):
        self.config = ConfigParser.SafeConfigParser()
        for section in DEFAULTS:
            if self._has_section(section):
                continue;

            self._add_section(section)
            for key, value in DEFAULTS[section].iteritems():
                self._set(section, key, str(value))

        if path.exists(self.name) and path.isfile(self.name):
            self._read(self.name)

    # @report()
    def getDongle(self, address):
        self.reload()
        address = address.replace(":", "_")
        dongles = self._options("dongles")
        for op in dongles:
            if address.lower().startswith(op):
                return self._getboolean("dongles", op)
        return self._getboolean("dongles", "default")

    # @report()
    def getCameraSections(self):
        self.reload()
        cameras = self._sections()
        if "dongles" in cameras:
            cameras.remove("dongles")
        if "pin" in cameras:
            cameras.remove("pin")
        return cameras

    # @report()
    def getCameraSection(self, address, create=False):
        self.reload()
        cameras = self.getCameraSections()
        for cam in cameras:
            if address.lower().startswith(self._get(cam, "address").lower()):
                return cam
        if create:
            cameras=self._sections()
            if "dongles" in cameras:
                cameras.remove("dongles")
            section="camera%i"%(len(cameras)+1)
            self._add_section(section)
            self._set(section, "address", address)
            return section
        return None

    #@report(level=20)
    def __cameraDict(self, items):
        # defaults
        out = {
            "reconnect_timeout": 10,
            "reconnect": False,
            "voice": False,
            "flash": False,
            "exposure": 0,
            "pan": "none"
        }
        for key, val in items:
            if key in ['reconnect_timeout', 'exposure']:
                out[key] = int(val)
            elif key in ['reconnect', 'enable', 'voice', 'flash', "enable_pincode"]:
                out[key] = val.lower() == "true"
            else:
                out[key] = val
        try:
            out["pincode"] = self.getPIN(out["address"], perfect=True, silent=False)
            out["enable_pincode"] = True
        except Exception, err:
            out["enable_pincode"] = False
        if "type" not in out:
            return None
        return out

    #@report(debug=True)
    def getCameras(self):
        self.reload()
        for camera in self.getCameraSections():
            c = self.__cameraDict(self._items(camera))
            if c: yield c

    def deleteCamera(self, address):
        self.reload()
        cam = self.getCameraSection(address)
        if not cam:
            return
        self._remove_section(cam)

    #@report(debug=True)
    def getCamera(self, address):
        self.reload()
        cam = self.getCameraSection(address)
        if cam:
            return self.__cameraDict(self._items(cam))
        return None

    #@report(debug=True)
    def save(self):
        self._write(open(self.name, "wb"))

    #@report(level=30)
    def __sanitizeSetting(self, key, val):
        if key in ['reconnect_timeout', 'exposure']:
            val = int(val)
        elif key in ['reconnect', 'enable', 'voice', 'flash', "enable_pincode"]:
            if type(val) != bool:
                val = val.lower() in ["true", "ok"]
        return str(val)

    #@report(level=20)
    def setCameraSetting(self, address, key, value, section=None):
        if not section:
            section = self.getCameraSection(address, True)
        if not value:
            self._remove_option(section, key)
        else:
            self._set(section, key, self.__sanitizeSetting(key, value))

    #@report(level=20)
    def setCamera(self, configuration):
        if "address" not in configuration:
            raise Exception("You need to set address")

        section = self.getCameraSection(configuration["address"], True)

        for key, value in configuration.iteritems():
            self.setCameraSetting(configuration["address"], key, value, section=section)
        self.save()
        from airi.api import UpdateManager
        UpdateManager.propagate(configuration["address"], configuration)

    # @report(debug=True)
    def setDongle(self, block, enable=False):
        self._set("dongles", block.replace(":", "_"), str(enable))

    # @report(debug=True)
    def setPIN(self, npin, block="default"):
        self._set("pin", block.replace(":", "_"), str(npin))
        from airi.api import UpdateManager
        UpdateManager.propagate(block.replace(":", "_"), {"pin": npin})

    # @report(debug=True)
    def delPIN(self, block):
        self._remove_option("pin", block.replace(":", "_"))
        from airi.api import UpdateManager
        UpdateManager.propagate(block.replace(":", "_"), {"pin": None})

    # @report(debug=True)
    def getPINs(self):
        self.reload()
        if not self.config.has_section("pin"):
            pins = {"default": default}
        else:
            pins = dict((b[0].replace("_", ":"), b[1]) for b in self.config.items("pin"))
        return pins

    # @report(debug=True)
    def getPIN(self, address=None, perfect=False, default="1234", silent=True):
        self.reload()
        if not self.config.has_section("pin"):
            pins = {"default": default}
        else:
            pins = dict((b[0].lower(), b[1]) for b in self.config.items("pin"))
        if not address:
            log.msg("No address falling back to default", level=logging.DEBUG)
            return pins.get("default", default)
        address=address.replace(":", "_").lower()

        for block in pins:
            if not perfect:
                if address.startswith(block):
                    return pins[block]
            else:
                if address == block:
                    return pins[block]
        if not silent:
            raise Exception("PIN not provided")
        return pins.get("default", default)

    def __getattr__(self, name):
        return getattr(self.config, name[1:])

def getSettings(name=None):
    if Settings.instance:
        return Settings.instance
    Settings.instance = Settings(name)
    return Settings.instance

if __name__=='__main__':
    import logging
    logging.basicConfig(level=logging.DEBUG)
    logging.info("starting demo")
    s=Settings()
    logging.info(s.getDongle("00:25:BF:11:22:33"))
    s.setDongle("00:25:BF", "false")
    logging.info(s.getDongle("00:25:BF:11:22:33"))
    logging.info(s.getCamera("00:25:BF:11:22:33"))
    logging.info(s.getCamera("00:25:BF:00:25:BF"))
    s.setCamera({"address": "00:25:BF:00:25:AA", "reconnect": True})
    s.save()

