#!/bin/sh
# \
exec oagtclsh "$0" "$@"

if [info exists env(LOCO_BINDIR)] {
    set locoBinDir $env(LOCO_BINDIR)
} else {
    puts stderr "Error: LOCO_BINDIR environment variable is not defined"
    exit
}
source $locoBinDir/locoCommonProcedures

if [info exists env(LOCO_TMPDIR)] {
    set tmpDir $env(LOCO_TMPDIR)
} else {
    set tmpDir $env(HOME)/tmp
}

set args $argv
set usage "usage: locoTransformMeasuredFiles -machineName <APS|APSBooster|TeVatron|PAR> -xRawResponse <filename> -xyRawResponse <filename> \
           -yRawResponse <filename> -yxRawResponse <filename> -dispRawFile <filename> \
           \[-workDir <dirname<\] \[-definitionFile <filename>\] \[-useKickFiles 0 -kickFileX <filename> -kickFileY <filename>\]"

set argListRequired [list xRawResponse yRawResponse machineName]
set argList [concat $argListRequired useKickFiles kickFileX kickFileY definitionFile workDir xyRawResponse yxRawResponse dispRawFile]
foreach arg $argList {set $arg ""}
set useKickFiles 0
set workDir [exec pwd]
set definitionFile ""
APSParseArguments $argList
set error 0
foreach var $argListRequired {
    if ![string length [set $var]] {set error 1; puts stderr "Error: variable $var is empty."}
}
if $error {exit}
if {[string length $definitionFile] == 0} {
    set definitionFile $workDir/initialDefinitions.tcl
}

#-------------------------------------------------------------------------------------------------------------------------
proc AddTagNameColumn {args} {
    APSParseArguments {filename}
    exec sddsprocess $filename "-reprint=col,TagName,%s#%s#1,BPMName,Plane" -nowarning
    file delete ${filename}~
}
#-------------------------------------------------------------------------------------------------------------------------

