# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# libcloud.org licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Slicehost Driver
"""
from libcloud.types import NodeState, Provider
from libcloud.base import ConnectionKey, Response, NodeDriver, Node
from libcloud.base import NodeSize, NodeImage, NodeLocation
import base64
import struct
import socket
from xml.etree import ElementTree as ET
from xml.parsers.expat import ExpatError

class SlicehostResponse(Response):

    def parse_body(self):
        if not self.body:
            return None
        return ET.XML(self.body)

    def parse_error(self):
        try:
            object = ET.XML(self.body)
            return "; ".join([ err.text
                               for err in
                               object.findall('error') ])
        except ExpatError:
            return self.body
    

class SlicehostConnection(ConnectionKey):

    host = 'api.slicehost.com'
    responseCls = SlicehostResponse

    def add_default_headers(self, headers):
        headers['Authorization'] = ('Basic %s'
                              % (base64.b64encode('%s:' % self.key)))
        return headers
    

class SlicehostNodeDriver(NodeDriver):

    connectionCls = SlicehostConnection

    type = Provider.SLICEHOST
    name = 'Slicehost'

    NODE_STATE_MAP = { 'active': NodeState.RUNNING,
                       'build': NodeState.PENDING,
                       'reboot': NodeState.REBOOTING,
                       'hard_reboot': NodeState.REBOOTING,
                       'terminated': NodeState.TERMINATED }

    def list_nodes(self):
        return self._to_nodes(self.connection.request('/slices.xml').object)

    def list_sizes(self, location=None):
        return self._to_sizes(self.connection.request('/flavors.xml').object)

    def list_images(self, location=None):
        return self._to_images(self.connection.request('/images.xml').object)

    def list_locations(self):
        return [
            NodeLocation(0, 'Slicehost St. Louis (STL-A)', 'US', self),
            NodeLocation(0, 'Slicehost St. Louis (STL-B)', 'US', self),
            NodeLocation(0, 'Slicehost Dallas-Fort Worth (DFW-1)', 'US', self)
        ]

    def create_node(self, **kwargs):
        name = kwargs['name']
        image = kwargs['image']
        size = kwargs['size']
        uri = '/slices.xml'

        # create a slice obj
        root = ET.Element('slice')
        el_name = ET.SubElement(root, 'name')
        el_name.text = name
        flavor_id = ET.SubElement(root, 'flavor-id')
        flavor_id.text = str(size.id)
        image_id = ET.SubElement(root, 'image-id')
        image_id.text = str(image.id)
        xml = ET.tostring(root)

        node = self._to_nodes(
            self.connection.request(
                uri,
                method='POST',
                data=xml,
                headers={'Content-Type': 'application/xml'}
            ).object
        )[0]
        return node

    def reboot_node(self, node):
        """Reboot the node by passing in the node object"""

        # 'hard' could bubble up as kwarg depending on how reboot_node 
        # turns out. Defaulting to soft reboot.
        #hard = False
        #reboot = self.api.hard_reboot if hard else self.api.reboot
        #expected_status = 'hard_reboot' if hard else 'reboot'

        uri = '/slices/%s/reboot.xml' % (node.id)
        node = self._to_nodes(
            self.connection.request(uri, method='PUT').object
        )[0]
        return node.state == NodeState.REBOOTING

    def destroy_node(self, node):
        """Destroys the node

        Requires 'Allow Slices to be deleted or rebuilt from the API' to be
        ticked at https://manage.slicehost.com/api, otherwise returns::
            <errors>
              <error>You must enable slice deletes in the SliceManager</error>
              <error>Permission denied</error>
            </errors>
        """
        uri = '/slices/%s/destroy.xml' % (node.id)
        ret = self.connection.request(uri, method='PUT')
        return True

    def _to_nodes(self, object):
        if object.tag == 'slice':
            return [ self._to_node(object) ]
        node_elements = object.findall('slice')
        return [ self._to_node(el) for el in node_elements ]

    def _to_node(self, element):

        attrs = [ 'name', 'image-id', 'progress', 'id', 'bw-out', 'bw-in', 
                  'flavor-id', 'status', 'ip-address' ]

        node_attrs = {}
        for attr in attrs:
            node_attrs[attr] = element.findtext(attr)

        # slicehost does not determine between public and private, so we 
        # have to figure it out
        public_ip = element.findtext('ip-address')
        private_ip = None
        for addr in element.findall('addresses/address'):
            ip = addr.text
            try:
                socket.inet_aton(ip)
            except socket.error:
                # not a valid ip
                continue
            if self._is_private_subnet(ip):
                private_ip = ip
            else:
                public_ip = ip
                
        try:
            state = self.NODE_STATE_MAP[element.findtext('status')]
        except:
            state = NodeState.UNKNOWN

        n = Node(id=element.findtext('id'),
                 name=element.findtext('name'),
                 state=state,
                 public_ip=[public_ip],
                 private_ip=[private_ip],
                 driver=self.connection.driver)
        return n

    def _to_sizes(self, object):
        if object.tag == 'flavor':
            return [ self._to_size(object) ]
        elements = object.findall('flavor')
        return [ self._to_size(el) for el in elements ]

    def _to_size(self, element):
        s = NodeSize(id=int(element.findtext('id')),
                     name=str(element.findtext('name')),
                     ram=int(element.findtext('ram')),
                     disk=None, # XXX: needs hardcode
                     bandwidth=None, # XXX: needs hardcode
                     price=float(element.findtext('price'))/(100*24*30),
                     driver=self.connection.driver)
        return s

    def _to_images(self, object):
        if object.tag == 'image':
            return [ self._to_image(object) ]
        elements = object.findall('image')
        return [ self._to_image(el) for el in elements ]

    def _to_image(self, element):
        i = NodeImage(id=int(element.findtext('id')),
                     name=str(element.findtext('name')),
                     driver=self.connection.driver)
        return i


    def _is_private_subnet(self, ip):
        priv_subnets = [ {'subnet': '10.0.0.0', 'mask': '255.0.0.0'},
                         {'subnet': '172.16.0.0', 'mask': '172.16.0.0'},
                         {'subnet': '192.168.0.0', 'mask': '192.168.0.0'} ]

        ip = struct.unpack('I',socket.inet_aton(ip))[0]

        for network in priv_subnets:
            subnet = struct.unpack('I',socket.inet_aton(network['subnet']))[0]
            mask = struct.unpack('I',socket.inet_aton(network['mask']))[0]

            if (ip & mask) == (subnet & mask):
                return True
            
        return False
