if (name_declared("pkgversions") != 4 ) {  execute("strdef pkgversions") }
sprint(pkgversions,"%sSegment = $Revision: 1.11 $, ",pkgversions)

/*

SegmentRef

sect segref = new SegmentRef(x)

creates SegmentRef segref that refers to a segment x along the section sect.

The SegmentRef segref has two public variables:

segref.secref - the SectionRef referring to sect
segref.x      - the point x that locates the segment along sect

*/

begintemplate SegmentRef
public secref, x, name, print_distance
objref secref

proc init() {
    secref = new SectionRef()
    x = $1
}

proc name() {
    secref.sec print secname(), "(", x, ")"
}

proc print_distance() {
    secref.sec printf("%s, %f, %f\n", secname(), x, distance(x))
}

endtemplate SegmentRef

/*

SegmentRefList

segreflist = new SegmentRefList()

initialises a new SegmentRefList segreflist.

sect segreflist.append_internal_segments_from_section()

Appends all of the internal (i.e. where x is not 0 or 1) segments from
the currently-accessed section sect to the SegmentRefList segreflist.

segreflist.append_internal_segments_from_seclist(SectionList seclist)

Appends all of the internal (i.e. where x is not 0 or 1) segments from
the SectionList seclist to the SegmentRefList segreflist.

sect segreflist.append_nonzero_segments_from_section()
segreflsit.append_nonzero_segments_from_seclist(SectionList seclist)

The same as the append_internal_segments commands except that segments
with x=1 are also appended.

The following public variable is useful:

segreflist.srl - the List of SegmentRefs.  Can be accessed using List
                 member functions

segreflist.parents(Vector parent_indicies)

The ith element of parent_indicies contains the index of the
SegmentRef in segreflist.srl that is nearest to and ancestral to the
ith SegmentRef in the list.  Useful for certain kinds of plot.

*/


begintemplate SegmentRefList

// Public variables

public srl
objref srl

// Functions

public append_segments_from_section
public append_segments_from_seclist
public append_internal_segments_from_section
public append_internal_segments_from_seclist
public append_nonzero_segments_from_section
public append_nonzero_segments_from_seclist
public append_segment
public append_segments_from_segreflist
public display
public print_distance
public parents
public count
public find_ind_of_segment

// Private variables

objref bestseg

// Function definitions

proc init() { 
    srl = new List()
    verbose = 0
}

proc append_segments_from_section() { local x 
    if (numarg() == 1) {
        srl.append(new SegmentRef($1))
    } else {
        for (x) {
            srl.append(new SegmentRef(x))
        }
    }
}

proc append_segments_from_seclist() { local x
    forsec $o1 {
        append_segments_from_section()
    }
}

proc append_internal_segments_from_section() { local x 
    for (x) {
        if (( x != 0 ) && ( x != 1)) {
            srl.append(new SegmentRef(x))
        }
    }
}

proc append_internal_segments_from_seclist() { 
    forsec $o1 {
        append_internal_segments_from_section()
    }
}

proc append_nonzero_segments_from_section() { local x 
    for (x) {
        if ( x != 0 )  {
            srl.append(new SegmentRef(x))
        }
    }
}

proc append_nonzero_segments_from_seclist() { 
    forsec $o1 {
        append_nonzero_segments_from_section()
    }
}

proc append_segment() {
    srl.append($o1)
}

proc append_segments_from_segreflist() {
    for i=0, $o1.srl.count()-1 {
        srl.append($o1.srl.object(i))
    }
}

proc display() {
    for i=0,srl.count()-1 {
        srl.object(i).secref.sec printf("Segment %d: %s, %f\n", i, secname(), srl.object(i).x)
    }
}

proc print_distance() {
    for i=0,srl.count()-1 {
        srl.object(i).print_distance()
    }
}


proc parents() { local i, j, x, bsi
    $o1 = new Vector(srl.count())
    for i = 0, srl.count()-1 {
        // Access the section
        srl.object(i).secref.sec {
            // Refer to the best matching segment so far
            // bestseg = new SegmentRef(1)
            bsi = i                     // Best segment index
            // Look through all members of list for a parent
            for j = 0, srl.count()-1 {
                
                if (verbose) {
                    if (( i <=3) && (j <= 3) ) {
                        print i , j, bsi
                    }
                }
                
                // Igore if same as i
                if ( i == j ) {
                    continue
                }
                // Is segment j in the currently accessed section?
                if ( srl.object(j).secref.is_cas() ) {
                    // If it segment j has lower x it might be parent
                    if ( srl.object(j).x < srl.object(i).x ) {
                        // If the best segment isn't in this section it 
                        // should be or if it's not been set yet we should
                        // set it
                        if ( (!srl.object(bsi).secref.is_cas()) || (bsi == i) ) {
                            bsi = j 
                        } else {
                            if ( srl.object(bsi).x < srl.object(j).x ) {
                                // If it is, then only update if its x is
                                // lower than j's
                                bsi = j
                            }
                        }
                    }
                }
                // Is segment j in the parent section of i?
                // First check that section i has a parent (it might be the soma)
                // and that the best section isn't the current one
                if ( srl.object(i).secref.has_parent() && (!srl.object(bsi).secref.is_cas() || (bsi == i) )) {
                    srl.object(i).secref.parent {
                        if ( srl.object(j).secref.is_cas() ) {
                            // If the best segment isn't in this section it should be
                            if ( !srl.object(bsi).secref.is_cas() ) {
                                bsi = j 
                            } else {
                                // If it is, then only update if its x is
                                // lower than j's
                                if ( srl.object(bsi).x < srl.object(j).x ) {
                                    bsi = j
                                }
                            }
                        }
                    }
                }
            }
            if (verbose) {
                srl.object(bsi).secref.sec print "parent:", bsi , " ", secname(), srl.object(bsi).x
                srl.object(i).secref.sec print "child:", i , " ", secname(), srl.object(i).x
            }
            $o1.x(i) = bsi
        }
    }
}

func count() {
    return srl.count()
}

//
// find_ind_of_segment(SegmentRef seg)
// Find the index of the SegmentRef seg in the SegmentRefList. If the x value of 
// SEG doesn't match precisely, pick the closest segment that does
func find_ind_of_segment() { local i, j, dx, bestdx, bestind localobj seg
    seg = $o1
    bestdx  = 1
    bestind = -1                        // This is the default value -- it means that the segment wasn't found
    // Access the argument segment
    seg.secref.sec {
        // Look at each member of the segreflist
        for j=0, srl.count()-1 {
            // See if the member of the segreflist refers to the same section as SEG
            if ((srl.object(j).secref.is_cas())) { 
                // If so, see how close the x-values are
                dx = abs(srl.object(j).x - seg.x)
                // If the index improves on the previous one, then set the 
                if (dx <= bestdx) {
                    bestind = j
                    bestdx = dx
                }
            }
        }
    }
    return(bestind)
}

endtemplate SegmentRefList