#!/usr/bin/env python3

import sys
import os.path

root_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
sys.path.insert(0, root_path)

import argparse
import os
import string
import datetime
import getpass
import logging
import io

import plicense.scanner
import plicense.injector

try:
    _unicode = unicode
except NameError:
    _unicode = str

def _configure_logging():
    # Configure logging.

    logger = logging.getLogger()
    logger.setLevel(logging.DEBUG)
    #logger.setLevel(logging.INFO)

    ch = logging.StreamHandler()

    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    ch.setFormatter(formatter)
    logger.addHandler(ch)

#_configure_logging()
_logger = logging.getLogger(__name__)

description = "Intelligently install the license-stub at the top of every "\
              "file."

parser = argparse.ArgumentParser(description=description)

parser.add_argument(
        'license_filepath', 
        metavar='<license filepath>',
        help="The license file-path")

parser.add_argument(
        '-e', '--extension', 
        metavar='<ext>',
        help="Filter by extension")

mutex = parser.add_mutually_exclusive_group()

mutex.add_argument(
        '-d', '--no-changes', 
        action='store_true', 
        help="Just print the files that would be changed")

mutex.add_argument(
        '-q', '--quiet', 
        action='store_true', 
        help="Don't print the files being updated")

parser.add_argument(
        '-i', '--indicator', 
        metavar='<string>',
        default='opyright', 
        help="What to look for at the top of the file if a stub is already present")

parser.add_argument(
        '-l', '--max-lines', 
        type=int, 
        metavar='<n>',
        default=10, 
        help="The number of lines at the top of the sourcecode to check for the indicator")

parser.add_argument(
        '-a', '--insert-after', 
        metavar='<string>',
        default=['#!/'], 
        action='append', 
        help="If this exists at the top of the file, insert the license after rather than before")

parser.add_argument(
        '-m', '--insert-after-max-lines', 
        type=int, 
        metavar='<n>',
        default=10, 
        help="The number of lines at the top to check for insert-after strings")

parser.add_argument(
        '-r', '--replace', 
        action='append', 
        nargs=2,
        metavar=('<key>', '<value>'),
        default=[],
        help="Do a string-replacement into the license text")

parser.add_argument(
        '-p', '--path', 
        metavar='<path>',
        default=os.getcwd(),
        help="Path to use (defaults to current)")

parser.add_argument(
        '-c', '--no-recursion', 
        action='store_true', 
        help="Don't print the files being updated")

parser.add_argument(
        '-f', '--ignore-file', 
        action='append', 
        default=[],
        metavar='<filename>',
        help="Don't process this file")

parser.add_argument(
        '-g', '--ignore-directory', 
        action='append', 
        default=[],
        metavar='<directory name>',
        help="Don't process this directory")

parser.add_argument(
        '-n', '--no-stats', 
        action='store_true', 
        help="Don't print stats (usually goes to stderr)")

args = parser.parse_args()

def _get_license_text(license_stub_template_filepath, explicit_reps):
    with open(license_stub_template_filepath) as f:
        license_stub_template = f.read().strip()

    if "\r\n" in license_stub_template:
        nl = "\r\n"
    elif "\r" in license_stub_template:
        nl = "\r"
    else:
        nl = "\n"

    replacements = { 'YEAR': datetime.datetime.now().strftime('%Y'),
                     'USER': getpass.getuser() }

    replacements.update(dict([(k.upper(), v) 
                              for (k, v) 
                              in explicit_reps.items()]))

    t = string.Template(license_stub_template)
    license_stub = t.substitute(replacements)

    s = io.StringIO(_unicode(license_stub))
    lines = s.readlines() + [nl, nl]

    return (lines, nl)

def _dump(d):
    return "DUMP> " + (' '.join([x.encode('hex') for x in d])) + "\n"

def _apply_license(license_lines, license_indicator, max_lines, insert_after, 
                   insert_after_max_lines, path, is_no_changes, is_quiet, 
                   is_recursive, ignore_files, ignore_directories, is_no_stats,
                   sourcecode_ext=None):

    scanner = plicense.scanner.Scanner(
                path, 
                license_indicator, 
                max_lines, 
                is_recursive,
                ignore_files,
                ignore_directories,
                is_no_stats,
                sourcecode_ext)

    injector = plicense.injector.Injector(
                license_lines, 
                insert_after=insert_after,
                insert_after_max_lines=insert_after_max_lines)

    for (filepath, lines) in scanner.scan():
        if is_quiet is False:
            print(filepath)

        lines = injector.prepend(lines)

        if is_no_changes is False:
            with open(filepath, 'w') as f:
                for line in lines:
                    f.write(line)
        else:
            _logger.debug("Not making changes: [%s]", filepath)

replacements = dict([(k.upper(), v) for (k, v) in args.replace])

license_lines = _get_license_text(args.license_filepath, replacements)

if os.path.exists(args.path) is False:
    raise ValueError("Path does not exist: %s" % (args.path))

_apply_license(
    license_lines, 
    args.indicator, 
    args.max_lines, 
    args.insert_after,
    args.insert_after_max_lines,
    args.path,
    args.no_changes,
    args.quiet,
    args.no_recursion is not True,
    args.ignore_file,
    args.ignore_directory,
    args.no_stats,
    args.extension)
