#!/usr/bin/python

import os
import sys
import json
import zipfile
import argparse
import pprint

from packer import module_metadata
from packer.commands_discovery import discover_modules_commands

INTRO_MSG = """
 _____       _ _     __        _          _____       _     _         
| __  |___ _| |_|___|  |   ___| |_ ___   |     |___ _| |_ _| |___ ___ 
|    -| -_| . | |_ -|  |__| .'| . |_ -|  | | | | . | . | | | | -_|_ -|
|__|__|___|___|_|___|_____|__,|___|___|  |_|_|_|___|___|___|_|___|___|

This utility will walk you through creating a Redis module package file.
It only covers the most common items, and tries to guess sensible defaults.

See `module_packer help json` for definitive documentation on these fields
and exactly what they do.

Press ^C at any time to quit."""

def setup_arg_parser():
    """
    Initialize cmd args parser
    """
    arg_parser = argparse.ArgumentParser(description='Create a new module package')
    arg_parser.add_argument('module', metavar='MODULE')
    arg_parser.add_argument('-o', '--output', dest='outfile', default='module.zip', help='Output file name')
    arg_parser.add_argument('-v', '--verbose', action='store_true', default=False, help='Verbose mode: print the resulting metadata')
    g1 = arg_parser.add_mutually_exclusive_group()    
    g1.add_argument('-i', '--interactive', dest='interactive',default=False, action='store_true')
    g2 = arg_parser.add_mutually_exclusive_group()    
    g2.add_argument('-a', '--author', dest='author', default=module_metadata.AUTHOR, help='module author')
    g2.add_argument('-e', '--email', dest='email', default=module_metadata.EMAIL, help='author\'s email')
    g2.add_argument('-ar', '--architecture', dest='architecture', default=module_metadata.ARCHITECTURE, help='module compiled on i386/x86_64 arch')
    g2.add_argument('-d', '--description', dest='description', default=module_metadata.DESCRIPTION, help='short description')
    g2.add_argument('-ho', '--homepage', dest='homepage', default=module_metadata.HOMEPAGE, help='module homepage')
    g2.add_argument('-l', '--license', dest='license', default=module_metadata.LICENSE, help='license')
    g2.add_argument('-ex', '--extras', dest='extra_files', default=module_metadata.EXTRA_FILES, help='extra files')
    g2.add_argument('-c', '--cmdargs', dest='command_line_args', default=module_metadata.COMMAND_LINE_ARGS, help='module command line arguments')
    g2.add_argument('-r', '--redis-min-version', dest='redis_min_version', default=module_metadata.MIN_REDIS_VERSION, help='redis minimum version')
    g2.add_argument('-rl', '--rlec-min-version', dest='rlec_min_version', default=module_metadata.MIN_RLEC_VERSION, help='rlec minimum version')
    g2.add_argument('-O', '--os', dest='os', default=module_metadata.OS, help='Build target OS (Darwin/Linux)')

    return arg_parser

def set_defaults(module_path):
    """
    Creates a module metadata using default values
    """
    metadata = module_metadata.create_default_metadata(module_path)
    return metadata

def update_metadata_module_info(metadata, module):
    """
    Sets metadata with module internal attributes
    """
    metadata["module_name"] = module.name
    metadata["version"] = module.version
    metadata["commands"] = [cmd.to_dict() for cmd in module.commands]

def interactive_mode(metadata):
    """
    Creates module metadata from user provided input
    """
    print INTRO_MSG
    user_input = raw_input("Architecture:{} ".format(module_metadata.ARCHITECTURE))
    if user_input is not "":
        if user_input not in ('i386', 'x86_64'):
            raise ValueError("Invalid architecture. Allowed values are i386 and x86_64")
        metadata["architecture"] = user_input
    
    user_input = raw_input("Os:{} ".format(module_metadata.OS))
    if user_input is not "":
        if user_input.lower() not in ('linux', 'darwin'):
            raise ValueError("Invalid OS. Allowed values are Darwin and Linux")
        metadata["os"] = user_input

    user_input = raw_input("Author: ")
    if user_input is not "":
        metadata["author"] = user_input

    user_input = raw_input("Email: ")
    if user_input is not "":
        metadata["email"] = user_input

    user_input = raw_input("Description:{} ".format(module_metadata.DESCRIPTION))
    if user_input is not "":
        metadata["description"] = user_input

    user_input = raw_input("Homepage:{} ".format(module_metadata.HOMEPAGE))
    if user_input is not "":
        metadata["homepage"] = user_input

    user_input = raw_input("License:{} ".format(module_metadata.LICENSE))
    if user_input is not "":
        metadata["license"] = user_input

    user_input = raw_input("Extra files:{} ".format(module_metadata.EXTRA_FILES))
    if user_input is not "":
        metadata["extra_files"] = user_input

    user_input = raw_input("Command line args:{} ".format(module_metadata.COMMAND_LINE_ARGS))
    if user_input is not "":
        metadata["command_line_args"] = user_input

    user_input = raw_input("Min redis version:{} ".format(module_metadata.MIN_REDIS_VERSION))
    if user_input is not "":
        metadata["min_redis_version"] = user_input

    user_input = raw_input("Min rlec version:{} ".format(module_metadata.MIN_RLEC_VERSION))
    if user_input is not "":
        metadata["min_rlec_version"] = user_input

def cmd_mode(metadata, args):
    """
    Create module metadata from command line arguments
    """
    

    metadata["architecture"] = args.architecture
    metadata["os"] = args.os
    metadata["author"] = args.author
    metadata["email"] = args.email
    metadata["description"] = args.description
    metadata["homepage"] = args.homepage
    metadata["license"] = args.license
    metadata["extra_files"] = args.extra_files
    metadata["command_line_args"] = args.command_line_args
    metadata["min_redis_version"] = args.redis_min_version
    metadata["min_rlec_version"] = args.rlec_min_version

def archive(module_path, metadata,archive_name='module.zip'):
    """
    Archives both module and module metadata.
    """
    archive_name = archive_name.format(**metadata)
    with open('module.json', 'w') as outfile:
        json.dump(metadata, outfile, indent=4, sort_keys=True)

    archive_file = zipfile.ZipFile(archive_name, 'w', zipfile.ZIP_DEFLATED)
    try:
        archive_file.write(module_path, metadata["module_file"])
        archive_file.write('module.json')
        print "{} generated.".format(archive_name)
    finally:
        archive_file.close()
        os.remove("module.json")


def main(argv):
    arg_parser = setup_arg_parser()
    if len(argv) == 1:
        arg_parser.print_help()
        return 1

    args = arg_parser.parse_args()
    
    module_path = args.module
    metadata = set_defaults(module_path)

    if args.interactive:
        interactive_mode(metadata)
    else:
        cmd_mode(metadata, args)

    # Load module into redis and discover its commands
    module = discover_modules_commands(module_path, metadata["command_line_args"])
    update_metadata_module_info(metadata, module)


    if args.verbose:
        print("Module Metadata:")
        print(json.dumps(metadata, indent=2))
    archive(module_path, metadata,archive_name=args.outfile)
    return 0

if __name__ == '__main__':
    sys.exit(main(sys.argv))
