# Maps from NeuroML element space (Key) to python object space (value)
# The class names are essentially correct, the instance names need converting
# also attributes need fixing

import csv
import re
import sys

import lxml
import process_includes
from lxml import objectify

# In Python 3, it's io
try:
    from StringIO import StringIO
except ImportError:
    from io import StringIO
from config import variables

sys.setrecursionlimit(10000)


def remove_curlies(string):
    return re.sub("{.*}", "", string)


def to_lowercase_with_underscores(string):
    s1 = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", string)
    return re.sub("([a-z0-9])([A-Z])", r"\1_\2", s1).lower()


def to_camelback(string):
    string_list = list(string)
    i = 0
    for m in re.finditer("_", string):
        underscore_index = m.end()
        string_list[underscore_index - i] = string_list[
            underscore_index - i
        ].capitalize()
        string_list.pop(underscore_index - (1 + i))
        i += 1
    string = "".join(string_list)

    return str(string)


def traverse_doc(queue, rename):
    """Recursive function to traverse the nodes of a tree in
    breadth-first order.

    The first argument should be the tree root; children
    should be a function taking as argument a tree node and
    returning an iterator of the node's children.
    """
    if len(queue) > 0:
        node = queue.pop()
        children = node.getchildren()
        rename(node)
        queue = queue + children
        traverse_doc(queue, rename)
    else:
        return None


def pluralize(noun):
    if re.search("[sxz]$", noun):
        return re.sub("$", "es", noun)
    elif re.search("[^aeioudgkprt]h$", noun):
        return re.sub("$", "es", noun)
    elif re.search("[^aeiou]y$", noun):
        return re.sub("y$", "ies", noun)
    else:
        return noun + "s"


def _node_to_python(node):
    pluralize_flag = "maxOccurs" in node.attrib

    for attribute in node.attrib:
        nml_attribute = node.attrib.pop(attribute)
        if nml_attribute[0].islower():
            renamed_attribute = to_lowercase_with_underscores(nml_attribute)
            if pluralize_flag:
                renamed_attribute = pluralize(renamed_attribute)
            NameTable[nml_attribute] = renamed_attribute


filename = variables["schema_name"]

outfile = StringIO()
infile = open(filename, "r")

process_includes.process_include_files(infile, outfile, inpath=filename)
infile.close()
outfile.seek(0)
doc = objectify.parse(outfile)
root = doc.getroot()
queue = [root]

NameTable = {}

traverse_doc(queue, _node_to_python)

# filtering routine, need to get a better way to extract these, asked on Stack Overflow
import keyword

disallowed_keywords = keyword.kwlist
for keyword in disallowed_keywords:
    try:
        NameTable.pop(keyword)
    except:
        pass

NameTable["morphology"] = "morphology"  # overriding change to
# "morphologies" because it only applies outside of a cell - not a very
# elegant solution
NameTable["gateHHtauInf"] = "gate_hh_tau_infs"
NameTable["ionChannelHH"] = "ion_channel_hh"
NameTable["gateHHrates"] = "gate_hh_rates"
NameTable["gateHHtauInf"] = "gate_hh_tau_infs"

NameTable["ionChannel"] = "ion_channel"
NameTable["ionChannelHH"] = "ion_channel_hhs"


NameTable["basePyNNCell"] = "basePyNNCell"
NameTable["basePyNNIaFCell"] = "basePyNNIaFCell"
NameTable["basePyNNIaFCondCell"] = "basePyNNIaFCondCell"
NameTable["tau_syn_E"] = "tau_syn_E"
NameTable["tau_syn_I"] = "tau_syn_I"

NameTable["e_rev_E"] = "e_rev_E"
NameTable["e_rev_I"] = "e_rev_I"
NameTable["e_rev_Na"] = "e_rev_Na"
NameTable["e_rev_K"] = "e_rev_K"

NameTable["gbar_K"] = "gbar_K"
NameTable["gbar_Na"] = "gbar_Na"

NameTable["delta_T"] = "delta_T"

NameTable["IF_curr_alpha"] = "IF_curr_alpha"
NameTable["IF_curr_exp"] = "IF_curr_exp"
NameTable["IF_cond_alpha"] = "IF_cond_alpha"
NameTable["IF_cond_exp"] = "IF_cond_exp"

NameTable["extracellularProperties"] = "extracellular_properties"
NameTable["intracellularProperties"] = "intracellular_properties"
NameTable["biophysicalProperties"] = "biophysical_properties"

print("NameTable is as follows:")
print(NameTable)

print("Saving NameTable to csv file")
writer = csv.writer(open("name_table.csv", "w"))
for key, value in NameTable.items():
    writer.writerow([key, value])

print("Saving name changes table to csv file")
changes_writer = csv.writer(open("changed_names.csv", "w"))
for key in NameTable:
    value = NameTable[key]
    if key != value:
        changes_writer.writerow([key, value])
