//========================================================================================
//============================== position related functions ==============================
//========================================================================================

proc rotateZ(){ local i
	c = cos($1)
	s = sin($1)
	forsec $o2.all {
		for i=0,n3d()-1 {
			x = x3d(i)
			y = y3d(i)
			xprime = x * c - y * s
			yprime = x * s + y * c
			pt3dchange(i, xprime, yprime, z3d(i), diam3d(i))
			pt3dstyle(0)
		}
	}
}

// shift cell location
proc position(){ local i
	$o4.soma x = x3d(0)
	$o4.soma y = y3d(0)
	$o4.soma z = z3d(0)
	$o4.soma for i=0,n3d()-1 {
		xloc = x3d(i)+$1-x
		yloc = y3d(i)+$2-y
		zloc = z3d(i)+$3-z
		diamval = diam3d(i)
		pt3dchange(i, xloc, yloc, zloc, diamval)
	}
	define_shape() // shifts all the other sections in line with somatic section
}

proc position2() { local i
	$o4.soma for i = 0, n3d()-1 { // ith point of number of 3d locations stored in the currently accessed section
		pt3dchange(i, $1+=x3d(i), $2+y3d(i), $3+z3d(i), diam3d(i)) // Change the ith 3-d point info, Returns the x/y/z coordinate of the ith point in the 3-d list of the currently accessed section.
	}
	define_shape()
}
// pt3dstyle() // use if visualization gets wee-woo

//========================================================================================
//=============================== intrinsic manipulations ================================
//========================================================================================

proc addTonicInhibition(){
	forsec $o1.somatic {
		insert tonic
		g_tonic = $2
		e_gaba_tonic = -75
	}
	forsec $o1.basal {
		insert tonic
		g_tonic = $2
		e_gaba_tonic = -75
	}
	if ((strcmp($o1.cell_name, "HL23PN1") == 0) || (strcmp($o1.cell_name, "HL4PN1") == 0) || (strcmp($o1.cell_name, "HL5PN1") == 0) || (strcmp($o1.cell_name, "HL5PN1y") == 0) || (strcmp($o1.cell_name, "HL5PN1o") == 0)){
		forsec $o1.apical {
			insert tonic
			g_tonic = $3
			e_gaba_tonic = -75
		}
	}
}

//========================================================================================
//============================== synapse related functions ===============================
//========================================================================================

// double siteVec[2]
proc createArtificialSyn() {local sitenum,OUni,i localobj sl, postcell, sref
	strdef treename
	postcell = $o2
	
	treename = "dend"
	relpos = 0.5
	sl = postcell.locateSites(treename,relpos*postcell.getLongestBranch(treename))
	for (i=0;i<sl.count();i+=1){
		postcell.siteVec[0] = sl.o[i].x[0]
		postcell.siteVec[1] = sl.o[i].x[1]
		
		access postcell.dend[postcell.siteVec[0]]
		postcell.dend[postcell.siteVec[0]] sref = new SectionRef()
		
		sref {
			postcell.OUprocess.append(new Gfluct2(postcell.siteVec[1]))
			OUni = postcell.OUprocess.count()-1 // OU object index
			// Set OU parameters
			postcell.OUprocess.o[OUni].E_e = 0// time constant of excitatory conductance
			postcell.OUprocess.o[OUni].E_i = -80 // time constant of inhibitory conductance
			postcell.OUprocess.o[OUni].g_e0 = $3*exp(relpos) //0.001*exp(relpos) // average excitatory conductance
			postcell.OUprocess.o[OUni].g_i0 = 0//0.015*exp(relpos) // average inhibitory conductance
			postcell.OUprocess.o[OUni].tau_e = 65 // time constant of excitatory conductance
			postcell.OUprocess.o[OUni].tau_i = 20 // time constant of inhibitory conductance
			postcell.OUprocess.o[OUni].std_e = $3*exp(relpos) //0.001*exp(relpos) // standard dev of excitatory conductance
			postcell.OUprocess.o[OUni].std_i = 0//0.015*exp(relpos) // standard dev of inhibitory conductance
			// OUprocess.o[OUni].new_seed($1*10+i) // This appears to not be threadsafe
			postcell.roulist.append(new Random($1*10+i+5))
			postcell.roulist.o[OUni].normal(0,1)
			postcell.OUprocess.o[OUni].noiseFromRandom(postcell.roulist.o[OUni])
		}
	}
	
	// Apply 5 OUs along apical trunk (if PN)
	if ((strcmp(postcell.cell_name, "HL23PN1") == 0) || (strcmp(postcell.cell_name, "HL4PN1") == 0) || (strcmp(postcell.cell_name, "HL5PN1") == 0) || (strcmp(postcell.cell_name, "HL5PN1y") == 0) || (strcmp(postcell.cell_name, "HL5PN1o") == 0)){
		for (i=0; i<5; i+=1){
			treename = "apic"
			relpos = i*0.2 + 0.1 // [0.1, 0.3, 0.5, 0.7, 0.9]
			sl = postcell.locateSites(treename,relpos*postcell.getLongestBranch(treename))
			
			maxdiam = 0
			for (i1=0; i1<sl.count(); i1+=1){
				dd1 = sl.o[i1].x[1]
				dd = postcell.apic[sl.o[i1].x[0]].diam(dd1)
				if (dd > maxdiam){
					j = i1
					maxdiam = dd
				}
			}
			
			postcell.siteVec[0] = sl.o[j].x[0]
			postcell.siteVec[1] = sl.o[j].x[1]
			
			access postcell.apic[postcell.siteVec[0]]
			postcell.apic[postcell.siteVec[0]] sref = new SectionRef()
			
			sref {
				postcell.OUprocess.append(new Gfluct2(postcell.siteVec[1]))
				OUni = postcell.OUprocess.count()-1 // OU object index
				// Set OU parameters
				postcell.OUprocess.o[OUni].E_e = 0// time constant of excitatory conductance
				postcell.OUprocess.o[OUni].E_i = -80 // time constant of inhibitory conductance
				postcell.OUprocess.o[OUni].g_e0 = $3*exp(relpos) //0.001*exp(relpos) // average excitatory conductance
				postcell.OUprocess.o[OUni].g_i0 = 0//0.015*exp(relpos) // average inhibitory conductance
				postcell.OUprocess.o[OUni].tau_e = 65 // time constant of excitatory conductance
				postcell.OUprocess.o[OUni].tau_i = 20 // time constant of inhibitory conductance
				postcell.OUprocess.o[OUni].std_e = $3*exp(relpos) //0.001*exp(relpos) // standard dev of excitatory conductance
				postcell.OUprocess.o[OUni].std_i = 0//0.015*exp(relpos) // standard dev of inhibitory conductance
				// OUprocess.o[OUni].new_seed($1*10+i) // This appears to not be threadsafe
				postcell.roulist.append(new Random($1*10+i))
				postcell.roulist.o[OUni].normal(0,1)
				postcell.OUprocess.o[OUni].noiseFromRandom(postcell.roulist.o[OUni])
			}
		}
	}
}