proc TransformMeasuredFiles { args } {
    
    APSParseArguments {xRawResponse xyRawResponse hrmOutput yRawResponse yxRawResponse vrmOutput \
        dispRawFile dispMeasuredFile useKickFiles kickFileX kickFileY}
    
    global tmpDir hCalibFactor vCalibFactor dispCalibFactor dispFitWeight dispColumn machineName
    
    set tmpRoot $tmpDir/[APSTmpString]-transfMeas
    set deleteFiles ""

    #--- Prepare dispersion file: Transform dispersion measurement into 2-page 2-column (BPMName, Dispersion) file
    set addDispersion 0
    if [file exists $dispRawFile] {
	set addDispersion 1
        switch -exact -- $machineName {
	    APSU {
		foreach plane [list x y] Plane [list X Y] {
		    exec sddsconvert $dispRawFile -pipe=out -retain=col,Rootname,${plane}Dispersion \
			-rename=col,${plane}Dispersion=$dispColumn -rename=col,Rootname=BPMName \
			| sddsprocess -pipe=in $tmpRoot.$Plane -print=para,Plane,$Plane \
			"-redef=col,$dispColumn,$dispColumn $dispCalibFactor *"
		}
		exec sddscombine $tmpRoot.X $tmpRoot.Y $dispMeasuredFile -overWrite
                lappend deleteFiles $tmpRoot.X $tmpRoot.Y
	    }
            APS {
		foreach plane [list x y] Plane [list X Y] {
		    exec sddsconvert $dispRawFile -pipe=out -retain=col,Rootname,${plane}Dispersion \
			-rename=col,${plane}Dispersion=$dispColumn -rename=col,Rootname=BPMName \
			| sddsprocess -pipe=in $tmpRoot.$Plane -print=para,Plane,$Plane \
			"-redef=col,$dispColumn,$dispColumn $dispCalibFactor *"
		}
		exec sddscombine $tmpRoot.X $tmpRoot.Y $dispMeasuredFile -overWrite
                lappend deleteFiles $tmpRoot.X $tmpRoot.Y
            }
            APSBooster {
		foreach plane [list x y] Plane [list X Y] {
		    exec sddsconvert $dispRawFile -pipe=out -retain=col,Rootname,${plane}Dispersion \
			-rename=col,${plane}Dispersion=$dispColumn -rename=col,Rootname=BPMName \
			| sddsprocess -pipe=in $tmpRoot.$Plane -print=para,Plane,$Plane \
			"-redef=col,$dispColumn,$dispColumn $dispCalibFactor *"
		}
		exec sddscombine $tmpRoot.X $tmpRoot.Y $dispMeasuredFile -overWrite
                lappend deleteFiles $tmpRoot.X $tmpRoot.Y
            }
            generic {
                file copy -force $dispRawFile $dispMeasuredFile
            }
	    PAR {
		foreach plane [list x y] Plane [list X Y] {
		    exec sddsconvert $dispRawFile -pipe=out -retain=col,BPMNames,${plane}Dispersion \
			-rename=col,${plane}Dispersion=$dispColumn -rename=col,BPMNames=BPMName \
			| sddsprocess -pipe=in $tmpRoot.$Plane -print=para,Plane,$Plane "-reedit=col,BPMName,e i@$Plane@" \
			"-redef=col,$dispColumn,$dispColumn $dispCalibFactor *"
		}
		exec sddscombine $tmpRoot.X $tmpRoot.Y $dispMeasuredFile -overWrite
                lappend deleteFiles $tmpRoot.X $tmpRoot.Y
	    }
	    APSBTS {
		#--- Input should already be 2-page with plane parameter
		exec sddsconvert $dispRawFile -pipe=out -retain=col,BPMNames,dispersion \
		    | sddsprocess -pipe "-redef=col,$dispColumn,dispersion $dispCalibFactor *" \
		    "-edit=col,BPMName,BPMNames,%@AP@BTS:AP@ %@BP@BTS:BP@ %@CP@BTS:CP@ %@:x@@ %@:y@@" \
		    | sddsconvert -pipe=in $dispMeasuredFile -retain=col,BPMName,$dispColumn
	    }
            default {
                return -code error "Machine name $machineName is not known."
            }	
        }
    }
    if [catch {AddTagNameColumn -filename $dispMeasuredFile} result] {return -code error "AddTagNameColumn: $result"}
    
    if {[file exists $xRawResponse] && [file exists $yRawResponse] && [file exists $xyRawResponse] && [file exists $yxRawResponse]} {
	#--- Full coupled analysis
	set coupledMatrix 2
    } else {
	if {[file exists $xRawResponse] && [file exists $xyRawResponse]} {
	    #--- Non-coupled analysis
	    set coupledMatrix 0
	} else {
	    #--- Off-diagonal matrices only
	    set coupledMatrix 1
	}
    }
    switch -exact -- $coupledMatrix {
        0 {
            set measuredFileList [list $hrmOutput $vrmOutput]
            set calibFactorList [list $hCalibFactor $vCalibFactor]
            set rawFileList [list $xRawResponse $yRawResponse]
            set corPlaneList [list X Y]
            set bpmPlaneList [list X Y]
        }
        1 {
            set measuredFileList [list $hrmOutput $vrmOutput]
            set calibFactorList [list $hCalibFactor $vCalibFactor]
            set rawFileList [list $xyRawResponse $yxRawResponse]
            set corPlaneList [list X Y]
            set bpmPlaneList [list Y X]
        }
        2 {
            set measuredFileList [list $hrmOutput.page1 $hrmOutput.page2 $vrmOutput.page1 $vrmOutput.page2]
            set calibFactorList [list $hCalibFactor $hCalibFactor $vCalibFactor $vCalibFactor]
            set rawFileList [list $xRawResponse $xyRawResponse $yxRawResponse $yRawResponse]
            set corPlaneList [list X X Y Y]
            set bpmPlaneList [list X Y X Y]
        }
    }

    #--- Make files "corrector column and BPM row"; add plane at the end of BPM names and add #1 for occurence:
    foreach rawFile $rawFileList measuredFile $measuredFileList calibFactor $calibFactorList bpmPlane $bpmPlaneList {
	#------ Filtering out non-used elements and multiplying with calibration coefficients.
	switch -exact -- $machineName {
	    APSU {
		#--- APSU has corrector columns
		if [catch {exec sddsconvert $rawFile -pipe=out "-edit=col,*,e i@#1@" -del=para,* \
			       | sddsconvert -pipe -rename=col,BPMName#1=BPMName -rename=col,s#1=s \
			       | sddsprocess -pipe=in $measuredFile -reprint=para,Plane,$bpmPlane "-redef=col,s,s $calibFactor *" \
			       "-redefine=col,%s,%s $calibFactor /,select=*,exclude=*Name,units=m/rad"} result] {
		    return -code error "Error filtering elements in use (rawFile: $rawFile): $result"
		}
	    }
	    APSBooster {
		#--- APS booster has corrector columns and BPM in rows:
		if [catch {exec sddsconvert $rawFile -pipe=out -retain=col,B*C*,BPMName \
			       | sddsconvert -pipe "-edit=col,*,e i@#1@" \
			       | sddsconvert -pipe -rename=col,BPMName#1=BPMName \
			       | sddsprocess -pipe=in $measuredFile -reprint=para,Plane,$bpmPlane \
			       "-redefine=col,%s,%s $calibFactor /,select=*,exclude=*Name,units=m/rad"} result] {
		    return -code error "Error filtering elements in use (rawFile: $rawFile): $result"
		}
	    }
	    APS {
		#--- APS measurement file has BPMs in columns and correctors in rows:
		#------ Response is supplied in mm/A, therefore the calibFactor is in 1000*rad/A
		if [catch {exec sddsconvert $rawFile -pipe=out -rename=col,Corrector$bpmPlane=Corrector \
			       | sddsprocess -pipe "-reedit=col,Corrector,e i@#1@" \
			       | sddstranspose -pipe -oldColumnNames=BPMName -newColumnName=Corrector \
			       | sddsprocess -pipe=in $measuredFile -reprint=para,Plane,$bpmPlane \
			       "-redefine=col,%s,%s $calibFactor /,select=*,exclude=*Name,units=m/rad"} result] {
		    return -code error "Error filtering elements in use (rawFile: $rawFile): $result"
		}
	    }
	    PAR {
		#--- APS PAR has corrector columns and BPM in rows:
		if [catch {exec sddsprocess $rawFile -pipe=out "-reedit=col,BPMNames,e i@$bpmPlane@" \
			       | sddsconvert -pipe -retain=col,P*,BPMNames \
			       | sddsconvert -pipe "-edit=col,*,e i@#1@" \
			       | sddsconvert -pipe -rename=col,BPMNames#1=BPMName \
			       | sddsprocess -pipe=in $measuredFile -reprint=para,Plane,$bpmPlane \
			       "-redefine=col,%s,%s $calibFactor /,select=*,exclude=*Name,units=m/rad"} result] {
		    return -code error "Error filtering elements in use (rawFile: $rawFile): $result"
		}
	    }
	    APSBTS {
		#--- APSBTS has corrector columns and BPM in rows:
		if [catch {exec sddsconvert $rawFile -pipe=out -del=col,BPMName \
			       | sddsconvert -pipe "-edit=col,*,i@BTS:@ e i@#1@" \
			       | sddsconvert -pipe -rename=col,BTS:BPMNames#1=BPMName -rename=col,BTS:ES1#1=B2C9ES1C#1 -rename=col,BTS:ES2#1=B2C9ES2C#1 -rename=col,BTS:B2C8V#1=B2C8V#1\
			       | sddsprocess -pipe=in $measuredFile -reprint=para,Plane,$bpmPlane \
			       "-reedit=col,BPMName,%@AP@BTS:AP@ %@BP@BTS:BP@ %@CP@BTS:CP@ %@:x@@ %@:y@@" \
			       "-redefine=col,%s,%s $calibFactor /,select=*,exclude=*Name,units=m/rad"} result] {
		    return -code error "Error filtering elements in use (rawFile: $rawFile): $result"
		}
		if {[lsearch [exec sddsquery -col $measuredFile] B2C9ES*] != -1} {
		    exec sddsprocess $measuredFile -nowarning "-redef=col,B2C9ES1C#1,B2C9ES1C#1 1.7 *" "-redef=col,B2C9ES2C#1,B2C9ES2C#1 1.4 *"
		    file delete ${measuredFile}~
		}
		if {[lsearch [exec sddsquery -col $measuredFile] B2C8V*] != -1} {
		    exec sddsprocess $measuredFile -nowarning "-redef=col,B2C8V#1,B2C8V#1 -0.5 *"
		    file delete ${measuredFile}~
		}
	    }
	    default {
		return -code error "Machine name $machineName is not known."
	    }
	}
	if [catch {AddTagNameColumn -filename $measuredFile} result] {return -code error "AddTagNameColumn: $result"}
    }

    if {$coupledMatrix == 2} {
        exec sddscombine $hrmOutput.page1 $hrmOutput.page2 $hrmOutput -overWrite
        exec sddscombine $vrmOutput.page1 $vrmOutput.page2 $vrmOutput -overWrite
        lappend deleteFiles $hrmOutput.page1 $hrmOutput.page2 $vrmOutput.page1 $vrmOutput.page2
    }

    #------ Add dispersion to hResponse file:
    if $addDispersion {
	if [catch {AddDispersionColumn -hrmOutput $hrmOutput -dispMeasuredFile $dispMeasuredFile -dispColumn $dispColumn} result] {
	    return -code error "AddDispersionColumn: $result"
	}
    }

    catch {eval file delete $deleteFiles}
}

