#!/usr/bin/env python

import argparse
import sys
import time
from ast import literal_eval

try:
    import boto
    import boto.cloudformation
except ImportError:
    print("boto 2.8.0+ is required")
    sys.exit(1)

from troposphere.utils import tail


def upload_template_to_s3(conn, region, bucket_name, key_name, template):
    cloudformation_bucket = conn.lookup(bucket_name)
    if not cloudformation_bucket:
        if region == 'us-east-1':
            region = boto.s3.connection.Location.DEFAULT
        elif region == 'eu-west-1':
            region = boto.s3.connection.Location.EU

        cloudformation_bucket = conn.create_bucket(bucket_name, location=region)
    key = cloudformation_bucket.new_key(key_name)
    key.set_contents_from_string(template)
    cfn_template_url = "https://s3.amazonaws.com/%s/%s" % (
        bucket_name, key_name)
    return cfn_template_url


def create_stack(
    conn,
    stackname,
    template=None,
    url=None,
    params=None,
    capabilities=None,
):
    kwargs = dict(
        template_body=template,
        template_url=url,
        parameters=params,
        capabilities=capabilities,
    )
    
    try:
        stack_id = conn.create_stack(stackname, **kwargs)
    
    except boto.exception.BotoServerError as e:
        # XXX - need to figure out why this isn't getting parsed from boto.
        print("Error: %s" %
              (literal_eval(e.error_message)['Error']['Message'],))
        print("Exiting...")
        sys.exit(1)
    print("Created stack %s: %s" % (stackname, stack_id))


def build_s3_name(stack_name):
    timestamp = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())
    name = stack_name
    if stack_name.endswith('.json'):
        name = stack_name[:-5]
    return '%s-%s.json' % (name, timestamp)


def describe_resources(conn, stackname):
    if stackname is not None:
        print(conn.describe_stack_resources(stackname))
    else:
        stacks = conn.describe_stacks()
        for stack in stacks:
            print("Resources for stack {0}:".format(stack.stack_name))
            print(conn.describe_stack_resources(stack.stack_name))


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("-c", "--create", help="Create stack using template")
    parser.add_argument("-b", "--bucket", dest="s3bucket",
                        help="Upload template to S3 bucket")
    parser.add_argument("-d", "--debug", action='store_true',
                        help="Turn on boto debug logging")
    parser.add_argument("-n", "--name", dest="s3name",
                        help="Template name in S3 bucket")
    parser.add_argument("-p", "--parameter", dest="params", action='append',
                        help="stack parameters in key=value form")
    parser.add_argument("-r", "--region", default="us-east-1",
                        help="Region (default %(default)s)")
    parser.add_argument("-R", "--resources", action='store_true',
                        help="describe stack resources, list resources for "
                             "all stacks if no stack is specified")
    parser.add_argument("-t", "--tail", action='store_true',
                        help="tail event log")
    parser.add_argument(
        "-C",
        "--capability",
        dest="capabilities",
        action='append',
        help="Capability to allow in the stack",
    )
    parser.add_argument("stack", nargs='?')
    values = parser.parse_args()

    if values.params:
        values.params = [x.split('=') for x in values.params]
    else:
        values.params = []

    if values.debug:
        import logging
        logging.basicConfig(filename="boto.log", level=logging.DEBUG)

    conn = boto.cloudformation.connect_to_region(values.region)

    if values.create:
        # Read in the template file
        template = open(values.create).read()

        # If needed, build an S3 name (key)
        if values.s3bucket and not values.s3name:
            values.s3name = build_s3_name(values.create)

        kwargs = dict(
            template=template,
            params=values.params,
            capabilities=values.capabilities,
        )

        if values.s3bucket:
            # Upload to S3 and create the stack
            s3conn = boto.s3.connect_to_region(values.region)
            url = upload_template_to_s3(
                s3conn, values.region, values.s3bucket, values.s3name, template)
            kwargs['url'] = url
            del kwargs['template']

        create_stack(conn, values.stack, **kwargs)

    if values.resources:
        describe_resources(conn, values.stack)

    if values.tail:
        tail(conn, values.stack)