proc deleteSyn() { // input the presyn
	for (n=0;n<$o1.cons.count();n+=1){
		$o1.cons.o[n].weight = 0.0
	}
	$o1.cons.remove_all()
}

obfunc distributeSyn() {local sitenum,syni,preconi,jj localobj sl, postcell, sref, precell
	strdef treename,SynType,Target
	
	NumSyns = $1
	SynType = $s2
	Target = $s3
	synConductance = $4
	taur = $5
	taud = $6
	dep = $7
	fac = $8
	use = $9
	postcell = $o10
	precell = $o11
	postcell.synlist.remove_all()
	
	if (strcmp("both",Target)==0){
		if (postcell.rd1.repick()<postcell.pA){
			treename = "apic"
		} else {
			treename = "dend"
		}
	} else {
		treename = Target
	}
	
	for(jj=0;jj<NumSyns;jj+=1){
		
		sl = postcell.locateSites(treename,postcell.rd1.repick()*postcell.getLongestBranch(treename))
		sitenum = int((sl.count()-1)*postcell.rd1.repick())
		
		postcell.siteVec[0] = sl.o[sitenum].x[0]
		postcell.siteVec[1] = sl.o[sitenum].x[1]
		
		if (strcmp(treename, "dend") == 0){
			access postcell.dend[postcell.siteVec[0]]
			postcell.dend[postcell.siteVec[0]] sref = new SectionRef()
		}
		if (strcmp(treename, "apic") == 0){
			access postcell.apic[postcell.siteVec[0]]
			postcell.apic[postcell.siteVec[0]] sref = new SectionRef()
		}
		
		if (strcmp("E",SynType)==0){
			sref {
				postcell.synlist.append(new ProbAMPANMDA(postcell.siteVec[1]))
				syni = postcell.synlist.count()-1 //synapse index
				postcell.rslist.append(new Random(int(1000000*postcell.rd1.repick())))
				postcell.rslist.o[syni].negexp(1)
				postcell.synlist.o[syni].setRNG(postcell.rslist.o[syni])
				postcell.synlist.o[syni].tau_r_AMPA = taur
				postcell.synlist.o[syni].tau_d_AMPA = taud
				postcell.synlist.o[syni].tau_r_NMDA = 2
				postcell.synlist.o[syni].tau_d_NMDA = 65
				postcell.synlist.o[syni].e = 0
				postcell.synlist.o[syni].Dep = dep
				postcell.synlist.o[syni].Fac = fac
				postcell.synlist.o[syni].Use = use
				postcell.synlist.o[syni].u0 = 0
				postcell.synlist.o[syni].gmax = synConductance
				
				access precell.soma
				precell.cons.append(new NetCon(&v(1), postcell.synlist.o[syni]))
				preconi = precell.cons.count()-1 //connection index
				precell.cons.o[preconi].threshold = -30
				precell.cons.o[preconi].delay = 0
				precell.cons.o[preconi].weight = 1
			}
		}
		if  (strcmp("I",SynType)==0){
			sref {
				postcell.synlist.append(new ProbUDFsyn(postcell.siteVec[1]))
				syni = postcell.synlist.count()-1 //synapse index
				postcell.rslist.append(new Random(int(1000000*postcell.rd1.repick())))
				postcell.rslist.o[syni].negexp(1)
				postcell.synlist.o[syni].setRNG(postcell.rslist.o[syni])
				postcell.synlist.o[syni].tau_r = taur
				postcell.synlist.o[syni].tau_d = taud
				postcell.synlist.o[syni].e = -80
				postcell.synlist.o[syni].Dep = dep
				postcell.synlist.o[syni].Fac = fac
				postcell.synlist.o[syni].Use = use
				postcell.synlist.o[syni].u0 = 0
				postcell.synlist.o[syni].gmax = synConductance
				
				access precell.soma
				precell.cons.append(new NetCon(&v(1), postcell.synlist.o[syni]))
				preconi = precell.cons.count()-1 //connection index
				precell.cons.o[preconi].threshold = -30
				precell.cons.o[preconi].delay = 0
				precell.cons.o[preconi].weight = 1
			}
		}
	}
	return postcell.synlist
}

