#!/usr/bin/env python
import os
import ConfigParser

from ansible.module_utils.basic import *

from mist.client import MistClient

DOCUMENTATION = '''
---
module: mist_backends
short_description: Manage backends in the mist.io service
description:
  - Manage multi-cloud backends through mist.io service.
  - You can add/remove multiple backends from multiple providers through mist.io service.
  - Before you can provision, monitor etc machines through mist.io, you have to first add a backend to the mist.io service.
  - Mist.io supports
  - EC2,
  - Rackspace,
  - Openstack,
  - Linode,
  - Google Compute Engine,
  - SoftLayer,
  - Digital Ocean,
  - Nephoscale,
  - Bare metal servers,
  - Docker containers,
  - HP Cloud.
  - I(mist_email) and I(mist_password) can be skipped if I(~/.mist) config file is present.
  - See mist.client documentation for config file U(http://mistclient.readthedocs.org/en/latest/cmd/cmd.html)
requirements:
  - mist.client
options:
  mist_email:
    description:
      - Email to login to the mist.io service
    required: false
  mist_password:
    description:
      - Password to login to the mist.io service
    required: false
  mist_uri:
    default: https://mist.io
    description:
      - Url of the mist.io service. By default https://mist.io. But if you have a custom installation of mist.io you can provide the url here
    required: false
  state:
    description:
      - If provided it will instruct the module to trigger backend actions, otherwise it will only list information
    choices: ["present", "absent"]
    required: false
  name:
    description:
      - The title you want the backend to have
    required: false
  provider:
    description:
      - Provider id for the backend you want to add to mist.io. You can see all the providers ids using the M(mist_providers) module.
    required: false
  region:
    description:
      - Necessary only if there is a custom Openstack region
    required: false
  backend_key:
    description:
      - This is either the username, api_key etc, depending on the provider
    required: false
  backend_password:
    description:
      - This is either the password, api_secret etc, depending on the provider
    required: false
  api_url:
    description:
      - APIURL needed by Openstack and HP Cloud
    required: false
  compute_endpoint:
    description:
      - Needed by some OpenStack installations
    required: false
  machine_ip:
    description:
      - Ip address needed when adding Bare Metal Server
    required: false
  machine_key:
    description:
      - Id of ssh key needed when adding Bare Metal Server. The key must have been added first to the mist.io service
    required: false
  machine_port:
    description:
      - Used when adding a Bare Metal Server
    required: false
  machine_user:
    description:
      - User for Bare Metal Server
    required: false
  tenant_name:
    description:
      - In case of Openstack backend, it may have to be provided
    required: false
  backend:
    description:
      - Can be either he backend's name or id. To be used when listing info for backends.
author: "Chris Loukas <commixon@gmail.com>"
version_added: "1.7.1"

'''

EXAMPLES = '''
- name: Add NepshoScale backend
  mist_backends:
    mist_email: your@email.com
    mist_password: yourpassword
    name: NephoScale
    provider: nephoscale
    backend_key: 908dfjokjkma0hgj9809uj
    backend_secret: kjhf98y9lkj0909kj90
    state: present

- name: List information about DigitalOcean backend
  mist_backends:
    mist_email: your@email.com
    mist_password: yourpassword
    backend: DigitalOcean
  register: backend
'''


def authenticate(module):
    home_path = os.getenv("HOME")
    config_path = os.path.join(home_path, ".mist")
    config = ConfigParser.ConfigParser()

    mist_uri = module.params.get('mist_uri')
    mist_email = module.params.get('mist_email')
    mist_password = module.params.get('mist_password')


    # Set default mist uri
    config.add_section("mist.io")
    config.set("mist.io", "mist_uri", "https://mist.io")

    # Set default credentials
    config.add_section("mist.credentials")
    config.set("mist.credentials", "email", None)
    config.set("mist.credentials", "password", None)

    # Read configuration file
    if os.path.isfile(config_path):
            config.readfp(open(config_path))

    mist_uri = config.get("mist.io", "mist_uri")
    if not mist_email:
        mist_email = config.get("mist.credentials", "email") or ""

    if not mist_password:
        mist_password = config.get("mist.credentials", "password") or ""

    return init_client(mist_uri, mist_email, mist_password)


