# -*- coding: utf-8 -*-
"""
Created on Sun Mar 15 17:18:32 2020

@author: Sophie
"""

"""
Alternative method:

Utilise dictionaries, thusly:

enum_dict = {
    "KEY" : 0
    "OPTION' : 1
}

Key -> Value is looked up as is standard for dictionaries
Value -> Key is looked up through {v:k for k, v in dict.items()}[value]
This only works if all the values are unique
"""

from neticapy import neticaerror as err

QUERY_ns = -1
_MESG_LEN_ns = 600

def set_error_severity(severity):
    if severity == None:
        return 0
    if isinstance(severity, int):
        return severity
    if not isinstance(severity, str):
        raise TypeError('A string or integer is required (got type {})'.format(type(severity).__name__))
    if severity == "":
        return 0
    elif severity == "NOTHING":
        return 1
    elif severity == "REPORT":
        return 2
    elif severity == "NOTICE":
        return 3
    elif severity == "WARNING":
        return 4
    elif severity == "ERROR":
        return 5
    elif severity == "XXX":
        return 6
    else:
        mesg = 'Severity can be one of "NOTHING", "REPORT", "NOTICE", "WARNING", "ERROR", or "XXX".'
        err._raise_netica_error(6505, mesg)
        
def get_error_severity(severity):
    if severity == 1:
        return "NOTHING"
    if severity == 2:
        return "REPORT"
    if severity == 3:
        return "NOTICE"
    if severity == 4:
        return "WARNING"
    if severity == 5:
        return "ERROR"
    if severity == 6:
        return "XXX"
    
#flag
def set_error_condition(errorcondition):
    if errorcondition == None:
        return 0
    if isinstance(errorcondition, int):
        return errorcondition
    if not isinstance(errorcondition, str):
        raise TypeError('A string or integer is required (got type {})'.format(type(errorcondition).__name__))
    if errorcondition == "":
        return 0
    enum = 0
    indicator = False
    if "OUT_OF_MEMORY" in errorcondition:
        enum += 0x08
        indicator = True
    if "USER_ABORTED" in errorcondition:
        enum += 0x20
        indicator = True
    if "FROM_WRAPPER" in errorcondition:
        enum += 0x40
        indicator = True
    if "FROM_DEVELOPER" in errorcondition:
        enum += 0x80
        indicator = True 
    if "INCONS_FINDING" in errorcondition:
        enum += 0x200
        indicator = True
    if indicator:
        return enum 
    else:
        mesg = 'Error condition must be some combination of "OUT_OF_MEMORY", "USER_ABORTED", "FROM_WRAPPER", "FROM_DEVELOPER", or "INCONS_FINDING".'
        err._raise_netica_error(6506, mesg)

#flag
def get_error_condition(errorcondition):
    conditions = []
    if errorcondition & 0x08 == 0x08:
        conditions.append("OUT_OF_MEMORY")
    if errorcondition & 0x20 == 0x20:
        conditions.append("USER_ABORTED")
    if errorcondition & 0x40 == 0x40:
        conditions.append("FROM_WRAPPER")
    if errorcondition & 0x80 == 0x80:
        conditions.append("FROM_DEVELOPER")
    if errorcondition & 0x200 == 0x200:
        conditions.append("INCONS_FINDING")
    if conditions:
        conditions_str = ", ".join(conditions)
        return conditions_str

def set_node_type(nodetype):
    if nodetype == None:
        return 0
    if isinstance(nodetype, int):
        return nodetype
    if not isinstance(nodetype, str):
        raise TypeError('A string or integer is required (got type {})'.format(type(nodetype).__name__))
    if nodetype == "":
        return 0
    elif nodetype == "CONTINUOUS":
        return 1
    elif nodetype == "DISCRETE":
        return 2
    elif nodetype == "TEXT":
        return 3
    else:
        mesg = 'Nodetype must be one of "CONTINUOUS", "DISCRETE", or "TEXT".'
        err._raise_netica_error(6507, mesg)

def get_node_type(nodetype):
    if nodetype == 1:
        return "CONTINUOUS"
    if nodetype == 2:
        return "DISCRETE"
    if nodetype == 3:
        return "TEXT"

def set_node_kind(nodekind):
    if nodekind == None:
        return 0
    if isinstance(nodekind, int):
        return nodekind
    if not isinstance(nodekind, str):
        raise TypeError('A string or integer is required (got type {})'.format(type(nodekind).__name__))
    if nodekind == "":
        return 0
    elif nodekind == "NATURE":
        return 1
    elif nodekind == "CONSTANT":
        return 2
    elif nodekind == "DECISION":
        return 3
    elif nodekind == "UTILITY":
        return 4
    elif nodekind == "DISCONNECTED":
        return 5
    elif nodekind == "ADVERSARY":
        return 6
    else:
        mesg = 'Nodekind must be one of "NATURE", "CONSTANT", "DECISION", "UTILITY", "DISCONNECTED", or "ADVERSARY".'
        err._raise_netica_error(6508, mesg)