proc InitConnections(){local sitenum,syni,jj localobj sl, postcell, sref
	strdef treename,SynType,Target
	
	NumSyns = $1
	SynType = $s2
	Target = $s3
	synConductance = $4
	taur = $5
	taud = $6
	dep = $7
	fac = $8
	use = $9
	postcell = $o10
	
	if (strcmp("both",Target)==0){
		if (postcell.rd1.repick()<postcell.pA){
			treename = "apic"
		} else {
			treename = "dend"
		}
	} else {
		treename = Target
	}
	
	for(jj=0;jj<NumSyns;jj+=1){
		
		sl = postcell.locateSites(treename,postcell.rd1.repick()*postcell.getLongestBranch(treename))
		sitenum = int((sl.count()-1)*postcell.rd1.repick())
		
		postcell.siteVec[0] = sl.o[sitenum].x[0]
		postcell.siteVec[1] = sl.o[sitenum].x[1]
		
		if (strcmp(treename, "dend") == 0){
			access postcell.dend[postcell.siteVec[0]]
			postcell.dend[postcell.siteVec[0]] sref = new SectionRef()
		}
		if (strcmp(treename, "apic") == 0){
			access postcell.apic[postcell.siteVec[0]]
			postcell.apic[postcell.siteVec[0]] sref = new SectionRef()
		}
		
		if (strcmp("E",SynType)==0){
			sref {
				postcell.synlist.append(new ProbAMPANMDA(postcell.siteVec[1]))
				syni = postcell.synlist.count()-1 //synapse index
				postcell.rslist.append(new Random(int(1000000*postcell.rd1.repick())))
				postcell.rslist.o[syni].negexp(1)
				postcell.synlist.o[syni].setRNG(postcell.rslist.o[syni])
				postcell.synlist.o[syni].tau_r_AMPA = taur
				postcell.synlist.o[syni].tau_d_AMPA = taud
				postcell.synlist.o[syni].tau_r_NMDA = 2
				postcell.synlist.o[syni].tau_d_NMDA = 65
				postcell.synlist.o[syni].e = 0
				postcell.synlist.o[syni].Dep = dep
				postcell.synlist.o[syni].Fac = fac
				postcell.synlist.o[syni].Use = use
				postcell.synlist.o[syni].u0 = 0
				postcell.synlist.o[syni].gmax = synConductance
			}
		}
		if  (strcmp("I",SynType)==0){
			sref {
				postcell.synlist.append(new ProbUDFsyn(postcell.siteVec[1]))
				syni = postcell.synlist.count()-1 //synapse index
				postcell.rslist.append(new Random(int(1000000*postcell.rd1.repick())))
				postcell.rslist.o[syni].negexp(1)
				postcell.synlist.o[syni].setRNG(postcell.rslist.o[syni])
				postcell.synlist.o[syni].tau_r = taur
				postcell.synlist.o[syni].tau_d = taud
				postcell.synlist.o[syni].e = -80
				postcell.synlist.o[syni].Dep = dep
				postcell.synlist.o[syni].Fac = fac
				postcell.synlist.o[syni].Use = use
				postcell.synlist.o[syni].u0 = 0
				postcell.synlist.o[syni].gmax = synConductance
			}
		}
	}
}