"""
cassisStats
~~~~~~~~~~~~

A script printing some basic statistics for CASSIS files

cassisStats provides the functions:
    - printStats
    - writeStats
    - extractColumnNames


How to use them?
----------------

>>> printStats(column, filename, sigmaClip=sigmaClip)
>>> writeStats(userInputs, sigmaClip=sigmaClip, mode=mode, outputFile=outputFile)
>>> extractColumnNames(filename)

Example
-------

# printStats

>>> printStats(["tex_1(K)"], "path/to/file.dat")
>>> printStats(["tex_1(K)"], "path/to/file.dat", sigmaClip=3)

# writeStats

# Compute the statistics from the parameters and write them in a file
# named like userInputs.outputFile but with the extension ".txt"
>>> writeStats(userInputs)

# Compute and write using a sigma clipping = 3
>>> writeStats(userInputs, sigmaClip=3)

# The default behaviour of writeStats is to append the new statistics in the
# file. We can overwrite this behaviour by changing its mode to "w" (write)
>>> writeStats(userInputs, mode="w")

# Give a specific name to the output file
>>> writeStats(userInputs, outputFile="stats.txt")


"""

import os
import ScriptEnvironment
from Statistics	import *
from FileReader	import FileReader
from eu.omp.irap.cassis.database.access import AccessDataBase


def printStats(columns, filename, sigmaClip=None):
    rows = []
    if sigmaClip is not None:
        msg = "Statistics using a sigma clip = %d" % sigmaClip
        print(msg)
        rows.append(msg)

    hr = "=" * 50
    header = "Column".ljust(22)
    header += "Mean\tMedian\tStdev"
    print(hr)
    print(header)

    rows.append(hr)
    rows.append(header)
    #
    for column in columns:
        output = _printStatsForColumn(column, filename, sigmaClip)
        rows.append(output)
    print("=" * 50)
    rows.append(hr)
    return rows


# def writeStats(columns, inputFile, sigmaClip=None, outputFile=None):
#     """Write the statistics to the given filename"""
#     if not outputFile:
#         outputFile = os.path.splitext(inputFile)[0] + ".txt"

#     f = open(outputFile, "w")
#     rows = printStats(columns, inputFile, sigmaClip=sigmaClip)
#     for row in rows:
#         f.write(row + "\n")
#     f.close()
#     print("\nStatistics written in %s." % os.path.abspath(outputFile))


def _printStatsForColumn(columnName, filename, sigmaClip=None):
    """Print the following statistics on the given column fot the filename:
        - the number of points
        - the arithmetic mean
        - the median (using a criterion of convergence)
        - the root mean square
        - the standard deviation

    Usage
    -----
    _printStatsForColumn(columnName, filename, sigmaClip=sigmaClip)

    Parameters
    ---------
    columnName : a string
            the name of the column such as it is written in the file
    filename : a string
            the full path to file containing the data

    Returns
    -------
    None

    """
    # Check the file exists
    if not os.path.exists(filename):
        print("%s can't be found. Please check your input." % filename)

    else:
        # Read the file
        reader = FileReader(filename)
        reader.read_file(lines_to_skip=1)
        columnNames = reader.columnNames

        # Check the column exists
        if columnName not in columnNames:
            msg = "Column %s can't be found.\n" % columnName
            msg += "Please choose one of the following columns: %r." % columnNames
            print(msg)
        else:
            if sigmaClip:
                chi2 = reader.columns["chi2"]
                pairs_of_columns = zip(chi2, reader.columns[columnName])
                output = print_statistics_after_filter(columnName, pairs_of_columns, sigmaClip)
                return output
            else:
                output = print_statistics(columnName, reader.columns[columnName])
                return output


def writeRow(f, name, value):
    f.write("%.20s = %s\n" % (name, value))


def writeHeader(filename, info, mode="a"):
    f = open(filename, mode)
    writeRow(f, "species", info["species"])
    writeRow(f, "inputFile", info["inputFile"])
    writeRow(f, "telescope", info["telescope"])
    writeRow(f, "chi2Min", info["chi2Min"])
    writeRow(f, "Chi2MinReduced", info["Chi2MinReduced"])
    f.close()


