
/****************************************************
EndMembers LAUNCHER
****************************************************/
class EndMembersLauncher: MSA112_UIFrame
{
number sparsity
number radius	//spot radius to mark endmember
number MapsCubed

number hits
number AutoMethod,ClustMethod
number lambda

string MSAlabel	

number TableauID
number WaitingID
number MSAID

number enablingState


TagGroup CreateHead(object self)
	{
	TagGroup Dialog = DLGCreateDialog("display results")
	//Dialog.DLGTableLayout(4,1,0)
	
		TagGroup Upper = DLGCreateDialog("display results")
		Upper.DLGTableLayout(3,1,0)
	Upper.DLGAddElement(DLGCreateLabel(""+MSA112_Version()+"    "))
	Upper.DLGAddElement(self.InfoButton(20,210))	
	Upper.DLGAddElement(self.settingsButton(20,210,"Settings").DLGanchor("East"))
		TagGroup Lower = DLGCreatedialog("")
		Lower.DLGTableLayout(3,1,0)
	Lower.DLGAddElement(DLGCreateLabel("cluster"))
	Lower.DLGAddElement(DLGCreateIntegerField(0,4).DLGIdentifier("cluster").DLGanchor("West"))		
	Lower.DLGAddElement(DLGcreateLabel("hold ALT for info").DLGAnchor("East"))
	

	Dialog.DLGAddElement(Upper)
	Dialog.DLGAddElement(Lower)
	
	return Dialog
	}

	
TagGroup Create_Start(object self)
	{
	TagGroup Dialog = DLGCreateDialog("")
	Dialog.DLGTableLayout(3,1,0)
	
	Dialog.DLGAddElement(DLGCreatePushButton("new ","newTableau").DLGIdentifier("MakeNew").DLGanchor("West"))
	Dialog.DLGAddElement(DLGCreatePushButton("tune old","loadTableau").DLGIdentifier("TuneOld").DLGanchor("East"))	
	Dialog.DLGAddElement(DLGCreatePushButton("load old","loadMaps").DLGIdentifier("LoadOld").DLGanchor("East"))
	
	return Dialog
	}

TagGroup Create_Plot(object self)
	{
	TagGroup Dialog = DLGCreateDialog("").DLGIdentifier("scatter")
	Dialog.DLGTableLayout(3,1,0)
	
	Dialog.DLGAddElement(DLGCreatePushButton("add plot X-Y","PlotScatter").DLGIdentifier("AddScatter").DLGanchor("East"))	
	Dialog.DLGAddElement(DLGCreateIntegerField(3,5).DLGIdentifier("compF").DLGanchor("West"))
	Dialog.DLGAddElement(DLGCreateIntegerField(2,5).DLGIdentifier("compS").DLGanchor("West"))

	return Dialog
	}

TagGroup Create_AutoBox(object self)
	{	
	TagGroup Dialog = DLGCreateBox("auto-finding endmembers").DLGIdentifier("autoendmembers").DLGTableLayout(4,1,0)

	Dialog.DLGAddElement(DLGCreatePushButton("find","FindAuto").DLGIdentifier("findAuto").DLGanchor("West"))
	Dialog.DLGAddElement(DLGCreateLabel("show:").DLGanchor("East"))	
	Dialog.DLGAddElement(DLGCreatePushButton("sphere","ShowSphere").DLGIdentifier("sphere").DLGanchor("West"))
	Dialog.DLGAddElement(DLGCreatePushButton("hits","ShowHits").DLGIdentifier("hits").DLGanchor("West"))
		
	return Dialog
	}
	
TagGroup ColoredPanel(object self)
	{
	number colors = 6	
	number height = 24
	number narr = 8
	number width = narr*colors
	
	rgbimage color := rgbImage("",4,width,height)
	
	for(number i=1;i<=colors;i++)
		{
		color[0,(i-1)*narr,height,i*narr] = MSA112_ClusterColor(i)
		}

	taggroup Pan = DLGCreateGraphic(width,height)		
	Pan.DLGAddBitmap(color)	
	
	return Pan
	}

	
TagGroup Create_TuneBox(object self)
	{	
	TagGroup Dialog1 = DLGCreateDialog("").DLGTableLayout(3,1,0)
	Dialog1.DLGAddElement(DLGCreatePushButton(" add member","AddMember").DLGanchor("West"))
	Dialog1.DLGAddElement(DLGCreateLabel(": "+0+" ").DLGIdentifier("EndMembN").DLGanchor("West"))	
	Dialog1.DLGAddElement(self.ColoredPanel())
	//Dialog1.DLGAddElement(DLGCreateLabel("members").DLGanchor("East"))	
	
	TagGroup Dialog2 = DLGCreateDialog("").DLGTableLayout(4,1,0)		
	Dialog2.DLGAddElement(DLGCreatePushButton("fit one","FitOne").DLGanchor("West"))
	Dialog2.DLGAddElement(DLGCreatePushButton("fit all","FitAll").DLGIdentifier("ALS").DLGanchor("East"))
	Dialog2.DLGAddElement(DLGCreateLabel("           ").DLGanchor("West"))	
	//Dialog2.DLGAddElement(DLGCreatePushButton("order","orderLoadings").DLGIdentifier("ALS").DLGanchor("East"))	
		number size=18,Bcgrd=210,borderWidth=2
Dialog2.DLGAddElement(self.Button112(self.Isort(size,Bcgrd,borderWidth),"orderLoadings"))

	TagGroup Dialog = DLGCreateBox("tune endmembers").DLGIdentifier("tuned")
	Dialog.DLGAddElement(Dialog1)
	Dialog.DLGAddElement(Dialog2)
		
	return Dialog
	}


TagGroup Create_Finalize(object self)
	{
	TagGroup Dialog = DLGCreateDialog("").DLGIdentifier("finalize")
	Dialog.DLGTableLayout(3,1,0)
	
	Dialog.DLGAddElement(DLGCreatePushButton("make maps","BuildMaps").DLGIdentifier("ShowMaps").DLGanchor("West"))
	Dialog.DLGAddElement(DLGCreatePushButton("close","eraseTableau").DLGIdentifier("erase").DLGanchor("West"))	
	Dialog.DLGAddElement(DLGCreatePushButton(" store ","storeTableau").DLGIdentifier("storeTableau").DLGanchor("West"))
	
	return Dialog
	}		
	
TagGroup CreateAllBoxes(object self)
	{
	TagGroup Dialog = DLGCreatedialog("")

	Dialog.DLGAddElement(self.CreateHead())
	Dialog.DLGAddElement(self.Create_Start())
	Dialog.DLGAddElement(self.Create_Plot())	
	Dialog.DLGAddElement(self.Create_AutoBox())	
	Dialog.DLGAddElement(self.Create_TuneBox())
	Dialog.DLGAddElement(self.Create_Finalize())
	
	return Dialog
	}


void EnablingAuto(object self,number StateAuto)
	{	
	self.SetElementIsEnabled("findAuto",StateAuto)		
	}
	
void EnablingButtons(object self,number state)
	{
	self.SetElementIsEnabled("scatter",State)
	self.SetElementIsEnabled("tuned",State)	
	self.SetElementIsEnabled("finalize",State)
	self.SetElementIsEnabled("autoendmembers",State)
	
	self.SetElementIsEnabled("MakeNew",!State)
	self.SetElementIsEnabled("TuneOld",!State)	
	self.SetElementIsEnabled("LoadOld",!State)	
	
	if(state==0) self.lookupElement("EndMembN").DLGTitle(": "+0)
	enablingState = state
	}

	
number EnablingAll(object self)	//This is needed for INFO-mode
	{
	self.SetElementIsEnabled("scatter",1)
	self.SetElementIsEnabled("tuned",1)
	self.SetElementIsEnabled("autoendmembers",1)
	self.SetElementIsEnabled("hits",1)	
	self.SetElementIsEnabled("Confirm",1)	
	self.SetElementIsEnabled("finalize",1)
	
	self.SetElementIsEnabled("MakeNew",1)
	self.SetElementIsEnabled("LoadOld",1)	
	
	return enablingState
	}
	
object init(object self,string Package,string Name,string MSAlabelP)
	{
	MSAlabel = MSAlabelP
	
