#!/usr/bin/python

import simplejson as json
import ordereddict

import urllib2
import httplib
import ssl
from cStringIO import StringIO
from xml.etree import ElementTree as ET
import aps2.uLogging

# compatibility with python 2.7.9+
# see https://www.python.org/dev/peps/pep-0476/
_PYTHON_2_7_9_COMPAT = False
if '_create_unverified_context' in dir(ssl):
    _PYTHON_2_7_9_COMPAT = True


class HTTPSClientAuthHandler(urllib2.HTTPSHandler):
    def __init__(self, key, cert):

        if _PYTHON_2_7_9_COMPAT:
            context = ssl._create_unverified_context()
            urllib2.HTTPSHandler.__init__(self, context=context)
        else:
            urllib2.HTTPSHandler.__init__(self)

        self.key = key
        self.cert = cert

    def https_open(self, req):
        # Rather than pass in a reference to a connection class, we pass in
        # a reference to a function which, for all intents and purposes,
        # will behave as a constructor
        if _PYTHON_2_7_9_COMPAT:
            return self.do_open(self.getConnection, req, context=self._context)
        return self.do_open(self.getConnection, req)

    def getConnection(self, host, context=None, timeout=300):
        if context != None:
            return httplib.HTTPSConnection(host, key_file=self.key, cert_file=self.cert, context=context)
        return httplib.HTTPSConnection(host, key_file=self.key, cert_file=self.cert)


class API:
    verbose = False

    class APSExcStruct:
        def __init__(self):
            self.code = 0
            self.type = ''
            self.message = ''

    def __init__(self, url):
        """
        Takes something like the following argument as input:
        url = 'https://a.bvt.aps.sw.ru:6308'
        """
        self.url = url

    def call(self, verb, path, headers=None, data=None, cert=None, rheaders=None, is_json=True):

        data = json.dumps(data)

        url = self.url + path
        aps2.uLogging.trace('%s %s ...' % (verb, url))
        if headers:
            aps2.uLogging.trace('Request headers:\n\t%s' % "\t".join(["%s: %s" % (h, headers[h]) for h in headers.keys()]))

        if data and self.verbose:
            print "Request:\n%r" % data

        if not headers:
            headers = dict()
            aps2.uLogging.trace("not headers")

        req = urllib2.Request(url, headers=headers, data=data)
        req.get_method = lambda: verb

        resp = None
        try:
            if cert:
                opener = urllib2.build_opener(HTTPSClientAuthHandler(cert, cert))
                resp = opener.open(req)
            else:
                if _PYTHON_2_7_9_COMPAT:
                    context = ssl._create_unverified_context()
                    resp = urllib2.urlopen(req, context=context)
                else:
                    resp = urllib2.urlopen(req)

        except urllib2.HTTPError, error:
            contents = error.read()
            aps2.uLogging.error('API Error:')
            aps2.uLogging.error(contents)

            # APS Exceptions have the following structure (example):
            # {
            #    "code": 500,
            #    "type": "APS::Hosting::Exception",
            #    "message": "Limit for resource ..."
            # }
            # In order to allow simple processing of this exception like
            # ('something' in error.aps.message) we convert this exception
            # to JSON directly here.
            error.aps = API.APSExcStruct()
            if len(contents):
                error.aps = json.loads(contents, object_pairs_hook=ordereddict.OrderedDict)
            raise error

        try:
            # getcode() available since Python 2.6
            aps2.uLogging.trace('Status: %s' % resp.getcode())
        except AttributeError:
            # without code check resp.read() can return empty string
            aps2.uLogging.trace('Status: %s' % resp.code)

        if resp.headers:
            aps2.uLogging.trace('Response headers:\n\t%s' % "\t".join(resp.headers.headers))

            if rheaders != None:
                for h in resp.headers.headers:
                    (k, v) = h.split(':', 1)
                    rheaders[k] = v.strip()

        content = resp.read()

        # Converting JSON immediately if presented
        
        if len(content):
            if is_json:
                content = json.loads(content, object_pairs_hook=ordereddict.OrderedDict)
                if self.verbose:
                    aps2.uLogging.trace("Response:\n%r" % content)
            else:
                content = ET.parse(StringIO(content))
        return content

    def GET(self, path, headers=None, data=None, cert=None, is_json=True):
        return self.call('GET', path, headers, data, cert, None, is_json)

    def PUT(self, path, headers=None, data=None, cert=None):
        return self.call('PUT', path, headers, data, cert)

    def POST(self, path, headers=None, data=None, cert=None):
        return self.call('POST', path, headers, data, cert)

    def DELETE(self, path, headers=None, data=None, cert=None):
        return self.call('DELETE', path, headers, data, cert)

#
# Usage Example:
#   import apsapi
#   aapi = apsapi.API(url = 'https://a.bvt.aps.sw.ru:6308')
#   resp = aapi.GET( '/aps/2/resources/' + safilter, self.getProviderToken() )
#

