begintemplate ImpedanceRatio
public measure, inject, ratio, input, transfer, fmin, fmax, extended,fres, logf, rads
public box, move, imp, style, pl, shape, flush, view_count, begin
objectvar imp, sec[2], shape, b1, this, move_callback
objectvar g, imp, box, pbox
double x[2], color[2]
strdef s0, s1, stemp, sdist, fstyle, tstr, ipstyle, tpstyle

// kludge to use graphline() in pl()
f = 0


proc init() {
	extended = 0
	deltafac = 0.001
	fres = 1
	fmin = 0.01
	fmax = 100
	logf = 0
	style_ = 1
	rads = 0
	ipstyle = "Input Phase (deg)"
	tpstyle = "Transfer Phase (deg)"
	fstyle = "log(Attenuation)"
	mark_ = 1
	flush_ = 0
	scale_ = 1
	measure(0.5)
	inject(0.5)
	imp = new Impedance()
	build()
	doNotify()

	style(style_)
//	scale_ = 1
//	pl()
//	scale_ = 0
}

proc build(){
	dist()
	box = new VBox()
	box.ref(this)
	box.save("")
	box.intercept(1)
	xpanel("", 1)
	xbutton("Redraw", "pl()")
	xmenu("SelectLocation")
		xradiobutton("Select Measure", "mark_=0")
		xradiobutton("Select Inject", "mark_=1", 1)
		xbutton("Swap Measure/Inject", "exchange()")
	xmenu()
	xmenu("Plot")
		xradiobutton("log(Attenuation)", "style(0)")
		xradiobutton("Zin (Mohm)", "style(1)", 1)
		xradiobutton("Ztransfer (Mohm)", "style(2)")
		xradiobutton("V(measure)/V(inject)", "style(3)")
		xradiobutton(ipstyle, "style(4)")
		xradiobutton(tpstyle, "style(5)")
	xmenu()
	xmenu("Extras")
		xstatebutton("Movie mode", &flush_, "add_flush()")
		xstatebutton("Auto Scale", &scale_, "pl()")
		xbutton("Parameters", "parm()")
	xmenu()
	xpanel()
	xpanel("")
		xcheckbox("include dstate/dt contribution", &extended, "pl()")
		xvarlabel(s0)
		xvarlabel(s1)
		xvarlabel(sdist)
	xpanel()
	shape = new Shape()
	for i=0,1 color[i]=i+2
	shapemark(2)
	for i=0,1 {
		color[i] = i+2	// red, blue
		shapemark(i, sec[i], x[i], color[i])
	}
	shape.action("move()")
	defgraph()
	box.intercept(0)
	sprint(tstr, "%s Impedance vs Frequency", this)
	box.map(tstr)
}

proc parm() {
	pbox = new VBox()
	pbox.save("")
	pbox.intercept(1)
	xpanel("")
	xlabel("x axis scale (press redraw after changes)")
	xpvalue("fmin", &fmin, 2)
	xpvalue("fmax", &fmax, 2)
	if (logf == 1) {
		xpvalue("x resolution (log10 Hz)", &fres, 2)
	} else {
		xpvalue("x resolution (Hz)", &fres, 2)
	}
	xcheckbox("Use logarithmic axis", &logf, "logfchange()")
	xlabel("")
	xcheckbox("Phase in radians", &rads, "setpstyle()")
	xlabel("")
	xlabel("dy for df/dy calculation of extended y' = f(y)")
	xpvalue("delta factor", &deltafac, 2, "imp.deltafac(deltafac)")
	xpanel()
	pbox.intercept(0)
	sprint(tstr, "Params for %s", this)
	pbox.map(tstr)
}

proc logfchange() {
	if (logf == 1) {
		fres = log10(fres)
		if (fmin<0.01) fmin=-2 else fmin = log10(fmin)
		fmax = log10(fmax)
		if (fres<=0) fres=0.05
	} else {
		fres = 10^fres
		fmin = 10^fmin
		fmax = 10^fmax
	}
	style(style_)
}

proc setpstyle() {
	if (rads==0) {
		ipstyle = "Input Phase (deg)"
		tpstyle = "Transfer Phase (deg)"
	} else {
		ipstyle = "Input Phase (rad)"
		tpstyle = "Transfer Phase (rad)"
	}
	style(style_)
}

proc defgraph() {
	g = new Graph()
	g.size(0,fmax,0,1)
	style(style_)
}

