D__TPOINTLISTTHOC = 1
//see help file in neuron extention help pages (wiki)
// https://bbpteam.epfl.ch/wiki/index.php/NE:TPointList

begintemplate TPointList
	public append,each_point,count,sclst,point,points,access_,mark,each_point_var
	public setrand_distance
	objref sclst,x,null,this,rnd,marklist,sl,NULL,sec_list
	strdef classname,tmp,style
	public classname,loc,setrand,relocate,printf,total_l,x,mark1,filter_by_distance
	public setrand_descrete, relocate_descrete,get_random_point,point,secname_,sec_list
	
	proc init(){
		classname="TPointList"
		sclst = new List()
		sec_list = new SectionList()
		x = new Vector()
		SPLIT = 0 //by default it will be only the local list
		gid = -1 //by default points do not have to belong to the same cell.
		if(numarg()>0) gid = $1
		if(numarg()>1) SPLIT = $2 //you will be able to set it to complete by the Manager objects
        
	}

	obfunc append(){local j localobj pl,sl
		//need to push the currect sect, hopefully you are not one of them.ion into the section stack
		if(numarg()==1){
			if(argtype(1)==0){
				x.append($1)
				sclst.append(new SectionRef())
			}else{
				sl = $o1.sclst
				//this assumes that all sections exists
				for j=0, sl.count - 1 {
					sclst.append(sl.o(j))//we do not mind to reference the existing object
					x.append($o1.x.x[j])
				}
			}
			sec_list.append()
		//python style address. 	
		}else{
			sprint(tmp,"%s {%s.append(%g) \n %s.sec_list.append()}",$s1,this,$2,this)
			execute(tmp)
			x.append($2)
		}
		return this //for chaning 
	}
		
	iterator each_point(){local i
		for i=0, sclst.count-1{
			if(sclst.o(i).exists) {
				sclst.o(i).sec{
					$&1 = x.x[i]
					iterator_statement
				}
			}else{
				if(SPLIT){
					$&1 = -1 //Prevent using this number as a section loc(x)
					iterator_statement
				}
			}
		}
	}
	
	
	
	//from here on some utility functions which make the use of this class more convinient
	iterator point(){
		sclst.o($1).sec{
			$&2 = x.x[$1]
			iterator_statement
		}
	}
	
	//use points, it make more sense to use it this way.s
	iterator points(){local i
		for i=2, numarg() sclst.o($i).sec{
			$&1 = x.x[$i]
			iterator_statement
		}
	}
	
	
	proc loc(){
		sclst.o($2).sec $o1.loc(x.x[$2])
	}
	
	
	func count(){ 
		return sclst.count 
	}
	
	
	func access_(){
		sclst.o($1).sec sprint(tmp,"access %s",secname())
		execute(tmp)
		return x.x[$1]
	}

	proc mark(){local x,color,size localobj m
		{color = 1 style = "O" size = 6}
		if(numarg()>1) color = $2
		if(numarg()>2) style = $s3	
		if(numarg()>3) size = $4
		if(marklist != NULL) for x=0,marklist.count - 1  $o1.point_mark_remove(marklist.o(x))
		marklist = new List() //kill the old lists
		
		for each_point(&x) {
			m = new PointProcessMark(x)
			marklist.append(m)//so they will not disappear with refresh
			$o1.point_mark(m,color,style,size)
		}
	}
	proc mark1(){local x,color,size localobj m
		{color = 1 style = "O" size = 6}
		if(numarg()>2) color = $3
		if(numarg()>3) style = $s4	
		if(numarg()>4) size = $5
		marklist = new List() //kill the old lists
		
		for point($2,&x) {
			m = new PointProcessMark(x)
			marklist.append(m)//so they will not disappear with refresh
			$o1.point_mark(m,color,style,size)
		}
	}
	
	proc setrand(/*SectionList,point_count[,randobj]*/){local tl,l,i,k localobj vx
	//same seed every time - very important!!!! unless you use a stream
		rnd = new Random(123) 
		sl = $o1  //set the class level object
		i = 1 
		l = k = tl = 0		
		if(numarg()>1) i = $2
		if(numarg()>2)rnd = $o3
		vx = new Vector(i)
		forsec sl tl+=L //get the total length of the section list
		total_l = tl
		rnd.uniform(0,tl)
		vx.setrand(rnd).sort()
		vx.append(1e80)//l will never be bigger than this value
		//note that no matter how many points there are, I am iterating only
		// once over section list!
		forsec sl {
			l+=L
			while(l>=vx.x[k]) {//go over all the possible in this section
				append(1 - (l-vx.x[k])/L)
				k+=1
			}
			if(k==i) break
		}
	}

	
	
	proc setrand_distance(/*SectionList,distance,points_count,[,randobj]*/){local l,k,x,min_dist,points_countpoints_count
	//same seed every time - very important!!!! unless you use a stream
	// slow, but get you all the synapses above some distance from 
	// the last activation of distance(0) function
		distance()
		rnd = new Random(123) 
		sl = $o1  //set the class level object
		min_dist = $2
		points_count = 1 
		l = k = total_l = 0		
		if(numarg()>2) points_count = $3
		if(numarg()>3)rnd = $o4
		forsec sl total_l+=L //get the total length of the section list
		total_l = total_l
		rnd.uniform(0,total_l) //select a random point
		while(k<points_count){
			d = rnd.repick()
			l = 0
			//fprint ("\r%d synapses" , k)
			
			forsec sl {
				if(d > l && d < l + L){ //point is in this section
					x = (d - l) / L // x posibion on the section 
					dist = distance(x)
					if(dist > min_dist){//discard every point below dist_min.
						append(x)
						k+=1
					}
					break
				}
				l = l + L
			}
		}
	}
	func get_random_point(/*[randobj]*/){local tl,l,i,k,x localobj vx
	//same seed every time - very important!!!! unless you use a stream
		l = k = tl = 0		
		rnd = $o1
		for each_point(&x) tl += L/nseg
		rnd.uniform(0,tl)
		k = rnd.repick()
		tl = i = 0
		for each_point(&x) {
			tl += L/nseg
			if(tl <= k) i+=1
		}
		return i
		
	}
	proc setrand_descrete(/*SectionList,point_count[,randobj]*/){local i,k,point_count,x,nnseg localobj vx
	//same seed every time - very important!!!! unless you use a stream
		rnd = new Random(123) 
		sl = $o1 //set the class level object
		k = i = 0		
		point_count = $2 
		if(numarg()>2)rnd = $o3
		nnseg = 0
		forsec sl nnseg+=nseg //get the total number of segments
		vx = new Vector(nnseg)
		rnd.uniform(0,1)
		vx = vx.setrand(rnd).apply("int").sortindex() //uniqe synapses location
		forsec sl {
			for(x,0){
				if(vx.x[k] == i) {
					append(x)
					k+=1
					print "i=",i
				}
				i+=1 //for the none-unique position case
				if(k>=point_count) break
			}
			if(k>=point_count) break
		}
	}
	
	
	proc relocate_descrete(){local i,point,x1
		i = 0
		point = $1
		k = $2
		forsec sl {
			for(x1,0){
				if(k==i){
					x.x[point] = x1
					sclst.remove(point) 
					sclst.insrt(point,new SectionRef())
				}
				i+=1
			}
			if(k<i) break
		}
		
	}
	
	proc relocate(){local l,li
		l = 0
		li = $2
		k = $1
		forsec sl {
			l+=L
			if(l>=li) {
				x.x[k] = 1 - (l-li)/L
				sclst.remove(k) 
				sclst.insrt(k,new SectionRef())
				break
			}
		}
		
	}
	
	//just make it simple when it is on the same section
	/*proc relocate(){
		x.x[$1] = $2
	}*/
	

	
	iterator each_point_var(){local i
		for i=0, sclst.count-1{
			if(sclst.o(i).exists) {
				sclst.o(i).sec{
					sprint($s2,"%s.%s(%g)",secname(),$s1,x.x[i])
					iterator_statement
				}
			}else{
				if(SPLIT){
					sprint($s2,"%s.%s(%g)",secname(),$s1,x.x[i])
					iterator_statement
				}
			}
		}
	}
	
	proc printf(){local x
		for each_point(&x) print secname(),"(",x,")"
	}
	
	obfunc secname_(){local x localobj s
		s = new TString()
		sclst.o($1).sec {s.append(secname())}
		return s
	}
endtemplate TPointList