from neuron import h


def mech_names():
    """
    Retrieves the names of mechanisms available in the NEURON simulation environment.

    Returns:
        list: A list containing the names of mechanisms.
    """
    result = []
    mname = h.ref("str")
    mt = h.MechanismType(0)
    for i in range(int(mt.count())):
        mt.select(i)
        mt.selected(mname)
        result.append(mname[0])
    return result


def range_vars():
    """
    Retrieves the range variables associated with mechanisms available in the NEURON simulation environment.

    Returns:
        dict: A dictionary where keys are mechanism names and values are lists of corresponding range variable names.
    """
    result = {}
    for mech in mech_names():
        mt = h.MechanismStandard(mech, 0)
        result[mech] = []
        suffix = "_" + mech
        lensuffix = len(suffix)
        for i in range(int(mt.count())):
            mname = h.ref("")
            mt.name(mname, i)
            mname = mname[0]
            if mname[-lensuffix:] == suffix:
                mname = mname[:-lensuffix]
            result[mech].append(mname)
        if not result[mech]:
            del result[mech]
    return result


def mechs_present(sec):
    """
    Determines which mechanisms are present in a given NEURON section.

    Args:
        sec: NEURON section object.

    Returns:
        list: A list containing the names of mechanisms present in the section.
    """
    result = []
    for name in mech_names():
        if hasattr(sec(0.5), name):
            result.append(name)
    return result


def print_everything():
    """
    Prints the values of membrane potential and range variables for all segments and mechanisms in the NEURON simulation environment.
    """
    rvs = range_vars()
    for sec in h.allsec():
        my_mechs = mechs_present(sec)
        for seg in sec:
            print(repr(seg) + ".v", "=", seg.v)
            for mech in my_mechs:
                for rv in rvs[mech]:
                    if mech[-4:] != "_ion":
                        print(
                            repr(seg) + "." + mech + "." + rv,
                            "=",
                            seg.__getattribute__(mech).__getattribute__(rv),
                        )
                    else:
                        print(repr(seg) + "." + rv, "=", seg.__getattribute__(rv))


if __name__ == "__main__":
    soma = h.Section(name="soma")
    dend = h.Section(name="dend")
    soma.insert("hh")
    dend.insert("pas")
    soma.nseg = 3
    print_everything()