//mitral-granule reciprocal synapse

//src, target
// assume src,target unique
func syn_gid() {local i
    if ($1 < nmitral) { // target is granule
	i = ($2 * nmitral + $1 + 1 + ncell) * 100 + 1
    }else{ // target is mitral
	i = ($1 * nmitral + $2 + 1 + ncell) * 100
    }
    return i
}

begintemplate MGRS
public md, gd, md_gid, gd_gid, clear
public fi, ampanmda,  mitral, granule, mitral_gid, granule_gid
public md2ampanmda, gd2fi
public fi_exists, ampa_exists, mexist, gexist
public sm, sg, wm, wg, set_sm, set_sg, ws_str
public pr
external pc, syn_gid
external ncell, nmitral  //, nil,amp, rel, inh,synst, nmdafactor
objref mitral, granule
objref md2ampanmda, gd2fi
objref ampanmda, fi, md, gd
objref this, nil, ws_str_

strdef tstr 

proc clear() {
	objref md2ampanmda, gd2fi
	objref ampanmda, fi, md, gd
	objref mitral, granule
}

proc init() {
    ws_str_ = new String()
    mitral_gid = $1
    granule_gid = $4
    mexist = pc.gid_exists(mitral_gid)
    gexist = pc.gid_exists(granule_gid)
    md_gid = syn_gid(granule_gid, mitral_gid)
    gd_gid = syn_gid(mitral_gid, granule_gid)
    
    if (mexist) {	
	mitral = pc.gid2obj(mitral_gid)
//	print pc.gid2obj(mitral_gid)
	create_syn("{mitral.%s { fi = new FastInhib(%-10.20g )}}",$s2, $3)
	create_syn("{mitral.%s { md = new ThreshDetect(%-10.20g)}}",$s2, $3)
	pc.set_gid2node(md_gid, pc.id)
	pc.cell(md_gid, new NetCon(md, nil), 1)
    }

    if (gexist) {
	granule = pc.gid2obj(granule_gid)
	create_syn("{granule.%s { ampanmda = new AmpaNmda(%-10.20g) }}" , $s5, $6)
	create_syn("{granule.%s { gd = new ThreshDetect(%-10.20g)}}" , $s5, $6)
	pc.set_gid2node(gd_gid, pc.id)
	pc.cell(gd_gid, new NetCon(gd, nil), 1)
    }
//    print pc.id, this, mexist, gexist

    if (gexist) {
//	print pc.id, this, mitral_gid, granule_gid
//	print pc.id, this, md_gid,gd_gid
	md2ampanmda = pc.gid_connect(md_gid, ampanmda)
//	print pc.id, this, md2ampanmda, 
    }
    if (mexist) {
//	print pc.id, this, mitral_gid, granule_gid
//	print pc.id, this, md_gid,gd_gid
	gd2fi   = pc.gid_connect(gd_gid, fi  )
//	print pc.id, this, gd2fi
    }
//    print pc.id, this, mitral_gid, granule_gid, mitral, granule
    
    if (gexist) {
	md2ampanmda.weight = 1 // normalized
	md2ampanmda.delay = 1
    }
    if (mexist) {
	gd2fi.weight = 1 // normalized
	gd2fi.delay = 1
    }
}

proc create_syn() {
    sprint(tstr, $s1, $s2, $3)
    execute(tstr, this)
}

func fi_exists() {
    return (fi != nil)
}
func ampa_exists() {
    return (ampanmda != nil)
}

proc pr() {local x  localobj s
	s = new String()
	if (mexist) {
		x = md.get_loc()
		sprint(s.s, "%s(%g) %d --- ", secname(), x, mitral_gid)
		pop_section()
	}else{
		sprint(s.s, "%27d --- ", mitral_gid)
	}
	if (gexist) {
		x = gd.get_loc()
		sprint(s.s, "%s%d %s(%g)", s.s, granule_gid, secname(), x)
		pop_section()
	}else{
		sprint(s.s, "%s%d", s.s, granule_gid)
	}
	printf("%d %s\n", pc.id, s.s)
}

//returns volatile String in proper wsfile format
// srcid tarid s w
// may be one line or two, no trailing newline
obfunc ws_str() {
	if (mexist) {
		if (gexist) {
			sprint(ws_str_.s, "%d %d %g %g\n%d %d %g %g",\
				granule_gid, mitral_gid, sm(), wm(),\
				mitral_gid, granule_gid, sg(), wg())
		}else{
			sprint(ws_str_.s, "%d %d %g %g",\
				granule_gid, mitral_gid, sm(), wm())
		}
	}else if (gexist) {
		sprint(ws_str_.s, "%d %d %g %g", mitral_gid, granule_gid, sg(), wg())
	}else{
		ws_str_.s = ""
	}
	return ws_str_
}

proc set_sm() {
	if (mexist) { gd2fi.weight[1] = $1 }
}
proc set_sg() {
	if (gexist){ md2ampanmda.weight[1] = $1 }
}
func sm() {
	return gd2fi.weight[1]
}
func sg() {
	return md2ampanmda.weight[1]
}
func wm() {
	return gd2fi.weight[2] * fi.gmax
}
func wg() {
	return md2ampanmda.weight[2] * ampanmda.gmax
}

endtemplate MGRS

objref mgrs_list
mgrs_list = new List()

obfunc mk_mgrs() { local  mitral_gid, granule_gid    localobj mgrs
    //$1 is the imitral, $s2 section name, $3 section arc position,
    //$4 is the igranule, $s5 section name, $6 section arc position
    mitral_gid = $1
    granule_gid = $4 + ngranule_begin
    if (pc.gid_exists(mitral_gid) || pc.gid_exists(granule_gid)) {
	mgrs = new MGRS(mitral_gid, $s2, $3, granule_gid, $s5, $6)
	mgrs_list.append(mgrs)
	return mgrs
    }
    return nil
}