#-------------------------------------------------------------------------------------------------------------------------
proc AddDispersionColumn {args} {
    global tmpDir dispFitWeight
    APSParseArguments {hrmOutput dispMeasuredFile dispColumn}
    set tmpRoot $tmpDir/[APSTmpString]-addD
    #------ See if any BPMs are missing from dispersion file:
    if [catch {exec sddsselect $hrmOutput $dispMeasuredFile -pipe=out -match=TagName -inv \
		   | sddscombine -pipe -merge \
		   | sdds2stream -pipe=in -col=TagName} misingBpms] {
	return -code error "Error reading missing BPMs in $dispMeasuredFile file $misingBpms"
    }
    if [llength $misingBpms] {
	puts stdout "Error: the following BPMs are missing from dispersion file dispMeasuredFile ($hrmOutput -- $dispMeasuredFile): $misingBpms"
	exit
    }
    exec sddsxref $hrmOutput $dispMeasuredFile -pipe=out -take=$dispColumn -match=TagName -nowarning \
	| sddsprocess -pipe=in $tmpRoot "-redef=col,$dispColumn,$dispColumn $dispFitWeight *,symbol=,units="
    file copy -force $tmpRoot $hrmOutput
    file delete $tmpRoot
}
#-------------------------------------------------------------------------------------------------------------------------

