# Copyright (C)  2020 The Meme Factory, Inc. http://www.karlpinc.com/

# This file is part of PGWUI_Testing.
#
# This program is free software: you can redistribute it and/or
# modify it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License along with this program.  If not, see
# <http://www.gnu.org/licenses/>.
#
# PGWUI command line tool.  Presently, has only cookiecutter functionality.

# Karl O. Pinc <kop@karlpinc.com>

import click
import mako.template
import os
import pathlib
import pkg_resources
import sys
import tempfile


def validate_target(target):
    if target.exists():
        print(f'Already exists: {target}', file=sys.stderr)
        sys.exit(1)


def transform_name(vars, name):
    return name.replace('template', vars['short_name'])


def renderable(entry):
    suffix = entry.suffix
    return suffix == 'mak' or suffix == 'makish'


def transform_file_name(vars, entry):
    if renderable(entry):
        return transform_name(vars, entry.stem)
    else:
        return transform_name(vars, entry.name)


def render(vars, content):
    return mako.template.Template(text=content).render(**vars)


def make_renderable(text):
    return text.replace('$ {', '${').replace('%%', '%')


def produce_content(entry):
    content = entry.read_text()
    if renderable(entry):
        content = render(vars, content)
        if entry.suffix == 'makish':
            content = make_renderable(content)
    return content


def deliver_file(target, vars, entry):
    print(entry)
    print(transform_file_name(vars, entry))
    print()
    file = pathlib.Path(transform_file_name(vars, entry))
    file.write_text(produce_content(entry))


def deliver_dir(target, vars, entry):
    dir = pathlib.Path(target / transform_name(vars, entry.name))
    dir.mkdir()
    with os.scandir(entry) as entries:
        for subentry in entries:
            deliver_entry(dir, vars, subentry)


def deliver_entry(target, vars, entry):
    if entry.is_dir():
        deliver_dir(target, vars, entry)
    else:
        deliver_file(target, vars, pathlib.Path(entry))


def traverse_templates(target, vars, template_path):
    target.mkdir()
    with os.scandir(template_path) as entries:
        for entry in entries:
            deliver_entry(target, vars, entry)


def deliver_target(target, vars):
    with tempfile.TemporaryDirectory() as tmpdir:
        pkg_resources.set_extraction_path(tmpdir)
        template_path = pkg_resources.resource_filename(__name__, 'template')
        traverse_templates(target, vars, template_path)
        pkg_resources.cleanup_resources()


@click.group()
def pgwui():
    pass


@pgwui.command(
    epilog='''

When PATH is omitted it defaults to the current directory.

When an option is not supplied its value is prompted for.

\b
component
    The name of the component, usually starting with 'PGWUI_'.
    Case is significant.  Generally, the first letter of each word
    is capitalized.

\b
short_name
  The name of the component without the "PGWUI_" prefix, in lower case.
  Used as the default route (with a "/" prepended) and in variable
  names, etc.

\b
summary
    Short description to go into setup.py.  Should conform to the
    Python Packaging Authority Specifications for a summary:
    https://packaging.python.org/specifications/core-metadata/#summary

\b
author-name
   The name of the author.
   https://packaging.python.org/specifications/core-metadata/#author

\b
author-email
   The email of the author.
   https://packaging.python.org/specifications/core-metadata/#author-email''')
@click.argument(
    'path',
    required=False,
    type=click.Path(exists=True, file_okay=False, dir_okay=True))
@click.option(
    '--component',
    prompt='Name of new component, in mixed case, with PGWUI_ prefix',
    help='name of new component, in mixed case')
@click.option(
    '--short-name',
    prompt='Lower case component name, with PGWUI_ prefix removed',
    help='lower case component name with PGWUI_ prefix removed')
@click.option(
    '--summary',
    prompt='Short description of new component',
    help='short description of new component')
@click.option(
    '--author-name',
    prompt='Name of author',
    help='name of author')
@click.option(
    '--author-email',
    prompt='Email of author',
    help='email of author')
def cookiecutter(
        path, component, short_name, summary, author_name, author_email):
    '''Produce, in the PATH directory, a directory of code containing
    the basic elements of a PGWUI component.  PGWUI components are packaged
    as independent Python distributions (packages).
    '''
    target = pathlib.Path(path, component)
    validate_target(target)
    deliver_target(target, {'component': component,
                            'short_name': short_name,
                            'summary': summary,
                            'author_name': author_name,
                            'author_email': author_email})