def init_client(mist_uri="https://mist.io", email=None, password=None):
    client = MistClient(mist_uri, email, password)
    return client


def determine_action(state):
    if not state:
        return "list"
    else:
        return "addremove"


def list_backends(module, client):
    backends = client.backends
    backend = module.params.get('backend')

    if not backend:
        result = {}
        for backend_key in backends.keys():
            result[backend_key] = backends[backend_key].info
    else:
        found = client.backend_from_id(backend)
        if not found:
            found = client.backend_from_title(backend)

        if not found:
            result = {}
        else:
            result = {}
            result[found.id] = found.info

    module.exit_json(changed=False, info=result)


def backend_action(module, client):
    provider = module.params.get('provider')
    backend_name = module.params.get('name')
    desired_state = module.params.get('state')

    backend_state, chosen_backend = check_state(client, provider, backend_name)

    if backend_state == 'present' and desired_state == 'present':
        module.exit_json(changed=False, info=chosen_backend.info)
    elif backend_state == 'present' and desired_state == 'absent':
        chosen_backend.delete()
        module.exit_json(changed=True)
    elif backend_state == 'absent' and desired_state == 'absent':
        module.exit_json(changed=False)
    elif backend_state == 'absent' and desired_state == 'present':
        chosen_backend = add_backend(module, client)
        module.exit_json(changed=True, info=chosen_backend.info)
    module.exit_json(changed=False, info="paparia")


def check_state(client, provider, backend_name):
    backend_state = 'absent'
    chosen_backend = None

    for key in client.backends:
        backend = client.backends[key]
        if backend.info['provider'] == provider and backend.title == backend_name:
            backend_state = 'present'
            chosen_backend = backend
            break

    return backend_state, chosen_backend


def remove_backend(provider, client):
    for key in client.backends:
        backend = client.backends[key]
        if backend.info['provider'] == provider:
            backend.delete()
            return


def add_backend(module, client):
    title = module.params.get('name')
    provider = module.params.get('provider')
    key = module.params.get('backend_key')
    secret = module.params.get('backend_secret')
    tenant_name = module.params.get('tenant_name')
    region = module.params.get('region')
    apiurl = module.params.get('api_url')
    machine_ip = module.params.get('machine_ip')
    machine_key = module.params.get('machine_key')
    machine_user = module.params.get('machine_user')
    compute_endpoint = module.params.get('compute_endpoint')
    machine_port = module.params.get('machine_port')

    client.add_backend(title, provider, key, secret, tenant_name, region, apiurl, machine_ip, machine_key, machine_user,
                       compute_endpoint, machine_port)

    client.update_backends()

    backend = client.backend_from_title(title)
    return backend


def main():
    module = AnsibleModule(
        argument_spec=dict(
            provider=dict(required=False, type='str'),
            state=dict(required=False, choices=['present', 'absent']),
            # enabled=dict(required=False, default=True, type='bool'),
            name=dict(required=False, type='str'),
            backend=dict(required=False, type='str'),
            backend_key=dict(required=False, type='str'),
            backend_secret=dict(required=False, type='str'),
            tenant_name=dict(required=False, type='str'),
            region=dict(required=False, type='str'),
            api_url=dict(required=False, type='str'),
            compute_endpoint=dict(required=False, type='str'),
            machine_ip=dict(required=False, type='str'),
            machine_key=dict(required=False, type='str'),
            machine_user=dict(required=False, type='str'),
            machine_port=dict(required=False, type='str'),
            mist_uri=dict(default='https://mist.io', type='str'),
            mist_email=dict(required=False, type='str'),
            mist_password=dict(required=False, type='str'),
        )
    )

    client = authenticate(module)

    #Determine which action to run (e.g. list backends, add backend etc)
    state = module.params.get('state')
    action = determine_action(state)

    if action == "list":
        list_backends(module, client)
    else:
        backend_action(module, client)

main()