"""
    genonets_constants
    ~~~~~~~~~~~~~~~~~~

    Defines constans used throughout the package.

    :author: Fahad Khalid
    :license: MIT, see LICENSE for more details.
"""

from genonets_utils import Utils


class GenonetsConstants:
    ALL = 0


class SupportedAlphabet:
    binary = ['0', '1']
    rna = ['A', 'U', 'C', 'G']
    dna = ['A', 'T', 'C', 'G']
    protein = ['A', 'R', 'N', 'D', 'C', 'E', 'Q', 'G', 'H', 'I',
               'L', 'K', 'M', 'F', 'P', 'S', 'T', 'W', 'Y', 'V']

    typeToList = {"RNA": rna, "DNA": dna, "Binary": binary, "Protein": protein}

    @staticmethod
    def getAlphabet(alphabetType):
        return SupportedAlphabet.typeToList[alphabetType]


class EpistasisConstants:
    # Constants for classes of epistasis
    NO_EPISTASIS = 0
    MAGNITUDE = 1
    SIGN = 2
    RECIPROCAL_SIGN = 3

    # Dictionary to map the classes to string descriptions
    epiToDesc = {
        MAGNITUDE: "Magnitude epistasis",
        SIGN: "Sign epistasis",
        RECIPROCAL_SIGN: "Reciprocal sign epistasis",
        NO_EPISTASIS: "No epistasis"
    }

    @staticmethod
    def getDesciption(epiType):
        try:
            return EpistasisConstants.epiToDesc[epiType]
        except KeyError:
            return ""


class AnalysisConstants:
    # Constants representing analysis types
    ALL = 0
    LANDSCAPE = 1  # FIXME: Is this grouping really necessary? ...
    PEAKS = 2
    PATHS = 3
    EPISTASIS = 4
    ROBUSTNESS = 5
    EVOLVABILITY = 6
    ACCESSIBILITY = 7
    NEIGHBOR_ABUNDANCE = 8
    PHENOTYPIC_DIVERSITY = 9
    STRUCTURE = 10
    OVERLAP = 11

    # Dictionary to map constants to string descriptors
    # TODO: Look into whether 'ALL' and 'LANDSCAPE' should be included
    #		in the following dict ...
    analysisToDesc = {PEAKS: "Peaks",
                      PATHS: "Paths",
                      EPISTASIS: "Epistasis",
                      ROBUSTNESS: "Robustness",
                      EVOLVABILITY: "Evolvability",
                      ACCESSIBILITY: "Accessibility",
                      NEIGHBOR_ABUNDANCE: "Neighbor Abundance",
                      PHENOTYPIC_DIVERSITY: "Diversity Index",
                      STRUCTURE: "Structure",
                      OVERLAP: "Overlap"}

    @staticmethod
    def getAnalysisTypes():
        return Utils.reverseDict(AnalysisConstants.analysisToDesc)


class ErrorCodes:
    # Generic unknown error
    UNKNOWN_ERROR = 5000

    # Parsing errors
    UNKNOWN_PARSING_ERROR = 400
    INCONSISTENT_HEADER = 500
    MISSING_VALUE = 501
    BAD_SCORE_FORMAT = 502
    BAD_DELTA_FORMAT = 503
    INCONSISTENT_SEQ_LEN = 504
    ALPHABET_TYPE_MISMATCH = 505
    NO_USEABLE_SCORES = 506

    # File I/O errors
    CANNOT_WRITE_TO_FILE = 550
    CANNOT_CREATE_DIRECTORY = 551

    # Analysis errors
    NOT_ENOUGH_REPS_OLAP = 700

    # Error code to description dict
    errCodeToDesc = {
        UNKNOWN_ERROR: "Something went wrong while performing analyses",
        UNKNOWN_PARSING_ERROR: "Something went wrong during input file parsing",
        INCONSISTENT_HEADER: "Input file parsing error - Column headers are not consistent with specification",
        MISSING_VALUE: "Input file parsing error - Missing value encountered in input file",
        BAD_SCORE_FORMAT: "Input file parsing error - Score value is not in the supported format",
        BAD_DELTA_FORMAT: "Input file parsing error - Delta value is not in the supported format",
        INCONSISTENT_SEQ_LEN: "Input file parsing error - Inconsistent genotype length encountered. All genotypes must be of equal length",
        ALPHABET_TYPE_MISMATCH: "Input file parsing error - Genotype consists of at least one letter not in the selected alphabet type",
        NO_USEABLE_SCORES: "Input file parsing error - No genotypes found with score values greater than",
        NOT_ENOUGH_REPS_OLAP: "Analysis error - Overlap computation can only be performed if there are least two phenotypes that have genotypes with Score values greater than Tau",
        CANNOT_WRITE_TO_FILE: "Could not write to file",
        CANNOT_CREATE_DIRECTORY: "Error while trying to create directory"
    }

    @staticmethod
    def getErrDescription(errCode):
        try:
            return ErrorCodes.errCodeToDesc[errCode]
        except:
            return ""
