from plstackapi.planetstack.config import Config
from plstackapi.openstack.shell import OpenStackShell

class OpenStackDriver:

    def __init__(self, config = None): 
        if config:
            self.config = Config(config)
        else:
            self.config = Config() 
        self.shell = OpenStackShell()

    def create_tenant(self, tenant_name, enabled, description):
        """Create keystone tenant. Suggested fields: name, description, enabled"""  
        tenants = self.shell.keystone.tenants.findall(name=tenant_name)
        if not tenants:
            fields = {'tenant_name': tenant_name, 'enabled': enabled, 
                      'description', description}  
            tenant = self.shell.keystone.tenants.create(**fields)
        else:
            tenant = tenants[0]
        return tenant

    def update_tenant(self, id, **kwds):
        return self.shell.keystone.tenants.update(id, **kwds)

    def delete_tenant(self, id):
        tenant = self.shell.keystone.tenants.find(id=id)
        return self.shell.keystone.tenants.delete(tenant)

    def create_user(self, name, email, password, enabled):
        users = self.shell.keystone.users.findall(email=email)
        if not users:
            fields = {'name': name, 'email': email, 'password': password,
                      'enabled': enabled}
            user = self.shell.keystone.create(**fields)
        else: 
            user = users[0]
        return user

    def add_user_role(self, user_id, tenant_id, role_name):
        user = self.shell.keystone.users.find(id=user_id)
        tenant = self.shell.keystone.tenants.find(id=tenant_id)
        role = self.shell.keystone.roles.find(role_name)
        return tenant.add_user(user, role)

    def delete_user_role(self, user_id, tenant_id, role_name):
        user = self.shell.keystone.users.find(id=user_id)
        tenant = self.shell.keystone.tenants.find(id=tenant_id)
        role = self.shell.keystone.roles.find(role_name)
        return tenant.delete_user(user, role)

    def update_user(self, id, **kwds):
        return self.shell.keystone.users.update(id, **kwds)

    def delete_user(self, id):
        user = self.shell.keystone.users.find(id=id)
        return self.shell.keystone.users.delete(user)  

    def create_router(self, name):
        router = self.shell.quantum.create_router(name=name)
        # TODO: add router to external network
        return router

    def delete_router(self, name):
        return self.shell.quantum.delete_router(name=name)
    
    def create_network(self, name):
        return self.shell.quantum.create_network(name=name, admin_state_up=True)
    
    def delete_network(self, name):
        nets = self.shell.quantum.list_networks(name=name)
        for net in nets:
            # delete all subnets:
            #subnets = self.api.client_shell.quantum.list_subnets(network_id=net['network_id'])['subnets']
            for subnet_id in net['subnets']:
                self.delete_subnet(subnet_id)
            self.shell.quantum.delete_network(net['id'])
    
    def create_subnet(self, network_name, cidr_ip, ip_version, start, end):
        nets = self.shell.quantum.list_networks(name=network_name)
        if not nets:
            raise Exception, "No such network: %s" % network_name   
        nets = nets[0]

        subnets = self.shell.quantum.list_subnets(name=self.name)
        allocation_pools = [{'start': start, 'end': end}]
        subnet = self.shell.quantum.create_subnet(network_id=net['id'],
                                                ip_version=ip_version,
                                                cidr=cidr_ip,
                                                dns_nameservers=['8.8.8.8'],         
                                                allocation_pools=allocation_pools)

        # TODO: Add route to external network
        # e.g. #  route add -net 10.0.3.0/24 dev br-ex gw 10.100.0.5 
        return subnet

    def delete_subnet(self, id):
        return self.client.quantum.delete_subnet(id=id)
     
    
    def create_keypair(self, name, key):
        keys = self.client.nova.keypairs.findall(name=name)
        if keys:
            raise Exception, "Key name already exists: %s" % name
        return self.client.nova.keypairs.create(name=name, public_key=key)

    def delete_keypair(self, name):
        keys = self.client.nova.keypairs.findall(name=name)
        for key in keys:
            self.client.nova.keypairs.delete(key) 

    def spawn_instance(self, name, key_name=None, hostname=None, flavor=None, image=None, security_group=None, pubkeys=[]):
        if not flavor:
            flavor = self.config.nova_default_flavor
        if not image:
            image = self.config.nova_default_imave
        if not security_group:
            security_group = self.config.nova_default_security_group 

        authorized_keys = "\n".join(pubkeys)
        files = {'/root/.ssh/authorized_keys': authorized_keys}
       
        flavor_id = self.shell.nova.flavors.find(name=flavor)
        images = self.shell.glance.get_images(name=image)
        if not images:
            raise Exception, "Image not found: " + image  
        image_id = images[0]['id']
        hints = {}
        if hostname:
            hints['force_hosts']= hostname
        server = self.shell.nova.servers.create(
                                            name=name,
                                            key_name = key_name,
                                            flavor=flavor_id,
                                            image=image_id,
                                            security_group = security_group,
                                            files=files,
                                            scheduler_hints=hints)
        return server
          
    def destroy_instance(self, name, id=None):
        args = {'name': name}
        if id:
            args['id'] = id
        servers = self.shell.nova.servers.findall(**args)
        for server in servers:
            if name == server.name:
                if not id or id == server.id:
                    self.shell.nova.servers.delete(server)
