"""
Misc utility functions required by several modules in the ligpy program.
"""
import os

import numpy as np

from constants import GAS_CONST, MW

def set_paths():
    """
    Set the absolute path to required files on the current machine.

    Returns
    -------
    reactionlist_path     : str
                            path to the file `complete_reactionlist.dat`
    rateconstantlist_path : str
                            path to the file `complete_rateconstantlist.dat`
    compositionlist_path  : str
                            path to the file `compositionlist.dat`
    """
    module_dir = os.path.abspath(__file__).split('ligpy_utils')[0]
    reactionlist_path = module_dir + 'data/complete_reaction_list.dat'
    rateconstantlist_path = module_dir + 'data/complete_rateconstant_list.dat'
    compositionlist_path = module_dir + 'data/compositionlist.dat'
    return reactionlist_path, rateconstantlist_path, compositionlist_path


def get_specieslist(completereactionlist):
    """
    Make a list of all the molecular species involved in the kinetic scheme.

    Parameters
    ----------
    completereactionlist : str
                           the path to the `complete_reaction_list.dat` file

    Returns
    -------
    specieslist : list
                  a list of all the species in the kinetic scheme
    """
    specieslist = []
    for line in open(completereactionlist, 'r').readlines():
        for spec in line.split(','):
            # If the species has already been added to the list then move on.
            if spec.split('_')[1].split()[0] in specieslist:
                continue
            else:
                specieslist.append(spec.split('_')[1].split()[0])
    specieslist.sort()
    return specieslist


def get_speciesindices(specieslist):
    """
    Create a dictionary to assign an arbitrary index to each of the species in
    the kinetic scheme.

    Parameters
    ----------
    specieslist : list
                  a list of all the species in the model

    Returns
    -------
    speciesindices     : dict
                         a dictionary of arbitrary indices with the species
                         from specieslist as keys
    indices_to_species : dict
                         the reverse of speciesindices (keys are the indices
                         and values are the species)
    """
    speciesindices = {}
    index = 0
    for x in specieslist:
        speciesindices[x] = index
        index += 1
    indices_to_species = dict(zip(speciesindices.values(),
                                  speciesindices.keys()))
    return speciesindices, indices_to_species


def define_initial_composition(compositionlist, species):
    """
    Read the plant ID specified and define the initial composition of the
    lignin polymer in terms of the three model components (PLIGC, PLIGH,
    PLIGO).

    Parameters
    ----------
    compositionlist : str
                      the path of the `compositionlist.dat` file
    species         : str
                      the name of a lignin species that exists in the
                      `compositionlist.dat` file
    Returns
    -------
    pligc_0 : float
              The initial composition (mol/L) of PLIGC
    pligh_0 : float
              The initial composition (mol/L) of PLIGH
    pligo_0 : float
              The initial composition (mol/L) of PLIGO

    """
    for line in open(compositionlist, 'r').readlines():
        if line.split(',')[0] == species:
            # Initial compositions [mole fraction]
            pligc_mol = float(line.split(',')[1])
            pligh_mol = float(line.split(',')[2])
            pligo_mol = float(line.split(',')[3])
            # The weighted average molar mass of mixture [kg/mol]
            weighted_m = (301*pligc_mol + 423*pligh_mol + 437*pligo_mol)/1000
            # the density of the condensed phase [kg/L]
            density = 0.75
            # Initial compositions [mol/L]
            pligc_0 = density/weighted_m * pligc_mol
            pligh_0 = density/weighted_m * pligh_mol
            pligo_0 = density/weighted_m * pligo_mol
            break
    return pligc_0, pligh_0, pligo_0


def build_k_matrix(rateconsts):
    """
    Build a matrix of all the rate constant parameters (A, n, E).

    Parameters
    ----------
    rateconsts : str
                 the path to the file `complete_rateconstant_list.dat`

    Returns
    -------
    kmatrix : list
              a list of lists that defines a matrix.  Each entry in the list
              is A, n, E for a given reaction
    """
    num_lines = sum(1 for line in open(rateconsts))
    kmatrix = [None]*num_lines
    for i, line in enumerate(open(rateconsts, 'r').readlines()):
        kmatrix[i] = [line.split(' ')[0], line.split(' ')[1],
                      line.split(' ')[2].split()[0]]
    return kmatrix


def get_k_value(T, reaction_index, kmatrix):
    """
    Returns the value of the rate constant for a particular reaction index.

    Parameters
    ----------
    T              : float
                     temperature in Kelvin
    reaction_index : int
                     the index of the reaction for which you want the rate
    kmatrix        : list
                     the kmatrix generated by build_k_matrix()

    Returns
    -------
    k : float
        the value of the rate constant for the given reaction at the given
        temperature.
    """
    k = (eval(kmatrix[reaction_index][0]) *
         T**eval(kmatrix[reaction_index][1]) *
         np.exp(-1 * eval(kmatrix[reaction_index][2]) /(GAS_CONST * T)))
    return k


def get_k_value_list(T, kmatrix):