def extractColumnNames(filename):
    """Extract the names of the columns in the given outout data file"""
    f = open(filename, "r")
    # Skip the first line
    f.readline()
    # Skip columns: '#' and 'chi2'
    columnNames = f.readline().split("\t")[1:-1]
    f.close()
    return columnNames


def analyzeComponent(component):
    """Analyze a component object"""
    result = {}
    result["model"] = component.model
    if result["model"].upper() == "RADEX":
        result["collisionFile"] = component.collisionFile
        result["collisioner"] = component.collisioner
        result["geometry"] = component.geometry
    return result


def analyzeInputs(inputs):
    """Analyze the inputs defined by the user"""
    result = {}
    # Metadata
    getMoleculeName = lambda moltag: AccessDataBase.getDataBaseConnection().getMolName(str(moltag))
    result["species"] = ", ".join(getMoleculeName(x[1]) for x in inputs.species)
    result["inputFile"] = inputs.inputFile
    result["telescope"] = inputs.telescope

    # Components
    components = inputs.components.components
    componentsResults = map(analyzeComponent, components)
    result["components"] = componentsResults
    return result


def writeStats(inputs, sigmaClip=None, mode="a", outputFile=""):
    """Write the statistics of the physical parameters processed with LineAnalysisScripting

    Usage
    -----
    writeStats(inputs, sigmaClip=sigmaClip, mode=mode, outputFile=outputFile)
    
    Parameters
    ----------
    inputs : UserInputs
        The inputs defined by the user

    sigmaClip : int
        The value for the sigma clipping 
        (optional)
        
    mode : str
        Determine if the new result should overwrite the previous results ("w")
        or if it should be appended ("a")
        (optional)

    outputFile : str
        The name of the output file. By default output file is named from the
        output filename set in the inputs but with the extension '.txt'
        (optional)

    Returns
    -------
    None. A file is created or updated.
        
    Examples
    --------
    # Compute the statistics from the parameters and write them in a file
    # named like userInputs.outputFile but with the extension ".txt"
    >>> writeStats(userInputs)

    # Compute and write using a sigma clipping = 3
    >>> writeStats(userInputs, sigmaClip=3)

    # The default behaviour of writeStats is to append the new statistics in the
    # file. We can overwrite this behaviour by changing its mode to "w" (write)
    >>> writeStats(userInputs, mode="w")

    # Give a specific name to the output file
    >>> writeStats(userInputs, outputFile="stats.txt")

    """
    # Files
    inputFile = inputs.outputFile

    if outputFile:
        statsFile = outputFile
    else:
        statsFile = os.path.splitext(inputFile)[0] + ".txt"
	
    # Analysis of the user inputs
    result = analyzeInputs(inputs)
    componentCount = len(result["components"])

    # Header
    result["chi2Min"] = "%.2f" % inputs.chi2Min
    result["Chi2MinReduced"] = "%.2f" % inputs.chi2MinReduced
    writeHeader(statsFile, result, mode)

    # Parameters
    columnNames = extractColumnNames(inputFile)
    # Display and writing
    f = open(statsFile, "a")
    cpt_component_species = 0 
    for i in range(componentCount):
        componentResult = result["components"][i]
       
        model = componentResult["model"]

        cpt_component_species = cpt_component_species +1
        columnNamesForComponent = filter(lambda p: "_%d" % (cpt_component_species) in p, columnNames)
        rows = printStats(columnNamesForComponent, inputFile, sigmaClip=sigmaClip)

        f.write("\n* Component %d\n" % (cpt_component_species))
        writeRow(f, "model", model)

        if model.upper() == "RADEX":
            writeRow(f, "collisionFile", componentResult["collisionFile"])
            writeRow(f, "collisioner", componentResult["collisioner"])
            writeRow(f, "geometry", componentResult["geometry"])

        for row in rows:
            f.write(row + "\n")

    f.write("\n" + "-" * 80 + "\n\n")
    f.close()
    print("\nStatistics written in %s." % os.path.abspath(statsFile))