if [catch {Fit_ReadDefinitionFile -definitionFile $definitionFile -workDir $workDir -warnings 0 \
	       -variableList "hrmMeasured vrmMeasured dispMeasuredFile hCalibFactor vCalibFactor dispCalibFactor dispFitWeight dispColumn zeroBpmTol"} result] {
    return -code error "Fit_ReadDefinitionFile: $result"
}

if 0 {
if [string match APSU $machineName] {
    exec sddsprocess $xRawResponse -pipe=out "-reprint=col,BPMName,%s#%s,BPMName,Plane" "-edit=col,TagName,BPMName,ei@#1@" \
	"-redefine=col,%s,%s $hCalibFactor /,select=S*,units=m/rad" "-redef=col,Dispersion,Dispersion $dispCalibFactor * $dispFitWeight *,symbol=,units=" \
	| sddsconvert -pipe=in $hrmMeasured.traMe "-editnames=col,S*,ei@#1@" -del=col,s
    exec sddsprocess $yRawResponse -pipe=out "-reprint=col,BPMName,%s#%s,BPMName,Plane" "-edit=col,TagName,BPMName,ei@#1@" \
	"-redefine=col,%s,%s $vCalibFactor /,select=S*,units=m/rad" \
	| sddsconvert -pipe=in $vrmMeasured.traMe "-editnames=col,S*,ei@#1@" -del=col,s
}
}
if [catch {TransformMeasuredFiles \
	       -xRawResponse $xRawResponse -xyRawResponse $xyRawResponse -hrmOutput $hrmMeasured.traMe \
	       -yRawResponse $yRawResponse -yxRawResponse $yxRawResponse -vrmOutput $vrmMeasured.traMe \
	       -dispRawFile $dispRawFile -dispMeasuredFile $dispMeasuredFile \
	       -useKickFiles $useKickFiles -kickFileX $kickFileX -kickFileY $kickFileY} result] {
    return -code error "TransformMeasuredFiles: $result"
}


exec touch $workDir/transformMeasuredFiles.done
puts stdout "locoTransformMeasuredFiles: done."
puts stdout " "