3294db0b60e4d6e207548ef23b75118267726a02
#!/usr/bin/python

import simplejson as json
import ordereddict

import urllib2
import httplib
import ssl
from cStringIO import StringIO
from xml.etree import ElementTree as ET
import aps2.uLogging

# compatibility with python 2.7.9+
# see https://www.python.org/dev/peps/pep-0476/
_PYTHON_2_7_9_COMPAT = False
if '_create_unverified_context' in dir(ssl):
    _PYTHON_2_7_9_COMPAT = True


class HTTPSClientAuthHandler(urllib2.HTTPSHandler):
    def __init__(self, key, cert):

        if _PYTHON_2_7_9_COMPAT:
            context = ssl._create_unverified_context()
            urllib2.HTTPSHandler.__init__(self, context=context)
        else:
            urllib2.HTTPSHandler.__init__(self)

        self.key = key
        self.cert = cert

    def https_open(self, req):
        # Rather than pass in a reference to a connection class, we pass in
        # a reference to a function which, for all intents and purposes,
        # will behave as a constructor
        if _PYTHON_2_7_9_COMPAT:
            return self.do_open(self.getConnection, req, context=self._context)
        return self.do_open(self.getConnection, req)

    def getConnection(self, host, context=None, timeout=300):
        if context != None:
            return httplib.HTTPSConnection(host, key_file=self.key, cert_file=self.cert, context=context)
        return httplib.HTTPSConnection(host, key_file=self.key, cert_file=self.cert)


class API:
    verbose = False

    class APSExcStruct:
        def __init__(self):
            self.code = 0
            self.type = ''
            self.message = ''

    def __init__(self, url):
        """
        Takes something like the following argument as input:
        url = 'https://a.bvt.aps.sw.ru:6308'
        """
        self.url = url

    def call(self, verb, path, headers=None, data=None, cert=None, rheaders=None, is_json=True):

        data = json.dumps(data)

        url = self.url + path
        aps2.uLogging.trace('%s %s ...' % (verb, url))
        if headers:
            aps2.uLogging.trace('Request headers:\n\t%s' % "\t".join(["%s: %s" % (h, headers[h]) for h in headers.keys()]))

        if data and self.verbose:
            print "Request:\n%r" % data

        if not headers:
            headers = dict()
            aps2.uLogging.trace("not headers")

        req = urllib2.Request(url, headers=headers, data=data)
        req.get_method = lambda: verb

        resp = None
        try:
            if cert:
                opener = urllib2.build_opener(HTTPSClientAuthHandler(cert, cert))
                resp = opener.open(req)
            else:
                if _PYTHON_2_7_9_COMPAT:
                    context = ssl._create_unverified_context()
                    resp = urllib2.urlopen(req, context=context)
                else:
                    resp = urllib2.urlopen(req)

        except urllib2.HTTPError, error:
            contents = error.read()
            aps2.uLogging.error('API Error:')
            aps2.uLogging.error(contents)

            # APS Exceptions have the following structure (example):
            # {
            #    "code": 500,
            #    "type": "APS::Hosting::Exception",
            #    "message": "Limit for resource ..."
            # }
            # In order to allow simple processing of this exception like
            # ('something' in error.aps.message) we convert this exception
            # to JSON directly here.
            error.aps = API.APSExcStruct()
            if len(contents):
                error.aps = json.loads(contents, object_pairs_hook=ordereddict.OrderedDict)
            raise error

        try:
            # getcode() available since Python 2.6
            aps2.uLogging.trace('Status: %s' % resp.getcode())
        except AttributeError:
            # without code check resp.read() can return empty string
            aps2.uLogging.trace('Status: %s' % resp.code)

        if resp.headers:
            aps2.uLogging.trace('Response headers:\n\t%s' % "\t".join(resp.headers.headers))

            if rheaders != None:
                for h in resp.headers.headers:
                    (k, v) = h.split(':', 1)
                    rheaders[k] = v.strip()

        content = resp.read()

        # Converting JSON immediately if presented
        
        if len(content):
            if is_json:
                content = json.loads(content, object_pairs_hook=ordereddict.OrderedDict)
                if self.verbose:
                    aps2.uLogging.trace("Response:\n%r" % content)
            else:
                content = ET.parse(StringIO(content))
        return content

    def GET(self, path, headers=None, data=None, cert=None, is_json=True):
        return self.call('GET', path, headers, data, cert, None, is_json)

    def PUT(self, path, headers=None, data=None, cert=None):
        return self.call('PUT', path, headers, data, cert)

    def POST(self, path, headers=None, data=None, cert=None):
        return self.call('POST', path, headers, data, cert)

    def DELETE(self, path, headers=None, data=None, cert=None):
        return self.call('DELETE', path, headers, data, cert)

#
# Usage Example:
#   import apsapi
#   aapi = apsapi.API(url = 'https://a.bvt.aps.sw.ru:6308')
#   resp = aapi.GET( '/aps/2/resources/' + safilter, self.getProviderToken() )
#
