from tempfile import NamedTemporaryFile
from os import path
from urlparse import urlparse
from contextlib import closing

import binascii
import calendar
import logging
import os
import re
import subprocess
import time
import uuid
import json
import urllib2
import arrow


try:
    from eventlet.green.subprocess import check_output as e_check_output
    from eventlet.green.subprocess import Popen as e_popen
except:
    pass

from subprocess import PIPE, Popen, CalledProcessError

log = logging.getLogger('cattle')

_TEMP_NAME = 'work'
_TEMP_PREFIX = 'cattle-temp-'


def _to_json_object(v):
    if isinstance(v, dict):
        return JsonObject(v)
    elif isinstance(v, list):
        ret = []
        for i in v:
            ret.append(_to_json_object(i))
        return ret
    else:
        return v


class JsonObject:
    def __init__(self, data):
        for k, v in data.items():
            self.__dict__[k] = _to_json_object(v)

    def __getitem__(self, item):
        value = self.__dict__[item]
        if isinstance(value, JsonObject):
            return value.__dict__
        return value

    def __getattr__(self, name):
        return getattr(self.__dict__, name)

    @staticmethod
    def unwrap(json_object):
        if isinstance(json_object, list):
            ret = []
            for i in json_object:
                ret.append(JsonObject.unwrap(i))
            return ret

        if isinstance(json_object, dict):
            ret = {}
            for k, v in json_object.items():
                ret[k] = JsonObject.unwrap(v)
            return ret

        if isinstance(json_object, JsonObject):
            ret = {}
            for k, v in json_object.__dict__.items():
                ret[k] = JsonObject.unwrap(v)
            return ret

        return json_object


class CadvisorAPIClient(object):
    def __init__(self, host, port, version='v1.2', proto='http://'):
        self.url = '{0}{1}:{2}/api/{3}'.format(proto, host, str(port), version)

    def get_containers(self):
        return self._get(self.url + '/containers')

    def get_latest_stat(self):
        containers = self.get_stats()
        if len(containers) > 1:
            return containers[-1]
        return {}

    def get_stats(self):
        containers = self.get_containers()
        if containers:
            return containers['stats']
        return []

    def timestamp_diff(self, time_current, time_prev):
        time_current_conv = self._timestamp_convert(time_current)
        time_prev_conv = self._timestamp_convert(time_prev)

        diff = (time_current_conv - time_prev_conv).total_seconds()
        return round((diff * 10**9))

    def _timestamp_convert(self, stime):
        # Cadvisor handles everything in nanoseconds.
        # Python does not.
        t_conv = arrow.get(stime[0:26])
        return t_conv

    def _marshall_to_python(self, data):
        if isinstance(data, str):
            return json.loads(data)

    def _get(self, url):
        try:
            with closing(urllib2.urlopen(url, timeout=5)) as resp:
                if resp.code == 200:
                    data = resp.read()
                    return self._marshall_to_python(data)
        except:
            log.exception(
                "Could not get stats from cAdvisor at: {0}".format(url))

        return None


def ping_include_resources(ping):
    try:
        return ping.data.options['resources']
    except (KeyError, AttributeError):
        return False


def ping_include_stats(ping):
    try:
        return ping.data.options['stats']
    except (KeyError, AttributeError):
        return False


def ping_include_instances(ping):
    try:
        return ping.data.options['instances']
    except (KeyError, AttributeError):
        return False


def ping_add_resources(pong, *args):
    if 'resources' not in pong.data:
        pong.data.resources = []

    for resource in args:
        pong.data.resources.append(resource)


def ping_set_option(pong, key, value):
    if 'options' not in pong.data:
        pong.data.options = {}

    pong.data.options[key] = value


def events_from_methods(obj):
    ret = []
    for method in dir(obj):
        if method.startswith('_do_'):
            ret.append(method[4:].replace('_', '.'))
    return ret


def reply(event, data=None, parent=None):
    if data is None: