#!/usr/bin/env python2.7

import sys
import os

_APP_PATH = \
    os.path.join(os.path.dirname(__file__), '..', '..', '..')

sys.path.insert(0, os.path.abspath(_APP_PATH))

import logging
import argparse
import re

import pm.config.log
import pm.manifest

_LOGGER = logging.getLogger(__name__)

def _parse_args():
    description = "Create an archive with all differences since the manifest was written."
    parser = argparse.ArgumentParser(description=description)
    parser.add_argument(
        'root_path',
        help='Root path')

    parser.add_argument(
        'patch_name',
        help='Patch name')

    parser.add_argument(
        'output_path',
        help='Output path')

    parser.add_argument(
        '-mf', '--manifest-filename',
        help='Manifest filename')

    parser.add_argument(
        '-e', '--exclude-rel-path',
        metavar='REL-PATH',
        action='append',
        default=[],
        dest='excluded_rel_paths',
        help="Ignore the contents of this child path")

    parser.add_argument(
        '-i', '--include-rel-path',
        metavar='REL-PATH',
        action='append',
        default=[],
        dest='included_rel_paths',
        help="Constraint the matched files to one or more directories")

    parser.add_argument(
        '-ef', '--exclude-rel-filepath',
        metavar='REL-FILEPATH',
        action='append',
        default=[],
        dest='excluded_rel_filepaths',
        help="Ignore this filepath")

    parser.add_argument(
        '-j', '--json',
        action='store_true',
        help="Print result in JSON")

    parser.add_argument(
        '-m', '--max-files',
        type=int,
        metavar='COUNT',
        default=pm.config.patch.DEFAULT_MAXIMUM_ALLOWED_FILES_IN_PATCH,
        help="A safe maximum for the number of allowed files in the patch "
             "(0 for unlimited)")

    args = parser.parse_args()

    return args

def _main():
    args = _parse_args()

    root_path = args.root_path
    manifest_filename = args.manifest_filename
    excluded_rel_paths = args.excluded_rel_paths
    included_rel_paths = args.included_rel_paths
    excluded_rel_filepaths = args.excluded_rel_filepaths
    patch_name = args.patch_name
    patch_output_path = args.output_path
    do_print_json = args.json
    max_files = args.max_files or None

    if re.match(pm.config.patch.NAME_RX, patch_name) is None:
        print("The patch-name can only have numbers, letters, and "
              "underscores.")

        sys.exit(1)

    m = pm.manifest.Manifest(
            root_path, 
            manifest_filename=manifest_filename, 
            excluded_rel_paths=excluded_rel_paths,
            excluded_rel_filepaths=excluded_rel_filepaths,
            included_rel_paths=included_rel_paths)

    result = None

    try:
        r = m.make_patch(patch_name, patch_output_path, max_files=max_files)
    except pm.manifest.NoChangedFilesException:
        if do_print_json is True:
            result = {
                'found_changes': False,
            }
        else:
            print("No files have been changed.")
    else:
        (patch_filepath, patch_info) = r

        if do_print_json is True:
            hashes = m.get_hashes_for_files_in_patch(patch_info)

            for rel_filepath, info in patch_info['files'].items():
                info['hash_md5'] = hashes[rel_filepath]

            result = {
                'found_changes': True,
                'patch_filepath': patch_filepath,
                'patch_info': patch_info,
            }
        else:
            print("Created/Updated Files")
            print('---------------------')
            print('')

            for rel_filepath in patch_info['files'].keys():
                print(rel_filepath)

            print('')

            print("Patch file-path:")
            print('')
            print(patch_filepath)

    if do_print_json is True:
        print(pm.utility.pretty_json_dumps(result))
    else:
        print('')

if __name__ == '__main__':
    pm.config.log.configure_log()
    _main()
