#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
nmrstarlib command-line interface

Usage:
    nmrstarlib -h | --help
    nmrstarlib --version
    nmrstarlib convert (<from-path> <to-path>) [--from-format=<format>] [--to-format=<format>] [--bmrb-url=<url> | --pdb-url=<url>] [--nmrstar-version=<version>] [--verbose]
    nmrstarlib csview <starfile-path> [--aa=<aa>] [--at=<at>] [--aa-at=<aa-at>] [--csview-outfile=<path>] [--csview-format=<format>] [--bmrb-url=<url> | --pdb-url=<url>] [--nmrstar-version=<version>] [--verbose] [--show]
    nmrstarlib plsimulate (<from-path> <to-path> <spectrum>) [--from-format=<format>] [--to-format=<format>] [--plsplit=<%>] [--distribution=<func>] [--seed=<value>] [--H=<value>] [--C=<value>] [--N=<value>] [--bmrb-url=<url> | --pdb-url=<url>] [--nmrstar-version=<version>] [--spectrum-descriptions=<path>] [--verbose]

Options:
    -h, --help                      Show this screen.
    --version                       Show version.
    --verbose                       Print what files are processing.
    --show                          Display chemical shifts image generated by 'csview' command by default image viewer.
    --from-format=<format>          Input file format, available formats: nmrstar, json [default: nmrstar].
    --to-format=<format>            Output file format, available formats: nmrstar, json [default: json].
    --nmrstar-version=<version>     Version of NMR-STAR format to use, available: 2, 3 [default: 3].
    --bmrb-url=<url>                URL to BMRB interface [default: http://rest.bmrb.wisc.edu/bmrb/NMR-STAR3/].
    --pdb-url=<url>                 URL to PDB interface [default: https://files.rcsb.org/view/].
    --aa=<aa>                       Comma-separated amino acid three-letter codes (e.g. --aa=ALA,SER).
    --at=<at>                       Comma-separated BMRB atom codes (e.g. --at=CA,CB).
    --aa-at=<aa-at>                 Amino acid three-letter codes (keys) and corresponding atoms (values) (e.g. --aa-at=ALA-CA,CB:LYS-CB,CG,CD).
    --csview-outfile=<path>         Where to save chemical shifts table.
    --csview-format=<format>        Format to which save chemical shift table [default: svg].
    --plsplit=<%>                   How to split peak list into chunks by percent [default: 100].
    --spectrum-descriptions=<path>  Path to custom spectrum descriptions file.
    --distribution=<func>           Statistical distribution function [default: normal].
    --seed=<value>                  Integer value used to initialize a pseudorandom number generator during peak list simulation.
    --H=<value>                     Statistical distribution parameter(s) for H dimension.
    --C=<value>                     Statistical distribution parameter(s) for C dimension.
    --N=<value>                     Statistical distribution parameter(s) for N dimension.
"""

import collections

from . import nmrstarlib
from . import converter
from . import csviewer
from . import noise
from . import translator


def cli(cmdargs):

    nmrstarlib.BMRB_REST = cmdargs["--bmrb-url"]
    nmrstarlib.VERBOSE = cmdargs["--verbose"]
    nmrstarlib.NMRSTAR_VERSION = cmdargs["--nmrstar-version"]

    if cmdargs["convert"]:

        nmrstar_file_translator = translator.StarFileToStarFile(from_path=cmdargs["<from-path>"],
                                                                to_path=cmdargs["<to-path>"],
                                                                from_format=cmdargs["--from-format"],
                                                                to_format=cmdargs["--to-format"])

        nmrstar_converter = converter.Converter(file_generator=nmrstar_file_translator)
        nmrstar_converter.convert()

    elif cmdargs["csview"]:
        amino_acids = cmdargs["--aa"].split(",") if cmdargs["--aa"] else None
        atoms = cmdargs["--at"].split(",") if cmdargs["--at"] else None
        amino_acids_and_atoms = cmdargs["--aa-at"]

        if amino_acids_and_atoms:
            amino_acids_and_atoms_list = [pair.split('-') for pair in amino_acids_and_atoms.split(':')]
            amino_acids_and_atoms = {aa: at.split(",") for aa, at in amino_acids_and_atoms_list}
        else:
            amino_acids_and_atoms = None

        chemshift_viewer = csviewer.CSViewer(from_path=cmdargs["<starfile-path>"],
                                             amino_acids=amino_acids,
                                             atoms=atoms,
                                             amino_acids_and_atoms=amino_acids_and_atoms,
                                             filename=cmdargs["--csview-outfile"],
                                             csview_format=cmdargs["--csview-format"],
                                             nmrstar_version=cmdargs["--nmrstar-version"])
        chemshift_viewer.csview(view=cmdargs["--show"])

    elif cmdargs["plsimulate"]:
        if cmdargs["--spectrum-descriptions"]:
            nmrstarlib.update_constants(spectrum_descriptions_cfg=cmdargs["--spectrum-descriptions"])

        plsplit = tuple(float(i) for i in cmdargs["--plsplit"].split(","))
        distribution_name = cmdargs["--distribution"]
        seed = int(cmdargs["--seed"]) if cmdargs["--seed"] else None
        distribution_parameter_names = noise.distributions[distribution_name]["parameters"]

        if not distribution_parameter_names:
            parameters = None
        else:
            parameters = collections.defaultdict(list)

            for dim in ("H", "N", "C"):
                params = cmdargs["--{}".format(dim)]
                if params in (None, ""):
                    for param_name in distribution_parameter_names:
                        parameters["{}_{}".format(dim, param_name)].append(None)
                else:
                    params = params.split(",")
                    if len(params) > len(distribution_parameter_names):
                        raise ValueError("Inconsistent number of parameters provided.")

                    for param, param_name in zip(params, distribution_parameter_names):
                        parameters["{}_{}".format(dim, param_name)].extend([float(val) if val else None for val in param.split(":")])

            # fill with None values for parameters that have missing values
            for param_name, param_values in parameters.items():
                given_values = list(param_values)
                missing_values = [None for _ in range(len(plsplit) - len(param_values))]
                param_values = given_values + missing_values
                parameters[param_name] = tuple(param_values)

        noise_generator = noise.NoiseGenerator(parameters=parameters, distribution_name=distribution_name, seed=seed)

        peaklist_file_translator = translator.StarFileToPeakList(from_path=cmdargs["<from-path>"],
                                                                 to_path=cmdargs["<to-path>"],
                                                                 from_format=cmdargs["--from-format"],
                                                                 to_format=cmdargs["--to-format"],
                                                                 spectrum_name=cmdargs["<spectrum>"],
                                                                 plsplit=plsplit,
                                                                 noise_generator=noise_generator,
                                                                 nmrstar_version=cmdargs["--nmrstar-version"])

        nmrstar_to_peaklist_converter = converter.Converter(file_generator=peaklist_file_translator)
        nmrstar_to_peaklist_converter.convert()