def get_node_kind(nodekind):
    if nodekind == 1:
        return "NATURE"
    if nodekind == 2:
        return "CONSTANT"
    if nodekind == 3:
        return "DECISION"
    if nodekind == 4:
        return "UTILITY"
    if nodekind == 5:
        return "DISCONNECTED"
    if nodekind == 6:
        return "ADVERSARY"

#flag
def set_reading_option(readingoption):
    if readingoption == None:
        return 0
    if isinstance(readingoption, int):
        return readingoption
    if not isinstance(readingoption, str):
        raise TypeError('A string or integer is required (got type {})'.format(type(readingoption).__name__))
    if readingoption == "":
        return 0
    enum = 0
    indicator = False
    if "NO_VISUAL_INFO" in readingoption:
        enum += 0
        indicator = True
    elif "NO_WINDOW" in readingoption:
        enum = 0x10
        indicator = True
    elif "MINIMIZED_WINDOW" in readingoption:
        enum = 0x30
        indicator = True
    elif "REGULAR_WINDOW" in readingoption:
        enum = 0x70
        indicator = True
    if "IGNORE_FINDINGS" in readingoption:
        enum += 0x100
        indicator = True
    if indicator:
        return enum 
    else:
        mesg = 'Reading option must be some combination of "NO_VISUAL_INFO", "NO_WINDOW", "MINIMIZED_WINDOW", "REGULAR_WINDOW", or "IGNORE_FINDINGS".'
        err._raise_netica_error(6509, mesg)
  
#flag
def get_reading_option(readingoption):
    options = []
    if readingoption & 0 == 0:
        options.append("NO_VISUAL_INFO")
    if readingoption & 0x10 == 0x10:
        options.append("NO_WINDOW")
    if readingoption & 0x30 == 0x30:
        options.append("MINIMIZED_WINDOW")
    if readingoption & 0x70 == 0x70:
        options.append("REGULAR_WINDOW")
    if options:
        options_str = ", ".join(options)
        return options_str

def set_learning_method(learningmethod):
    if learningmethod == None:
        return 0
    if isinstance(learningmethod, int):
        return learningmethod
    if not isinstance(learningmethod, str):
        raise TypeError('A string or integer is required (got type {})'.format(type(learningmethod).__name__))
    if learningmethod == "":
        return 0
    elif learningmethod == "COUNTING":
        return 1
    elif learningmethod == "MINDEP":
        return 2
    elif learningmethod == "EM":
        return 3
    elif learningmethod == "GRADIENT_ASCENT":
        return 4
    else:
        mesg = 'Learning method must be one of "COUNTING", "EM", "MINDEP" or "GRADIENT_ASCENT".'
        err._raise_netica_error(6510, mesg)

def get_learning_method(learningmethod):
    if learningmethod == 1:
        return "COUNTING"
    if learningmethod == 2:
        return "MINDEP"
    if learningmethod == 3:
        return "EM"
    if learningmethod == 4:
        return "GRADIENT_ASCENT"

def set_sampling_method(samplingmethod):
    if samplingmethod == None:
        return 0
    if isinstance(samplingmethod, int):
        return samplingmethod
    if not isinstance(samplingmethod, str):
        raise TypeError('A string or integer is required (got type {})'.format(type(samplingmethod).__name__))
    if samplingmethod == "":
         return 0
    elif samplingmethod == "DEFAULT":
        return 0
    elif samplingmethod == "JOIN_TREE":
        return 1
    elif samplingmethod == "FORWARD":
        return 2
    else:
        mesg = 'Sampling method must be one of "DEFAULT", "JOIN_TREE", or "FORWARD".'
        err._raise_netica_error(6511, mesg)

def get_sampling_method(samplingmethod):
    if samplingmethod == 0:
        return "DEFAULT"
    if samplingmethod == 1:
        return "JOIN_TREE"
    if samplingmethod == 2:
        return "FORWARD"

#flag
def set_sensv(sensv):
    if sensv == None:
        return 0
    if isinstance(sensv, int):
        return sensv
    if not isinstance(sensv, str):
        raise TypeError('A string or integer is required (got type {})'.format(type(sensv).__name__))
    if sensv == "":
        return 0
    enum = 0
    indicator = False
    if "ENTROPY" in sensv:
        enum += 0x02 
        indicator = True
    if "VARIANCE_OF_REAL" in sensv:
        enum += 0x104
        sensv = sensv.replace("VARIANCE_OF_REAL", "")
        indicator = True
    if "REAL" in sensv: 
        enum += 0x04
        indicator = True
    if "VARIANCE" in sensv: 
        enum += 0x100
        indicator = True  
    if indicator:
        return enum
    else:
        mesg = 'what_calc must be some combination of "ENTROPY", "REAL", "VARIANCE", or "VARIANCE_OF_REAL".'
        err._raise_netica_error(6512, mesg)
        
