#!/usr/bin/python
import subprocess
import argparse
import pprint
import glob
import json
import os

from pych.version import APP_NAME, APP_VERSION
from pych.compiler import moduralize
from pych import CONFIG
from pych.utils import info, warn, error

#
# pych commands
#

def check(arg):
    """Sanity checks the configuration."""

    info("Checking installation...")

    if not CONFIG:
        error("Cannot find configuration file (pych.json).")

    info(" * Templates")
    for slang in CONFIG["specializers"]["templates"]:
        for template_dir in CONFIG["specializers"]["templates"][slang]:
            if not os.path.exists(template_dir):
                error(
                    "Missing template dir(%s) for slang(%s)",
                    template_dir,
                    slang
                )

    info(" * Object Storage")
    try:
        for slang in CONFIG["object_store"]["output_paths"]:
            o_path = CONFIG["object_store"]["output_paths"][slang]
            path = os.sep.join([
                CONFIG["object_store"]["root_path"],
                o_path,
                'write_test'
            ])
            with open(path, 'w') as fd:
                fd.write("test")
    except Exception as e:
        error("Error trying to write to object-store: %s", e)

    # Check that Chapel libraries are there
    info(" * Libraries")

    # Check that c-headers are there
    info(" * Headers")

    # Check that the commands are invokable
    info(" * Commands")

    errors = []
    warnings = []
    required = ["g++", "chpl", "gcc", "py.test"]
    recommended = ["py.test"]
    for executable in required+recommended:
        try:
            process = subprocess.Popen(
                [executable, "--version"],
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE
            )
            out, err = process.communicate()
        except OSError as exc:
            if executable in required:
                errors.append((exc, "stacktrace here"))
            elif executable in recommended:
                warnings.append((exc, "stacktrace here"))

def version(arg):
    """Print the pych version."""

    info("%s %s" % (APP_NAME, APP_VERSION))

def compile(sfile):
    """Compile a Chapel module into a Python module."""

    if not CONFIG:
        error("Configuration is broken, can't compile.")
        return

    info("Compile this %s" % sfile)
    (source_file, output_file, wrap_fp) = moduralize(sfile)
    info("Compiled sfile(%s) into output_file(%s)"
         " with wrapped-source(%s)" % (
        source_file, output_file, wrap_fp
    ))

def bfiles(arg):
    if not CONFIG:
        error("Configuration is broken.")
        return

    CONFIG.pprint_specializers(['bfiles'])

def sfiles(arg):
    if not CONFIG:
        error("Configuration is broken.")
        return

    CONFIG.pprint_specializers(['sfiles'])

def templates(arg):
    if not CONFIG:
        error("Configuration is broken.")
        return

    CONFIG.pprint_specializers(['templates'])

def object_store(arg):

    if not CONFIG:
        error("Configuration is broken, can't compile.")
        return

    pprint.pprint(CONFIG._config)
    # TODO: List all the bfiles

if __name__ == "__main__":
    
    parser = argparse.ArgumentParser(   # Setup cli-argument parser
        description='Tool aiding the pych module'
    )

    exclusive = parser.add_mutually_exclusive_group()
    exclusive.add_argument(
        '-c', '--compile',
        metavar="source_file", type=str,
        help='Compile the given Chapel module into a Python module.'
    )
    exclusive.add_argument(
        '-k', '--check',
        action="store_const", const=True, default=False,
        help="Check the 'pych' installation, configuration, and environment."
    )
    exclusive.add_argument(
        '-z', '--testing',
        action="store_const", const=True, default=False,
        help="Run 'pych' testing."
    )
    exclusive.add_argument(
        '-s', '--sfiles',
        action="store_const", const=True, default=False,
        help="Show information about source-files (sfiles)."
    )
    exclusive.add_argument(
        '-b', '--bfiles',
        action="store_const", const=True, default=False,
        help='Show information about function-body files (bfiles).'
    )
    exclusive.add_argument(
        '-t', '--templates',
        action="store_const", const=True, default=False,
        help='Show information about templates.'
    )
    exclusive.add_argument(
        '-a', '--object-store',
        action="store_const", const=True, default=False,
        help='Show information about the object-store (.so files).'
    )
    exclusive.add_argument(
        '-v', '--version',
        action="store_const", const=True, default=False,
        help="Print version"
    )

    args = parser.parse_args()

    cmd = cmd_args = cmd_exec = None    # Grab a command, the "--long-name" of
    for arg in args.__dict__:           # the arg maps to the function-name
        cmd_args = args.__dict__[arg]
        if cmd_args:
            cmd = arg
            cmd_exec = locals()[arg]

    if cmd_exec:                        # Invoke it
        cmd_exec(cmd_args)
    else:                               # Print help when no commands provided
        parser.print_usage()
        error("No command provided, see help(-h, --help) for commands.")