	self.MSA112_initUIFrame(self.CreateAllBoxes(),Package,Name)	
	
	try{self.EnablingButtons(0);}
	catch{break;}
	
	//get basic parameters
	sparsity = self.MSA112P_sparsity()
	Radius = self.MSA112P_Rad()
	MapsCubed = self.MSA112P_MapsCubed()
	
	lambda =self.MSA112P_lambda()
	
	//get advanced parameters
	hits =self.MSA112P_VCAhits()
	AutoMethod =self.MSA112P_hitsMethod()
	ClustMethod =self.MSA112P_clustMethod()
	
	MSA112_reset()
	
	return self	
	}

void CloseUIFrame(object self)
	{
	//add some actions if neccesary
	}

/*********************Setting****************************/
void Settings(object self)
	{	
	number NumberLines = 3 	//number of adjusted parameters
	 
	TagGroup SettingList = DLGCreateBox("Settings").DLGTableLayout(1,NumberLines,1)

	taggroup tg1 =	self.AddSettingsLine_Int(SettingList,self.MSA112P_sparsity(),4)
	taggroup tg2 =	self.AddSettingsLine_Int(SettingList,self.MSA112P_Rad(),4)
	taggroup tg3 =	self.AddSettingsLine_Check(SettingList,self.MSA112P_MapsCubed())
	
	taggroup tg4,tg5,tg6,tg7,tg8
	
		
	MSA112_reset()
	
	object SettingsFrame = Alloc(UIframe).init(SettingList)
	if(SettingsFrame.Pose())
		{
		sparsity = self.SettingNumberParameter(tg1)
		Radius = self.SettingNumberParameter(tg2)
		MapsCubed = self.SettingNumberParameter(tg3)
	
		}
	}
	
image CheckMSAimage(object self,number stored)
	{
	number CurrCluster = self.LookUpElement("cluster").DLGgetValue()
	
	image MSAimage:=getFrontImage()

	//Check if it is MSA container	
	TagGroup MatrixTags = MSA112_GetMatrixTags(MSAimage,0)
	if(!MatrixTags.TagGroupIsValid()) exit(0)

	//Check if there are enough PCA components
	number CompN =MSA112_ReadNumberComponents(MatrixTags,currCluster,"PCA")
	if(CompN<2)
		{
		OKdialog("At least 2 PCA components must be extracted !!")
		exit(0)		
		}
	
	//Check if there are stored endmembers
	if(stored)
		{
		string 	clusterLabel = MSA112_GetClusterLabel(currCluster)				
		TagGroup StoredEndMembers
		MatrixTags.TagGroupGetTagAsTagGroup(ClusterLabel+":EndMembering",StoredEndMembers)
		if(!StoredEndMembers.TagGroupIsValid())	
			{
			OKdialog("There are no stored Endmembers \nin MSA container !!")
			exit(0)
			}
		}
	
	return MSAimage
	}


	
void newTableau(object self)
	{
	self.MSA112_Info("new",-20,50,\
	"press this button"+\
	"\nwhen wish to design"+\
	"\nnew endmembers"+\
	"\nin front-most" +\
	"\nMSA container")
	
	image MSAimage :=self.CheckMSAimage(0)
	MSAID =MSAimage.ImageGetID()
	number CurrCluster = self.LookUpElement("cluster").DLGgetValue() 
	
	object EMTableau = alloc(MSA_EndMembersTableau)
	TableauID = EMTableau.init(MSAID,CurrCluster,self.scriptObjectGetID(),sparsity,radius);	

	EMTableau.newTableau()

	MSA112_restoreLoadingPositionAndSize(EMTableau.GetFirstLoading(),"EndMembers:first Loading")
	MSA112_restoreLoadingPositionAndSize(EMTableau.GetLastLoading(),"EndMembers:last Loading")

//EMTableau.getTableauTags().TagGroupOpenBrowserWindow(0)		
	}

	
void orderLoadings(object self)	
	{
	self.MSA112_Info("order",360,200,\
	"order positions and"+\
	"\nsize of displayed"+\
	"\nendmember spectra"+\
	"\n(they'll be cascaded"+\
	"\nbetween first and"+\
	"\nlast endmembers)")
	
	object Tableau =GetScriptObjectFromID(TableauID)

	number endMembN =Tableau.GetNumberLoadings()
	
	number Xini,Yini,widthIni,heightIni	
	image FirstLoading := Tableau.GetFirstLoading()	
	MSA112_GetLoadingPositionAndSize(FirstLoading,Xini,Yini,widthIni,heightIni)

	number Xfin,Yfin,widthFin,heightFin
	image LastLoading := Tableau.GetLastLoading()
	MSA112_GetLoadingPositionAndSize(LastLoading,Xfin,Yfin,widthFin,heightFin)
	
	number width = widthFin
	number height = heightFin
	number spacingX =(Xfin-Xini)/(endMembN-1)
	number spacingY =(Yfin-Yini)/(endMembN-1)
	
	for(number i=0;i<endMembN;i++)
		{
		image Loading := Tableau.GetLoading(i)
		MSA112_SetLoadingPositionAndSize(Loading,Xini+spacingX*i,Yini+spacingY*i,width,height)
		}		
	}


void loadTableau(object self)
	{
	self.MSA112_Info("tune old",160,140,\
	"press this button"+\
	"\nwhen wish to tune"+\
	"\nstored endmembers"+\
	"\nin front-most" +\
	"\nMSA container")
	
	image MSAimage :=self.CheckMSAimage(1)
	MSAID =MSAimage.ImageGetID()
	
	number CurrCluster = self.LookUpElement("cluster").DLGgetValue()
	
	object EMTableau = alloc(MSA_EndMembersTableau)
	TableauID = EMTableau.init(MSAID,CurrCluster,self.ScriptObjectGetID(),sparsity,radius);	

	EMTableau.loadTableau()
	
	MSA112_restoreLoadingPositionAndSize(EMTableau.GetFirstLoading(),"EndMembers:first Loading")
	MSA112_restoreLoadingPositionAndSize(EMTableau.GetLastLoading(),"EndMembers:last Loading")

	self.orderLoadings()
	}
	
	
	
void addMember(object self)
	{
	self.MSA112_Info("add member",0,170,\
	"adding extra"+\
	"\nendmember"+\
	"\nto existing set"+\
	"\n(the pallet shows"+\
	"\ncolors of sequential" +\
	"\nendmembers)")
	
	object Tableau = GetScriptObjectFromID(TableauID)
	if(Tableau.ScriptObjectIsValid()) Tableau.AddEndMember()
//Tableau.getTableauTags().TagGroupOpenBrowserWindow(0)
	
	MSA112_restoreLoadingPositionAndSize(Tableau.GetLastLoading(),"EndMembers:last Loading")
	orderLoadings(self)
	}

void CloseWaiting(object self,string buttonIdentifier)
	{	//this is called from EMTableau class
	self.EndThread(buttonIdentifier,WaitingID)
	}

TagGroup GetMatrixTags(object self)
	{	
	image MSAimage := getImageFromID(MSAID)

	return MSA112_GetMatrixTags(MSAimage,0)
	}

string GetClusterLabel(object self)
	{	
	number clust =self.LookUpElement("cluster").DLGgetValue()

	return MSA112_GetClusterLabel(clust)
	}
		
void PlotScatter(object self)	
	{	
	self.MSA112_Info("add Plot X-Y",-10,70,\
	"adding extra"+\
	"\nscatter plot"+\
	"\nwith indicated"+\
	"\ncomponent indexes"+\
	"\nin addition to" +\
	"\ndefault '1-2' plot")
	
	number First = self.LookUpElement("compF").DLGgetValue()
	number Second = self.LookUpElement("compS").DLGgetValue()
	number CurrCluster = self.LookUpElement("cluster").DLGgetValue()
	
	if(!GetScriptObjectFromID(TableauID).NewScatterPlot(First,Second,currCluster))
		{
		OKdialog("Scatterplot "+First+"-"+Second+" is already drawn !!") 
		}
	}

	
void ShowHits(object self)
	{
	self.MSA112_Info("confirm",350,120,\
	"press this knob"+\
	"\nto see all"+\
	"\nendmembers"+\
	"\nhitted by VCA")
	
	}

void ShowSphere(object self)
	{
	self.MSA112_Info("confirm",330,120,\
	"press this knob"+\
	"\nto see a sphere"+\
	"\nfor custering VCA"+\
	"\nendmembers")
		
	}

	
	
void FindAuto(object self)
	{
	self.MSA112_Info("find",-10,120,\
	"automatic finding"+\
	"\nof endmembers"+\
	"\nwithin a space"+\
	"\ndefined by"+\
	"\ngiven number of" +\
	"\nPCA components")
		
	}

	
		
void FitOne(object self) 
	{
	self.MSA112_Info("fit one",20,200,\
	"fit the position of"+\
	"\ncurrently selected"+\
	"\nendmember for"+\
	"\nmaximal density"+\
	"\nof data points in"+\
	"\nhidden dimensions")
	
	}


void FitALS(object self)		//Fire Thread
	{
result("\nlambda in "+lambda)	
	
	GetScriptObjectFromID(TableauID).FitALS(lambda)
	}
	
void FitAll(object self)		//Fire Thread
	{
	self.MSA112_Info("fit all",200,320,\
	"fit the positions of"+\
	"\nall endmembers"+\
	"\nto maximize "+\
	"\ncapturing of all"+\
	"\ndata points")
	
	}


//Make Maps section
	
void MakeCurrentEndmemberMaps(object self)	//Thread
	{
	try{
	image EndMembers,Abundancies
	GetScriptObjectFromID(TableauID).MakeMaps(EndMembers,Abundancies,lambda)
	
	number MapsCubed = MSA112P_MapsCubed(self)
	image MSAimage := getImageFromID(MSAID)
	TagGroup MatrixTags = MSA112_GetMatrixTags(MSAimage,0)
	
	number CurrCluster = self.LookUpElement("cluster").DLGgetValue()
	
	string DataName = MSAimage.getName()
	MSA112_EndMemberMaps(EndMembers,Abundancies,MatrixTags,currCluster,DataName,MapsCubed)	
		}
	catch
		{
		break	
		}
	
	self.CloseWaiting("BuildMaps")
	}
	
							
void BuildMaps(object self)	//Lunch "MakeCurrentEndmemberMaps" as a thread
	{
	self.MSA112_Info("make maps",-30,280,\
	"generate abundance"+\
	"\nmaps for currently"+\
	"\nshown endmembers")

	
	object Tableau = GetScriptObjectFromID(TableauID)
	if(Tableau.ScriptObjectIsValid()) 
		{
		WaitingID = self.StartThreadFromDLG("MakeCurrentEndmemberMaps","BuildMaps")	
		}
	}	

void LoadMaps(object self)	//Lunch "MakeCurrentEndmemberMaps" as a thread
	{	
	self.MSA112_Info("load old",340,50,\
	"press this button"+\
	"\nto see endmembers"+\
	"\nand maps stored"+\
	"\nin front-most" +\
	"\nMSA container")
	
	image MSAimage := self.CheckMSAimage(1)	//check also if there are endmembers
	TagGroup MatrixTags = MSA112_GetMatrixTags(MSAimage,0)
	
	number CurrCluster = self.LookUpElement("cluster").DLGgetValue()
	
	string clusterLabel = MSA112_GetClusterLabel(currCluster)
	TagGroup TableauTags	
	MatrixTags.TagGroupGetTagAsTagGroup(clusterLabel+":EndMembering",TableauTags)
//TableauTags.TagGroupOpenBrowserWindow(0)	

	//check if there are maps
	TagGroup testTg
	if(!TableauTags.TagGroupGetTagAsTagGroup(":EMSpectra",testTg))
		{
		OKdialog("Endmember maps\nwere not extracted\nload endmembers\nby 'tune old', then\npress 'make maps'")
		exit(0)
		}
	
	image EndMembers =TableauTags.MSA112_getImagefromTags("EMSpectra")
	image Abundancies = TableauTags.MSA112_getImagefromTags("Abundancies")
	
	number MapsCubed = MSA112P_MapsCubed(self)
	string DataName = MSAimage.getName()
	MSA112_EndMemberMaps(EndMembers,Abundancies,MatrixTags,currCluster,DataName,MapsCubed)
	}

	
void EraseTableau(object self)
	{
	self.MSA112_Info("erase",180,370,\
	"stop endmembering"+\
	"\nand erase currently"+\
	"\nshown endmembers"+\
	"\nand their spectra")
	
	object Tableau = TableauID.getScriptObjectFromID()
	
	if(Tableau.ScriptObjectIsValid())
		{
		number membN =Tableau.GetNumberLoadings()
		
		//store the first,last loading positions
		MSA112_storeLoadingPositionAndSize(Tableau.GetFirstLoading(),"EndMembers:first Loading")
		if(membN>=2)	//otherwise the last loading is the first one
			{
		MSA112_storeLoadingPositionAndSize(Tableau.GetLastLoading(),"EndMembers:last Loading")
			}
			
		if(OKcancelDialog("do you want to\nclose endmembers \nwithout storing ?")) 
			{	
			Tableau.CloseTableau()
			}

		}	
	}


void storeTableau(object self)
	{
	self.MSA112_Info("store",350,280,\
	"store currently"+\
	"\nshown endmembers"+\
	"\nin MSA container")
	
	object Tableau = TableauID.getScriptObjectFromID()
	if(Tableau.ScriptObjectIsValid()) Tableau.StoreTableau()
	}
	
}

void createAll()
{
alloc(EndMembersLauncher).init(MSA112_MSApath(),"MSA endMembers",MSA112_Label()) 

}

createAll()
