/* The SectionRef built in object is not sufficient for what is needed from a Section object in the
   data structure. Therefore, an alternative object, Section, is defined. For some reason, Neuron
   supports recursion only to a limited extent, therefore, a tedious procedure for scanning the
   tree and identifying individual branches while creating Section objects that match the SectionRef
   tree arrangement is carried out.
*/


/* Querry examples:
   ===============
   Branch
   ------
   The name of Section (num 2) of a selected Branch (num 33) -
   	tree.branchlist.object(33).seclist.object(2).sec.sec
   Parent/Child
   ------------
   The name of the child (num 0) of the selected Branch's (above) parent -
   	tree.branchlist.object(33).seclist.object(2).parent.childlist.object(0).sec.sec
*/

//////////////////////////////////////////////////////////////////////////////////////////////
//                                      Section Functions
//                                      =================
//////////////////////////////////////////////////////////////////////////////////////////////


// create a list of all the root sections (who's parents are soma sections)
proc create_root_list() {
	NUMROOT=0
	objref sec,rootlist
	root_list=new List()
	subtree=new Vector()
	forsec dendrite_basal_section_list {		  // create list of root sections
		   root_section_list(0)
	}
	forsec dendrite_apical_section_list {		  // create list of root sections
		   root_section_list(1)
	}
}

proc root_section_list() { local subtree_type
	 subtree_type=$1
	 sec=new SectionRef()  // note: sec here is a regular SectionRef
	 if (sec.has_parent) {
		sec.parent {
			if (issection(MORPH.soma_name.object(0).s)) {
		   		sec.sec root_list.append(new Root())
		   		subtree.append(subtree_type)
		   		NUMROOT+=1
			}
		}
	 }
}

// Scan the tree looping through child sections of the roots (depth first search)
proc create_tree() { local id,r
	objref node,rnode,cnode,nodelist,tree
	objref branch
	nodelist=new List()
	tree=new Tree()
	for r=0,NUMROOT-1 {
		root_list.object(r).sec.sec {
			rnode=new Node(1) // 1=root
			nodelist.append(rnode) // add the new Node to the seclist
			while (rnode.status) { // as long as current root is branchable
				// create a candidate branch, initialize first item on the seclist to be the current root
				branch=new Branch(subtree.x(r))
				cont=1 // continue flag
				node=rnode
				while (cont) { // loop the Nodes within a candidate branch
					// leaf => accepted branch
					// =======================
					if (node.leaf) { // a leaf has been reached (leaves already have status set to zero)
					   	branch.Node_to_Branch(node) // add leaf to end of branche's Node list
						tree.add_branch(branch) // add the branch to the accepted branch list
						// scan accepted branch and append the Section branchlists
						cont=0
						// decrease parent's child counter (as long as parent is not a root)
						if (!node.root) {
							node.parent.childcount+=1
						} else { // special case of root being also a leaf
							node.status=0
						}	
					// either on the way to a potential leaf or an unbranchable node
					// ===============================================================
					} else {
						// branchable Section
						// ==================
						if (node.status) {
							branch.Node_to_Branch(node) // add branchable Node to branch's Section list
							id=node.childcount
							if (id<node.sec.nchild) { // turn to node's next child if it still has any
								node.sec.child(id) {
									if (node.childstatus.x(id)) { // use existing child Node
										cnode=node.childlist.object(id)
									} else { // create a new child Node
										cnode=new Node(0) // 0=non root Node
										nodelist.append(cnode)
										cnode.parent=node // two directional pointers
										node.childlist.append(cnode)
										node.childstatus.x(id)=1 // flag - id child has been created
									}
									node=cnode
								}
							} else { // if no more children are left
								node.status=0 // switch Node off
								if (!node.root) { node.parent.childcount+=1 }
								cont=0 // try a new branch
							}
							// unbranchable Section
							// ==================== 
						} else { cont=0	}
					}
				}
			}
		}
	}
	NUMNODE=nodelist.count()
}

// For each Node create a pointer list to the branches it is included in
proc Section_to_Branch() { local i,j,n
	 NUMBRANCH=tree.numbranch
	 for i=0,NUMBRANCH-1 {
	 	 branch=tree.branchlist.object(i)
	 	 n=branch.length
		 for j=0,n-1 {
		 	branch.nodelist.object(j).add_branch(branch)
		 }
	 }
	 BRANCH=tree.branchlist.object(SLCT_BRANCH)
}


// ===================================================================================

proc branch_manual_select() { local i, found, ifound
	found = 0
	for i = 0, tree.branchlist.count - 1 {
		if (BRANCHmanual == tree.branchlist.object(i).id) {
			found = 1
			ifound = i
			break
		}
	}
	if (found) {
		branch_select(ifound)
	} else {
		BRANCHmanual = BRANCH.id
	}	
}

proc branch_select() {
	 SLCT_BRANCH=$1
	 BRANCH=tree.branchlist.object(SLCT_BRANCH)
	 BRANCHmanual = BRANCH.id
	 SLCT_LOGSYN=0
	 LOGSYN=BRANCH.logsynlist.object(SLCT_LOGSYN)
	 LOGSYNmanual = LOGSYN.id
	 browser_logsynlist_update()
	 plot_branch_logsyn()
 	tree.branchlist.select(SLCT_BRANCH)
}

proc logsyn_manual_select() { local i, found, ifound
	found = 0
	for i = 0, BRANCH.logsynlist.count - 1 {
		if (LOGSYNmanual == BRANCH.logsynlist.object(i).id) {
			found = 1
			ifound = i
			break
		}
	}
	if (found) {
		logsyn_select(ifound)
	} else {
		LOGSYNmanual = LOGSYN.id
	}	
}

proc logsyn_select() { local input
	input=$1
	if (input>=0) {
		SLCT_LOGSYN=$1
		LOGSYN=BRANCH.logsynlist.object(SLCT_LOGSYN)
		LOGSYNmanual = LOGSYN.id
		plot_branch_logsyn()
		sprint(SLCT_LOGSYN_name,"%d syn(s) %5.4g um",LOGSYN.numsyns,LOGSYN.dist)
	}
	browser_logsynlist.select(SLCT_LOGSYN)
}

proc browser_logsynlist_update() { local i
	 browser_logsynlist.remove_all()
	 for i=0,BRANCH.numlogsyn-1 {
//	 	 browser_logsynlist.append(new Name(BRANCH.logsynlist.object(i).logsyn_name))
	 	 browser_logsynlist.append(new String(BRANCH.logsynlist.object(i).logsyn_name))
	 }
	 browser_logsynlist.select(SLCT_LOGSYN)
	sprint(SLCT_LOGSYN_name,"%d syn(s) %5.4g um",LOGSYN.numsyns,LOGSYN.dist)
}