proc style() {
	style_ = $1
	g.erase_all()
	g.label(-100, -100, "")
	if ($1 == 0) {
		g.addexpr("-log(ratio(f))")
		label("log(Attenuation)")
	}else if ($1 == 1) {
		g.addexpr("input(f)")
		label("Zin (Mohm)")
	}else if ($1 == 2) {
		g.addexpr("transfer(f)")
		label("Ztransfer (Mohm)")
	}else if ($1 == 3) {
		g.addexpr("ratio(f)")
		label("V(measure)/V(inject)")
	} else if ($1 == 4) {
		g.addexpr("input_phase(f)")
		label(ipstyle)
	} else if ($1 == 5) {
		g.addexpr("transfer_phase(f)")
		label(tpstyle)
	}

	sec[0].sec measure(x[0])
	sec[1].sec inject(x[1])
	pl()
}

proc label() {
	if (logf == 0) {
		g.label(.5, .9, "freq (Hz)")
	} else {
		g.label(.5, .9, "freq log10(Hz)")
	}
	g.label($s1)
}

proc move() {local i, xx
	i = mark_
	xx = hoc_ac_
	if (i == 0) {
		measure(xx)
	}else{
		inject(xx)
	}
	shapemark(i, sec[i], x[i], color[i])
	dist()
	pl()
}

//objectvar etmp
proc exchange() {local xx, i	localobj etmp	//swap inject and measure
	etmp = sec[0]
	xx = x[0]
	sec[1].sec measure(x[1])
	etmp.sec inject(xx)
//	objectvar etmp
	for i=0,1 shapemark(i, sec[i], x[i], color[i])
	pl()
}

double sz[4]
proc pl() {local max, x, val
	g.begin()
	for (x=fmin; x <= fmax; x=x+fres) {
		if (logf == 0) {
			f = x
		} else {
			f = 10^x
		}
		g.plot(x)
	}
	if (scale_) {
		g.size(&sz[0])
		g.size(fmin, fmax, sz[2], sz[3])
	}
	g.flush()
}

proc measure() {
	sec[0] = new SectionRef()
	x[0] = $1
	sectionname(stemp)
	if (style_ == 1) {
		sprint(s0, "unused (red): %s(%g)", stemp, $1)
	}else if (style_ == 4) {
		sprint(s0, "unused (red): %s(%g)", stemp, $1)
	}else{
		sprint(s0, "measure (red): %s(%g)", stemp, $1)
	}
}

proc inject() {
	sec[1] = new SectionRef()
	x[1] = $1
	sectionname(stemp)
	if (style_ == 1) {
		sprint(s1, "measure/inject (blue): %s(%g)", stemp, $1)
	} else if (style_ == 4) {
		sprint(s1, "measure/inject (blue): %s(%g)", stemp, $1)
	}else{
		sprint(s1, "inject (blue): %s(%g)", stemp, $1)
	}
}

func ratio() {local y
	compute($1)
	sec[1].sec y = imp.ratio(x[1])
	return y
}
func transfer() {local y
	compute($1)
	sec[1].sec y = imp.transfer(x[1]) // since v(x)/i(loc) == v(loc)/i(x)
	return y
}
func input() {local y
	compute($1)
	sec[1].sec y = imp.input(x[1])
	return y
}
func input_phase() {local y
	compute($1)
	sec[1].sec y = imp.input_phase(x[1])
	if (rads == 0) y=y/PI*180
	return y
}
func transfer_phase() {local y
	compute($1)
	sec[1].sec y = imp.transfer_phase(x[1])
	if (rads == 0) y=y/PI*180
	return y
}
proc compute() {
	sec[0].sec imp.loc(x[0])
	imp.compute($1, extended)
}

objectvar rvp
proc dist() {local y
	sec[0].sec distance(0,x[0])
	sec[1].sec y = distance(x[1])
	sprint(sdist, "distance(um) %g", y)
}

// should put this in plotshape class and avoid a meaningless point process
objectvar stim[1]
proc shapemark() {local i
	if (numarg() == 1) {
		objectvar stim[$1]
		for i=0,1 sec[i].sec stim[i] = new PointProcessMark(x[i])	
		for i=0,1 shape.point_mark(stim[i], color[i])
	}else{
		$o2.sec stim[$1].loc($3)
	}
}

proc add_flush() {
	if (flush_) {
		sprint(tstr, "flush_list.append(%s)", this)
		execute(tstr)
	}
}
func view_count() {
	if (flush_) {
		return g.view_count()
	}else{
		return 0
	}
}
proc begin() {
}
proc flush() {
	pl()
}

proc save() {}

endtemplate ImpedanceRatio


proc makeImpRatio() {
	if(!execute1("v", 0)) {
		continue_dialog("No accessed section: Can't start an ImpedanceRatio")
		return
	}
	hoc_obj_[0] = new ImpedanceRatio()
	objref hoc_obj_[2]
}