#flag
def get_sensv(sensv):
    options = []
    if sensv & 0x02 == 0x02:
        options.append("ENTROPY")
    if sensv & 0x04 == 0x04:
        options.append("REAL")
    if sensv & 0x100 == 0x100:
        options.append("VARIANCE")
    if sensv & 0x104 == 0x104:
        options.append("VARIANCE_OF_REAL")
    if options:
        options_str = ", ".join(options)
        return options_str

def set_case_position(caseposition):
    if caseposition == None:
        return 0
    if isinstance(caseposition, int):
        return caseposition
    if not isinstance(caseposition, str):
        raise TypeError('A string or integer is required (got type {})'.format(type(caseposition).__name__))
    if caseposition == "":
        return 0
    elif caseposition == "FIRST_CASE":
        return -15
    elif caseposition == "NEXT_CASE":
        return -14
    elif caseposition == "NO_MORE_CASES":
        return -13
    else:
        mesg = 'Case Position must be one of "FIRST_CASE", "NEXT_CASE", or "NO_MORE_CASES".'
        err._raise_netica_error(6513, mesg)

def get_case_position(caseposition):
    if caseposition == -15:
        return "FIRST_CASE"
    if caseposition == -14:
        return "NEXT_CASE"
    if caseposition == -13:
        return "NO_MORE_CASES"

def set_argument_checking(argumentchecking):
    if argumentchecking == None:
        return 0
    if isinstance(argumentchecking, int):
        return argumentchecking
    if not isinstance(argumentchecking, str):
        raise TypeError('A string or integer is required (got type {})'.format(type(argumentchecking).__name__))
    if argumentchecking == "":
        return 0
    elif argumentchecking == "NO_CHECK":
        return 1
    elif argumentchecking == "QUICK_CHECK":
        return 2
    elif argumentchecking == "REGULAR_CHECK":
        return 3
    elif argumentchecking == "COMPLETE_CHECK":
        return 4
    elif argumentchecking == "QUERY_CHECK":
        return -1
    else:
        mesg = 'Argument Checking must be one of "NO_CHECK", "QUICK_CHECK", "REGULAR_CHECK", "COMPLETE_CHECK" or "QUERY_CHECK".'
        err._raise_netica_error(6514, mesg)

def get_argument_checking(argumentchecking):
    if argumentchecking == 1:
        return "NO_CHECK"
    if argumentchecking == 2:
        return "QUICK_CHECK"
    if argumentchecking == 3:
        return "REGULAR_CHECK"
    if argumentchecking == 4:
        return "COMPLETE_CHECK"
    if argumentchecking == -1:
        return "QUERY_CHECK"

# if an option >= 0 is added, change the check in get_state_named
def set_state(state):
    if state == None:
        return 0
    if isinstance(state, int):
        return state
    if not isinstance(state, str):
        raise TypeError('A string or integer is required (got type {})'.format(type(state).__name__))
    if state == "":
        return 0
    elif state == "EVERY_STATE":
        return -5
    elif state == "IMPOSS_STATE":
        return -4
    elif state == "UNDEF_STATE":
        return -3
    else:
        mesg = 'State must be one of "EVERY_STATE", "IMPOSS_STATE", or "UNDEF_STATE".'
        err._raise_netica_error(6515, mesg)

def get_state(state):
    if state == -5:
        return "EVERY_STATE"
    if state == -4:
        return "IMPOSS_STATE"
    if state == -3:
        return "UNDEF_STATE"

def set_finding(finding):
    if finding == None:
        return 0
    if isinstance(finding, int):
        return finding
    if not isinstance(finding, str):
        raise TypeError('A string or integer is required (got type {})'.format(type(finding).__name__))
    if finding == "":
        return 0
    elif finding == "NEGATIVE_FINDING":
        return -7
    elif finding == "LIKELIHOOD_FINDING":
        return -6
    elif finding == "NO_FINDING":
        return -3
    else:
        mesg = 'Finding must be one of "NEGATIVE_FINDING", "LIKELIHOOD_FINDING", or "NO_FINDING".'
        err._raise_netica_error(6516, mesg)

def get_finding(finding):
    if finding == -7:
        return "NEGATIVE_FINDING"
    if finding == -6:
        return "LIKELIHOOD_FINDING"
    if finding == -3:
        return "NO_FINDING"