import argparse
import logging

from isoplot.plots import StaticPlot, InteractivePlot, Map

logger = logging.getLogger(__name__)


def parseArgs():
    """
    :return: Argument Parser object
    :rtype: class: argparse.ArgumentParser
    """

    logger.debug('Initializing parser')
    parser = argparse.ArgumentParser("Isoplot2: Plotting isotopic labelling MS data")

    logger.debug('Adding positionnal arguments for general plot infos')
    parser.add_argument('datafile', help="Path to datafile")
    parser.add_argument('destination', help="Path to export destination")
    parser.add_argument("name", help="Name of generated file")
    parser.add_argument("format", help="Format of generated file")
    parser.add_argument('value', choices=['corrected_area', 'isotopologue_fraction', 'mean_enrichment'])

    parser.add_argument('-m', '--metabolite', default='all',
                        help="Metabolite(s) to plot. For all, type in 'all' ")
    parser.add_argument('-c', '--condition', default='all',
                        help="Condition(s) to plot. For all, type in 'all' ")
    parser.add_argument('-t', '--time', default='all',
                        help="Time(s) to plot. For all, type in 'all' ")
    parser.add_argument("-tp", "--template", default=0, action="store",
                        help="Path to template")

    logger.debug('Adding optionnal arguments for calling the plot methods')
    parser.add_argument('-sa', '--stacked_areaplot', action="store_true",
                        help='Create static stacked areaplot')
    parser.add_argument("-bp", "--barplot", action="store_true",
                        help='Create static barplot(for corrected_area and isotopologue_fraction)')
    parser.add_argument('-mb', '--meaned_barplot', action="store_true",
                        help='Create static barplot with meaned replicates(for corrected_area and '
                             'isotopologue_fraction)')
    parser.add_argument('-smp', '--static_mean_enrichment_plot', action="store_true",
                        help='Create static barplot with mean enrichment data')
    parser.add_argument('-smm', '--static_mean_enrichment_meanplot', action="store_true",
                        help='Create static barplot with mean enrichment data and meaned replicates')

    parser.add_argument('-IMP', '--interactive_mean_enrichment_plot', action="store_true",
                        help='Create interactive barplot with mean enrichment data')
    parser.add_argument('-IMM', '--interactive_mean_enrichment_meanplot', action="store_true",
                        help='Create interactive barplot with mean enrichment data and meaned replicates')
    parser.add_argument('-ISB', '--interactive_stacked_barplot', action="store_true",
                        help='Create interactive stacked barplot (for corrected area and isotopologue_fraction)')
    parser.add_argument('-ISM', '--interactive_stacked_meanplot', action="store_true",
                        help='Create interactive stacked barplot with meaned replicates (for corrected area and '
                             'isotopologue_fraction)')
    parser.add_argument('-ISA', '--interactive_stacked_areaplot', action="store_true",
                        help='Create interactive stacked areaplot')

    parser.add_argument('-hm', '--static_heatmap', action="store_true",
                        help='Create a static heatmap using mean enrichment data')
    parser.add_argument('-cm', '--static_clustermap', action="store_true",
                        help='Create a static heatmap with clustering using mean enrichment data')
    parser.add_argument('-HM', '--interactive_heatmap', action="store_true",
                        help='Create interactive heatmap using mean enrichment data')

    parser.add_argument('-s', '--stack', action="store_false",
                        help='Add option if barplots should be unstacked')
    parser.add_argument('-v', '--verbose', action="store_true",
                        help='Turns logger to debug mode')
    parser.add_argument('-a', '--annot', action='store_true',
                        help='Add option if annotations should be added on maps')

    return parser


