// This handler is partly based on spikeplt.hoc in which a GUI component is defined for plotting spikes.
begintemplate SpikeTrainHandler
	public edit, createhandler, set, copy, preparerun, printtofile, show, get_sessionstr
	objref nil,this
	objref vbox, vbox1
	objref outputvariable, protocol
	objref graph
	objref outfile
					
					
	strdef tstr, tstr1, tstr2
	objref sc
	
	external MRC_debugmode, MRC_CreateOutParamHandler,MRC_SeparateSecAndIndex, tstop,all_in_list, all_in_vector
	strdef listname , sectionname , membername , shortname
	strdef llistname, lsectionname, lmembername, lshortname
	
	// From spikeplot
	public sources, outveclist,  update
	public flush,  size
	
	external  MRC_OutvecListGenerator, MRC_GetObjectFromName, MRC_ListGenerator_DummyObject
	objref sources, outveclist, spiketimes,  b, outlist
	strdef display_modestr
	strdef internalname, objecttypestr, obj2bnamed
		
	proc init(){
	
		if(numarg()==2){
			outputvariable=$o1
			protocol=$o2
			shortname=outputvariable.name
			
			//listname=outputvariable.name
			//sectionname=outputvariable.name
			//membername=outputvariable.name			
								
			// From spikeplot
				outveclist = new List()
				outlist= new List()
				fwindow = 100
				binwidth = .1
				display_modestr = "Spikes   "
				display_mode=1
				spiketimes = new Vector(1000)
						
		}else if(1==MRC_debugmode && numarg()>2){
			printf("To many initialization parameters")
		}
		
		sc = new SymChooser("Get List/Section/Variable Name Example")
		
		threshold=0
		record_start=0
		record_stop=tstop
		
		
		lthreshold=threshold
		lrecord_start=record_start
		lrecord_stop=record_stop
		useindexing=0
		isart=0
		runprepared=0
		
		internalname="  ------------  "	
		objecttypestr="  ------------  "	
	}
	
	
	proc set(){
		outputvariable=$o1
		protocol=$2
		//@@
		record_start=$4
		record_stop=$5
	}
					
	proc copy(){
		$o1.set(outputvariable, protocol,0/*@@*/,record_start,record_stop)
	}
	
	// Admittedly this is a hack to keep all the information on the handler class stricly local,
	// but it works!
	obfunc createhandler(){localobj handler
		execute1("obfunc MRC_CreateOutParamHandler(){return new SpikeTrainHandler($o1,$o2)}")
		handler=MRC_CreateOutParamHandler($o1,$o2)
		execute1("obfunc MRC_CreateOutParamHandler(){localobj nil  return nil}")
		return handler				
	}
	
	// Convenience function for creating string editors
	proc exprval() {
		xpanel("", 1)
			xbutton($s1, $s3)
			xvarlabel($s2)
		xpanel()
	}

	//Procedure: get_outparname
	//Create a symbol chooser to pick a new parameter for the loopparameter list.
	
	proc get_outparname(){
		if (sc.run()) {
			sc.text(tstr)
		}
		
			// Only replace existing llistname string if it is empty
		if(strcmp("",llistname)==0){
			llistname=tstr
		}
		
			// Only replace existing lsectionname string if it is empty
		if(strcmp("",lsectionname)==0){
			lsectionname=tstr
		}
		
			// Only replace existing lmembername string if it is empty
		if(strcmp("",lmembername)==0){
			lmembername=tstr
		}
		
		internalname=tstr
	}	
	
	proc getinternalname(){local type_index
		type_index=0
		MRC_GetObjectFromName($s1)
		sprint(internalname,"%s",MRC_ListGenerator_DummyObject)		
		/* */
		type_index=name_declared(internalname)
		
		if(0==type_index) {sprint(objecttypestr,"undefined")			} 		
		if(1==type_index) {sprint(objecttypestr,"otherwise")			}
		if(2==type_index) {sprint(objecttypestr,"objref")			}
		if(3==type_index) {sprint(objecttypestr,"Section")  			}	
		if(4==type_index) {sprint(objecttypestr,"strdef") 			}
		if(5==type_index) {sprint(objecttypestr,"scalar or double variable")	}
		/* */
		vbox.full_request(1)
	}
	
	
	proc createeditwindow(){
			
		sprint(tstr, "SpikeTrain Settings for variable: %s",outputvariable.name)
		
		
		vbox=new VBox()
		vbox.intercept(1)
		
		exprval("Short Name in Output (Preceding Index in List):", lshortname,"string_dialog(\"Short Name in Output:\", lshortname)")	
		xpanel(tstr)
			xvalue("spike threshold","lthreshold",0,"",0,1)
			xvalue("record start time","lrecord_start",0,"",0,1)
			xvalue("record stop time","lrecord_stop",0,"",0,1)
			if(1==numarg()){	
				xlabel($s1)
			}
			xbutton("Pick Outputvariable name for filling listname, sectionname and membername variables","get_outparname()")
		xpanel()
		
		xpanel("", 1)
			xbutton("Name of List:", "string_dialog(\"Select List part from outputvariable name:\", llistname)")
			xvarlabel(llistname)
			xbutton("Get Internal Name","getinternalname(internalname)")
			xvarlabel(internalname)
			//xvarlabel(objecttypestr)
		xpanel()
		//exprval("Name of List:", llistname,"string_dialog(\"Select List part from outputvariable name:\", llistname)")
		exprval("Sectionname:", lsectionname,"string_dialog(\"Select section part from outputvariable name:\", lsectionname)")
		exprval("Membername:", lmembername,"string_dialog(\"Select member part from outputvariable name:\", lmembername)")		
		xpanel("")
			xlabel("Give the type")
			xradiobutton("List", "llisttype=0", 0==llisttype)
			xradiobutton("Section/ Section Set", "llisttype=2", 2==llisttype)
			xradiobutton("SectionList", "llisttype=3", 3==llisttype)
			xradiobutton("Single Artificial Cell", "llisttype=4", 4==llisttype)
			xcheckbox("Listobjects are artificial cells",&lisart)
			xcheckbox("Use indexing (sections only)",&luseindexing)
		xpanel()
		xpanel("")
			xlabel("Using the vector/list/section (set)/Sectionlist type:")
			xlabel("	")
			xlabel("	For compartmental models specify separately the name of the")
			xlabel("	list/vector of cells over which you want to obtain information, the")
			xlabel("	section from which you want to obtain info and the parameter in this section.")
			xlabel("	")
		    xlabel("	Sectionlist, Section set: Specify the section set or sectionlist in the ")
			xlabel("	list field and leave the sectionname part open. Now you can specify the ")
			xlabel("	outparameter from this section in the membername part.")
			xlabel("	")
			xlabel("	Artificial cells: Specify the list/vector or ")
			xlabel("	if the cell is in an object in this list the name of")
			xlabel("	the cell in this object.")
		xpanel()
		
		
		vbox.intercept(0)
		doNotify()
		dialog_outcome=vbox.dialog(tstr,"Accept","Cancel")
		
		if(1==dialog_outcome){
			if(lrecord_start==lrecord_stop){
				createeditwindow("The start and stop time are the same, please adjust.")
			}
		}
		
	}
	
	proc edit(){
		lrecord_start=record_start
		lrecord_stop=record_stop
		lthreshold=threshold
		llistname=listname
		lsectionname=sectionname
		lmembername=membername
		llisttype=listtype
		luseindexing=useindexing
		lisart=isart
		lshortname=shortname
		
		createeditwindow()
						
		if(1==dialog_outcome){
			record_start=lrecord_start
			record_stop=lrecord_stop
			threshold=lthreshold
			listname=llistname
			sectionname=lsectionname
			membername=lmembername
			listtype=llisttype
			useindexing=luseindexing
			isart=lisart
			shortname=lshortname		
		}
		
		update()
	}
	
	proc preparerun(){
		if(0==runprepared){
			runprepared=1
		}
        update()
	}
	
	proc printtofile(){	local index,index2
	
		if(protocol.output_matlab_mfile==1){					
			sprint(tstr,"%s.m", $s1)
			outfile=new File(tstr)
			
			if(!outfile.isopen()){
				outfile.aopen()
			}
			
			if(outfile.isopen()){
				outfile.printf("%% Matlab object for: %s\n", shortname)
				if(4!=listtype){
				    outfile.printf("%s=cell(%d,1);\n", shortname,outveclist.count())
				}
                for all_in_list (outveclist,&index) {
					printf("Output Veclist for Run: %d \n",index)
					outfile.printf("%s =[\n", outveclist.object(index).label())
					for all_in_vector (outveclist.object(index),&index2){
						outfile.printf("%g\n", outveclist.object(index).x[index2])
					}
					outfile.printf("];\n")
				}
				outfile.close()
			}
		}					
    
    if(protocol.output_neuronbinary==1){
      for all_in_list (outveclist,&index) {
        tstr=outveclist.object(index).label()
        
        if(0==listtype ){
          MRC_SeparateSecAndIndex(tstr,tstr1,tstr2,"{","}")
          if(0==strcmp(tstr2, "")){
            sprint(tstr,"%s_%s_%s.dat", $s1,shortname,tstr1)
          }else{
            sprint(tstr,"%s_%s_%s_%s.dat", $s1,shortname,tstr1,tstr2)
          }
        }else if(2==listtype || 3==listtype){
          if(0==useindexing){
            MRC_SeparateSecAndIndex(tstr,tstr1,tstr2,"[","]")
            if(0==strcmp(tstr2, "")){
              sprint(tstr,"%s_%s_%s.dat", $s1,shortname,tstr1)
            }else{
              sprint(tstr,"%s_%s_%s_%s.dat", $s1,shortname,tstr1,tstr2)
            }
          }
        }else {
          
          // This requires a bit of refactoring
        }
        
        
        outfile=new File(tstr)
        
        if(!outfile.isopen()){
          outfile.aopen()
        }
        
        if(outfile.isopen()){
          outveclist.object(index).vwrite(outfile,4)
          outfile.close()
        }		
      }
    }
	}
	
	proc show(){
		vbox1 = new VBox(3)
		vbox1.intercept(1)
			xpanel("")
				xmenu("Plot")
					xbutton("Update", "update() flush()")
					xradiobutton("Spikes", "pmode(1)", display_mode==1)
					xradiobutton("Frequency", "pmode(2)", display_mode==2)
					xradiobutton("Smoothed Histogram", "pmode(3)", display_mode==3)
					xradiobutton("Histogram", "pmode(4)", display_mode==4)
				xmenu()
				xvarlabel(display_modestr)
				xpvalue("Freq Window (ms)", &fwindow, 1, "flush()")
				xpvalue("Hist Bin (ms)", &binwidth, 1, "flush()")
			xpanel()
			if(numarg()==0){
				graph = new Graph()						
			}else{
				graph=$o1
			}
		
		vbox1.intercept(0)
		vbox1.map()
		pmode(display_mode)			
		graph.exec_menu("View = plot")
	}
	
	proc unref(){local refcount
		refcount=$1
		if(refcount==0 && 1==runprepared){
			//remove recorded parameter 
		}
	}
	
		
	proc pmode() {
		display_mode = $1
		if (display_mode == 1) {
			display_modestr = "Spikes   "
		}else if (display_mode == 2) {
			display_modestr = "Frequency"
		}else if (display_mode == 3) {
			display_modestr = "Smoothed Histogram"
		}else if (display_mode == 4) {
			display_modestr = "Histogram"
		}
		flush()
	}
	

	
	proc update() {local index
	
		outlist.remove_all()	
		objref outveclist
		
		//Just a reminder about the correspondence
		//	"List", 			"llisttype=0"
		//	"Sets of sections", 	"llisttype=2"
		//	"SectionList", 		"llisttype=3"
		//	"Single Artificial Cell", 	"llisttype=4"
		
		outveclist=MRC_OutvecListGenerator(listtype,isart,listname,sectionname,membername,outlist,shortname,useindexing)
		for all_in_list (outlist,&index){
			outlist.object(index).threshold=threshold
		}
	}
	
		
	func size() {
		if (numarg() == 4) {
			graph.size($1,$2,0,sources.count+1)
			return 1.
		}else{
			return graph.size($1)
		}
	}
	
	proc flush() {local index

		graph.erase_all
		graph.vfixed(1)
		graph.label(.9,1)
		
		if (display_mode == 1) {
			for all_in_list (outveclist,&index) {
				spiketimes.resize(outveclist.object(index).size).fill(index+1)
				spiketimes.label(outveclist.object(index).label)
				spiketimes.mark(graph, outveclist.object(index), "O", 2, 1, 1)
				//spiketimes.line(graph, outveclist.object(index), 1, 0)
			}
			
			graph.size(0,tstop,0,outveclist.count()+1)
			
		}else if (display_mode == 2) {
			for all_in_list (outveclist,&index) { 
				spiketimes = outveclist.object(index).sumgauss(0, tstop, tstop/100, fwindow)
				spiketimes.label(outveclist.object(index).label)
				spiketimes.mul(1000).line(graph, spiketimes.c.indgen(0, tstop/100), 1,1)
			}
		}else if (display_mode == 3) {
			for all_in_list (outveclist,&index) { 
				if (outveclist.object(index).size > 1){
					spiketimes = outveclist.object(index).c.deriv(1,1)
					high = spiketimes.max
					spiketimes = spiketimes.sumgauss(0, high, high/50, binwidth)
					spiketimes.label(outveclist.object(index).label)
					spiketimes.line(graph, spiketimes.c.indgen(0, high/50), 1,1)
				}
			}	
		}else if (display_mode == 4) {
			for all_in_list (outveclist,&index) {
			 	if (outveclist.object(index).size > 1){
					spiketimes = outveclist.object(index).c.deriv(1,1)
					high = spiketimes.max
					spiketimes = spiketimes.histogram(0, high, binwidth)
					spiketimes=spiketimes.c(1)
					spiketimes.label(outveclist.object(index).label)
					spiketimes.line(graph, spiketimes.c.indgen(0, high/50), 1,1)
				}
			}
		}
		graph.flush()
	}

	proc get_sessionstr(){
		$s1=""
		sprint(tstr,"\t{")				$o2.save(tstr)
		sprint(tstr,"\t\trecord_start=%g",record_start)	$o2.save(tstr)
		sprint(tstr,"\t\trecord_stop=%g",record_stop)	$o2.save(tstr)
		sprint(tstr,"\t\tthreshold=%g",threshold)		$o2.save(tstr)
		sprint(tstr,"\t\tlistname=\"%s\"",listname)	$o2.save(tstr)
		sprint(tstr,"\t\tsectionname=\"%s\"",sectionname)	$o2.save(tstr)
		sprint(tstr,"\t\tmembername=\"%s\"",membername)	$o2.save(tstr)
		sprint(tstr,"\t\tlisttype=%d",listtype)		$o2.save(tstr)
		sprint(tstr,"\t\tuseindexing=%d",useindexing)	$o2.save(tstr)
		sprint(tstr,"\t\tisart=%d",isart)			$o2.save(tstr)
		sprint(tstr,"\t\tshortname=\"%s\"",shortname)	$o2.save(tstr)
		sprint(tstr,"\t}")				$o2.save(tstr)
	}

	
endtemplate SpikeTrainHandler