#!/usr/bin/env python

import json
import sys
import argparse
import StringIO
import requests
import base64
import datetime
import sha

import catsnap
from catsnap import Client
from catsnap.config.base import Config
from catsnap.config.argument_config import ArgumentConfig
from catsnap.config.env_config import EnvConfig
from catsnap.config.file_config import FileConfig
from catsnap.config import MetaConfig
from catsnap.image_truck import ImageTruck
from catsnap.document.image import Image
from catsnap.batch.image_batch import get_images
from catsnap.batch.tag_batch import get_tags, add_image_to_tags

from boto.exception import DynamoDBResponseError

def add(args):
    api_host = Client().config().api_host
    api_key = Client().config().api_key
    api_url = '%s/add.json' % api_host
    now = str(datetime.datetime.utcnow())
    string_to_sign = "%s\n%s" % (now, api_key)
    signature = sha.sha(string_to_sign).hexdigest()

    response = requests.post(api_url,
            data={'url': args.path, 'tags': ' '.join(args.tags)},
            headers={'X-Catsnap-Signature': signature,
                     'X-Catsnap-Signature-Date': now})
    body = json.loads(response.text)
    print body['url']

def find(args):
    api_host = Client().config().api_host
    api_url = '%s/find.json' % api_host
    response = requests.get(api_url, params={
        'tags': ' '.join(args.tags)})
    image_structs = json.loads(response.text)
    for struct in image_structs:
        url = ImageTruck.extensioned(struct['url'])
        tags = ' '.join(struct['tags'])
        print '%s   |   %s' % (url, tags)

def update_config(args):
    config = FileConfig()
    if 'settings' in args:
        config.collect_settings(settings_to_get=args.settings)
    else:
        config.collect_settings()

def main():
    orig_stdout = sys.stdout
    stdout_capture = StringIO.StringIO()
    sys.stdout = stdout_capture
    error = None
    try:
        config = MetaConfig(include_arg_config=True)
    except SystemExit:
        #the argparse inside the ArgumentConfig will print to
        #stdout and then throw a SYSTEM GODDAMN EXIT.
        config = None
        error = stdout_capture.getvalue()
    finally:
        sys.stdout = orig_stdout
    Client().config(config)
    parser = argparse.ArgumentParser(
            usage='',
            description='Store and search for images by tag.')
    subparsers = parser.add_subparsers(help='Actions')

    add_command = subparsers.add_parser('add', help='add an image')
    add_command.add_argument('path', help='url or filename to add')
    add_command.add_argument('tags', nargs='+', help='tags for this image')
    add_command.set_defaults(func=add)

    find_command = subparsers.add_parser('find', help='find an image')
    find_command.add_argument('tags', nargs='+', help='tags to find')
    find_command.set_defaults(func=find)

    config_command = subparsers.add_parser('config',
            help='update configuration')
    #we have to manually add a "no choice" option because of what appears to
    #be an argparse bug: choices=[...] requires some choice even though
    #nargs='*' says "no choice is required."
    choices = map(str, Config.CLIENT_SETTINGS)
    choices.append([])
    config_command.add_argument('settings', nargs='*', help='settings to '
            'update (or leave blank, to loop through all available settings)',
            choices=choices)
    #we had to map str() on the settings because of an argparse bug:
    #if the user specifies an invalid option here, the error message
    #uses the __repr__ of the choices rather than their __str__.
    config_command.set_defaults(func=update_config)

    #this help command is necessary because the argparse inside MetaConfig
    #doesn't see the `-h` in `catsnap find -h` as a flag on find, but as a
    #flag on catsnap itself. find never gets to see the -h and we don't get
    #its help from it.
    help_command = subparsers.add_parser('help',
            help='show help for an individual command')
    parsers = {
            'add': add_command,
            'find': find_command,
            'help': help_command,
            'config': config_command}
    help_command.add_argument('command', nargs=1,
            choices=parsers.keys())
    def show_command_help(args):
        sys.stderr.write(parsers[args.command[0]].format_help())
    help_command.set_defaults(func=show_command_help)

    if error is not None:
        sys.stderr.write(error)
        sys.stderr.write(parser.format_help())
        sys.exit(2)
    args = parser.parse_args(config['arg'])
    args.func(args)

main()