def control_isoplot_plot(args, data_object, metabolite, conditions, times):
    """Function to control which plot methods are called depending on the
    arguments that were parsed"""

    logger.debug("Initiating plot object")

    static_plot = StaticPlot(args.stack, args.value, data_object.dfmerge,
                             args.name, metabolite, conditions, times, args.format, )

    interactive_plot = InteractivePlot(args.stack, args.value, data_object.dfmerge,
                                       args.name, metabolite, conditions, times)

    logger.debug("Selecting plot method")

    if args.stacked_areaplot:
        static_plot.stacked_areaplot()

    elif args.barplot:
        static_plot.barplot()

    elif args.meaned_barplot:
        static_plot.mean_barplot()

    elif args.static_mean_enrichment_plot:
        static_plot.mean_enrichment_plot()

    elif args.static_mean_enrichment_meanplot:
        static_plot.mean_enrichment_meanplot()

    elif args.interactive_mean_enrichment_plot:
        interactive_plot.mean_enrichment_plot()

    elif args.interactive_mean_enrichment_meanplot:
        interactive_plot.mean_enrichment_meanplot()

    elif args.interactive_stacked_barplot:
        interactive_plot.stacked_barplot()
        
    elif args.interactive_stacked_barplot and not args.stack:
        interactive_plot.unstacked_barplot()

    elif args.interactive_stacked_meanplot:
        interactive_plot.stacked_meanplot()

    elif args.interactive_stacked_meanplot and not args.stack:
        interactive_plot.unstacked_meanplot()

    elif args.interactive_stacked_areaplot:
        interactive_plot.stacked_areaplot()


def control_isoplot_map(args, data_object):
    """Function to control which map methods are called depending on the
    arguments that were parsed"""

    logger.debug("Initiating map object")

    mymap = Map(data_object.dfmerge, args.name, args.annot, args.format)

    logger.debug("Selecting plot method")

    if args.static_heatmap:
        mymap.build_heatmap()

    elif args.static_clustermap:
        mymap.build_clustermap()

    elif args.interactive_heatmap:
        mymap.interactive_heatmap()


def get_local_cli_input(name, data_object, logger):
    """
    Function to get input from user and check for errors in spelling.
    If an error is detected input is asked once more.
    This function is used for local implementation

    :param name: name of what we are looking for
    :type name: str
    :param data_object: IsoplotData object containing final clean dataframe
    :type data_object: class: 'isoplot.dataprep.IsoplotData'
    :param logger: Logger object
    :type logger: class: 'logging.Logger'
    :return: Desired string after parsing
    :rtype: list
    """

    if item == "all":
        desire = data_object.dfmerge[name].unique()
    else:
        is_error = True

        while is_error:
            try:
                # We show the list of possibilities to user
                print(data_object.dfmerge[name].unique())

                # Cli gives list of strings, se we must make words of them
                desire = [item for item in input("Input " + name
                                                 + "(s) to plot from list above (write 'all' for all to be plotted) "
                                                 ).split()]

                # Checking input for typos
                for item in desire:
                    if item == "all":
                        break
                    else:
                        assert item in data_object.dfmerge[name].unique()

            except AssertionError:
                logger.error(
                    "One or more of the chosen " + name + "(s) were not in list. Please check and try again.")

            except Exception as e:
                logger.error("Unexpected error: {}".format(e))

            else:
                logger.info("Chosen " + name + ": {}".format(desire))
                is_error = False

    return desire


def get_cli_input(arg, name, data_object, logger):
    """
    Function to get input from user and check for errors in spelling.
    If an error is detected input is asked once more.
    This function is used for galaxy implementation

    :param arg: list from which strings must be parsed
    :type arg: list
    :param name: name of what we are looking for
    :type name: str
    :param data_object: IsoplotData object containing final clean dataframe
    :type data_object: class: 'isoplot.dataprep.IsoplotData'
    :param logger: Logger object
    :type logger: class: 'logging.Logger'
    :return: Desired string after parsing
    :rtype: list

    """

    if item == "all":
        desire = data_object.dfmerge[name].unique()
    else:
        is_error = True

        while is_error:
            try:

                # Cli gives list of strings, se we must make words of them
                desire = [item for item in arg.split(",")]

                # Checking input for typos
                for item in desire:
                    if item == "all":
                        break
                    else:
                        assert item in data_object.dfmerge[name].unique()

            except AssertionError:
                logger.error(
                    "One or more of the chosen " + name +
                    "(s) were not in list. Please check and try again. Error: {}".format(item))

            except Exception as e:
                logger.error("Unexpected error: {}".format(e))

            else:
                logger.info("Chosen " + name + ": {}".format(desire))
                is_error = False

    return desire
