#!/usr/bin/env python
# -*- coding: utf-8 -*-

import platform

system = platform.system()
working_directory = r"C:\circle"

from os import environ
from os.path import join

import logging
import tarfile
from StringIO import StringIO
from base64 import decodestring
from hashlib import md5
from datetime import datetime
import win32api
import wmi
import netifaces

from twisted.internet import reactor

from .network import change_ip_windows
from context import BaseContext


logging.basicConfig()
logger = logging.getLogger()
level = environ.get('LOGLEVEL', 'INFO')
logger.setLevel(level)


class Context(BaseContext):

    @staticmethod
    def change_password(password):
        from win32com import adsi
        ads_obj = adsi.ADsGetObject('WinNT://localhost/%s,user' % 'cloud')
        ads_obj.Getinfo()
        ads_obj.SetPassword(password)

    @staticmethod
    def restart_networking():
        pass

    @staticmethod
    def change_ip(interfaces, dns):
        change_ip_windows(interfaces, dns)

    @staticmethod
    def set_time(time):
        t = datetime.utcfromtimestamp(float(time))
        win32api.SetSystemTime(t.year, t.month, 0, t.day, t.hour,
                               t.minute, t.second, 0)

    @staticmethod
    def set_hostname(hostname):
        wmi.WMI().Win32_ComputerSystem()[0].Rename(hostname)

    @staticmethod
    def mount_store(host, username, password):
        import notify
        url = 'cifs://%s:%s@%s/%s' % (username, password, host, username)
        for c in notify.clients:
            logger.debug("sending url %s to client %s", url, unicode(c))
            c.sendLine(url.encode())

    @staticmethod
    def get_keys():
        pass

    @staticmethod
    def add_keys(keys):
        pass

    @staticmethod
    def del_keys(keys):
        pass

    @staticmethod
    def cleanup():
        # TODO
        pass

    @staticmethod
    def start_access_server():
        # TODO
        pass

    @staticmethod
    def append(data, filename, chunk_number, uuid):
        if chunk_number == 0:
            flag = "w"
        else:
            flag = "a"
        with open(filename, flag) as myfile:
            myfile.write(data)

    @staticmethod
    def _update_registry(dir, executable):
        # HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\circle-agent
        from _winreg import (OpenKeyEx, SetValueEx, QueryValueEx,
                             HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS)
        with OpenKeyEx(HKEY_LOCAL_MACHINE,
                       r'SYSTEM\CurrentControlSet\services\circle-agent',
                       0,
                       KEY_ALL_ACCESS) as key:
            (old_executable, reg_type) = QueryValueEx(key, "ImagePath")
            SetValueEx(key, "ImagePath", None, 2, join(dir, executable))
        return old_executable

    @staticmethod
    def update(filename, executable, checksum, uuid):
        with open(filename, "r") as f:
            data = f.read()
            local_checksum = md5(data).hexdigest()
            if local_checksum != checksum:
                raise Exception("Checksum missmatch the file is damaged.")
            decoded = StringIO(decodestring(data))
        try:
            tar = tarfile.TarFile.open("dummy", fileobj=decoded, mode='r|gz')
            tar.extractall(working_directory)
        except tarfile.ReadError as e:
            logger.error(e)
        logger.info("Transfer completed!")
        Context._update_registry(working_directory, executable)
        logger.info('Updated')
        reactor.stop()

    @staticmethod
    def ipaddresses():
        args = {}
        interfaces = netifaces.interfaces()
        for i in interfaces:
            if i == 'lo':
                continue
            args[i] = []
            addresses = netifaces.ifaddresses(i)
            args[i] = ([x['addr']
                        for x in addresses.get(netifaces.AF_INET, [])] +
                       [x['addr']
                        for x in addresses.get(netifaces.AF_INET6, [])
                        if '%' not in x['addr']])
        return args

    @staticmethod
    def get_agent_version():
        try:
            with open(join(working_directory, 'version.txt')) as f:
                return f.readline()
        except IOError:
            return None