from eu.omp.irap.cassis.gui.model.lineanalysis import LineAnalysisModel,LineAnalysisPanel,LineAnalysisControl,LineAnalysisDisplayEvent
from eu.omp.irap.cassis.common import MoleculeDescription, CommentedSpectrum, ComponentMode
from eu.omp.irap.cassis.gui.model.parameter.lteradexcomponent import ComponentDescription
from eu.omp.irap.cassis.gui import PanelView
from eu.omp.irap.cassis.gui.model.parameter.observing import ObservingMode
from eu.omp.irap.cassis.gui.model.parameter.continuum import ContinuumParameters
from java.util import ArrayList
from java.io import File
from javax.swing import JOptionPane
from eu.omp.irap.cassis.file import FileManagerVOTable
from eu.omp.irap.cassis.lineanalysis import LineAnalysisParameters
from eu.omp.irap.cassis.gui.model.parameter import TYPE_BAND
from eu.omp.irap.cassis.gui.model.parameter.threshold import QuantumNumberThresholdModel

from eu.omp.irap.cassis.file import FileReaderCassis
from eu.omp.irap.cassis.file import FileManagerFits

from eu.omp.irap.cassis.file import  FileManagerAsciiCassis
import ScriptUtilities
import ScriptConstants
from Constants import Constants
from eu.omp.irap.cassis.cassisd import ServerImpl

from eu.omp.irap.cassis.database.access import AccessDataBase
from inspect import isclass


def getSource(listMols, tag):
	if listMols is None:
		return "unknown"
	for mol in listMols:
		if mol.getSpeciesId() == str(tag):
			return mol.getSource()
	return "unknown"


class LineAnalysis(object):
	choice = None

	#====================
	# define a species
	def species(self, template, tag):
		L = []
		L.append(template) #0
		L.append(tag) #1
		return L

	#========================================
	# compute result according to the model
	def invokeSpectrumComputation(self):
#		CassisSpectrum 
		cassisSpectrum = self.model.getLoadDataModel().getCassisSpectrum()

#		EmAbTabbedPanelModel 
		lteRadexModel = self.model.getAbsorptionModel();

		#ArrayList<ComponentDescription> 
		componentsDescription = None
		if (self.model.isLteRadexSelected()) :
			componentsDescription = lteRadexModel.getComponentsWithMoleculeSelected()
		

		#HashMap<String, ParameterDescription> 
		mapPHashMap = self.model.getMapParameter()

#		Server
		lineAnalysisParams = LineAnalysisParameters(mapPHashMap, componentsDescription,
				self.model.getMoleculesSelected(),
				self.model.getParametersModel().getTelescope())
		server = ServerImpl()
		result = server.computeLineAnalysisSpectrum(lineAnalysisParams, cassisSpectrum)

		return result		

	#=======================
	# split array of datas with line Anlaysis Model
	def split(self, datas, tuningRange, tuningBand, plottingBand, plottingSort, species, 
				eup, aijMin=0.0, jup=["*", "*"], kup=["*", "*"], lup=["*", "*"], mup=["*", "*"]):
		splitDatas=[]
		for i in range (0, len(datas)) :
			resultVal, model = self.run(datas[i], tuningRange, tuningBand, plottingBand, plottingSort, species, 
				eup, aijMin, jup, kup, lup, mup)
			splitDatas.append(resultVal.getFileSpectrumList().get(0))
		return splitDatas	

	#=======================
	# split array of datas with line Anlaysis Model
	def split2(self, data, tuningRange, tuningBand, plottingBand, plottingSort, species, 
				eup, aijMin=0.0,jup=["*", "*"], kup=["*", "*"], lup=["*", "*"], mup=["*", "*"]):
		splitDatas=[]
	
		resultVal, model = self.run(data, tuningRange, tuningBand, plottingBand, plottingSort, species, 
			eup, aijMin, jup, kup, lup, mup)
		for i in range (0, resultVal.getFileSpectrumList().size()) :
			splitDatas.append(resultVal.getFileSpectrumList().get(i))
		return splitDatas	

	#=======================
	# run LineAnalysis model
	def run(self, cassisSpectrum, tuningRange, tuningBand, plottingBand, plottingSort, species, 
				eup, aijMin=0.0, jup=["*", "*"], kup=["*", "*"], lup=["*", "*"], mup=["*", "*"],  
				telescope="telescope-file-needed", tmb2ta=False, tbg=2.73, overSampling=3.0, rms=0., 
				components=[], warning=True, continuum = 0, observing_mode = ObservingMode.PSDBS):
		
		self.model = LineAnalysisModel()

		#datafile
		self.model.getLoadDataModel().setCassisSpectrum(cassisSpectrum)
		self.model.getLoadDataModel().setNameData(cassisSpectrum.getTitle())
		
		#tuning
		self.model.getTunningModel().setMinValue(tuningRange[ScriptConstants.MIN])
		self.model.getTunningModel().setMaxValue(tuningRange[ScriptConstants.MAX])
		self.model.getTunningModel().setBandValue(tuningBand)

		self.model.setTemplateMoleculeList(species[ScriptConstants.LA_SPECIES_TEMPLATE])
		self.model.setTemplate(species[ScriptConstants.LA_SPECIES_TEMPLATE])

		if isinstance(species[ScriptConstants.LA_SPECIES_TAG], int):
			self.model.setTagMoleculeSelected(str(species[ScriptConstants.LA_SPECIES_TAG]))
		elif isinstance(species[ScriptConstants.LA_SPECIES_TAG], list):
			for tag in species[ScriptConstants.LA_SPECIES_TAG]:
				self.model.setTagMoleculeSelected(str(tag))
		else:
			raise ValueError("Unknown type for species tag(s).")

		#eup
		self.model.getThresholdModel().setThresEupMin(eup[ScriptConstants.MIN])
		self.model.getThresholdModel().setThresEupMax(eup[ScriptConstants.MAX])

		#aijmin
		self.model.getThresholdModel().setThresAijMin(aijMin)

		#Quantum number threshold (jup, kup, lup, mup)
		qntm = QuantumNumberThresholdModel()
		qntm.setJupMin(str(jup[0]))
		qntm.setJupMax(str(jup[1]))
		qntm.setKupMin(str(kup[0]))
		qntm.setKupMax(str(kup[1]))
		qntm.setLupMin(str(lup[0]))
		qntm.setLupMax(str(lup[1]))
		qntm.setMupMin(str(mup[0]))
		qntm.setMupMax(str(mup[1]))
		self.model.getThresholdModel().setQntm(qntm)
		
		#telescope
		self.model.getParametersModel().setSelectedTelescope(telescope)
		self.model.getLoadDataModel().setTelescope(telescope)

		#tmb2ta
		self.model.getParametersModel().setTmbTa(tmb2ta)
		
		#observing_mode
		self.model.getObservingModel().setObserving(observing_mode)
		
		#tbg
		self.model.getTbgModel().setTbg(tbg)

		#overSampling
		self.model.getOversamplingModel().setOversampling(overSampling)

		#noise rmse
		self.model.getNoiseModel().setNoise(rms)
		
		#components
		continuumCompo = self.model.getAbsorptionModel().addContinuumComponent(True)
		if isinstance(continuum, float) or isinstance(continuum, int):
			continuumCompo.setConstantContinuum(float(continuum))
			continuumCompo.getContinuumModel().setSelectedContinuum(ContinuumParameters.DEFAULT_0)
		else :
			continuumCompo.setConstantContinuum(0.0)
			continuumCompo.getContinuumModel().setSelectedContinuum(continuum)

		num_compo_species = 1
		for com in components:
			#get the current component with the default values
			comDesc = self.model.getAbsorptionModel().addNewComponent()
			comDesc.setComponentName("Component %d" % num_compo_species)
			num_compo_species = num_compo_species +1

			# Geometry for the component
			if com[ScriptConstants.RADEX_COMPONENT_GEOMETRY].lower() == "sphere":
				comDesc.setGeometryMode(ComponentMode.SPHERE_MODE)
			elif com[ScriptConstants.RADEX_COMPONENT_GEOMETRY].lower() == "expanding sphere":
				comDesc.setGeometryMode(ComponentMode.EXPANDING_SPHERE_MODE)
			else:
				comDesc.setGeometryMode(ComponentMode.SLAB_MODE)

			#modify the component attributes
			if com[ScriptConstants.RADEX_COMPONENT_MODEL].lower()=="lteradex":
				comDesc.setLteRadexMode(True)
			elif com[ScriptConstants.RADEX_COMPONENT_MODEL].lower()=="radex":
				comDesc.setFullRadexMode(True)
			else:
				comDesc.setFullLteMode(True)

			comDesc.setDensity(com[ScriptConstants.RADEX_COMPONENT_DENSITY]) #n
			comDesc.setVlsr(com[ScriptConstants.RADEX_COMPONENT_VLSR]) #vlsr
			comDesc.setInteracting(com[ScriptConstants.RADEX_COMPONENT_INTERACTING])#interacting
		
			simpleMols = AccessDataBase.getDataBaseConnection().getAllMoleculeDescriptionDB()
			moleculeList = ArrayList()
			for mol in com[ScriptConstants.RADEX_COMPONENT_MOLECULES]: #molecules
				radexMolDesc = MoleculeDescription()
				radexMolDesc.setName(mol[ScriptConstants.RADEX_MOLECULE_NAME])
				if mol[ScriptConstants.RADEX_MOLECULE_DATABASE] == "unknown":
					radexMolDesc.setDataSource(getSource(simpleMols, mol[ScriptConstants.RADEX_MOLECULE_TAG]))
				else:
					radexMolDesc.setDataSource(mol[ScriptConstants.RADEX_MOLECULE_DATABASE])
				radexMolDesc.setSourceSize(mol[ScriptConstants.RADEX_MOLECULE_SIZE])
				radexMolDesc.setSpeciesId(str(mol[ScriptConstants.RADEX_MOLECULE_TAG]))
				radexMolDesc.setTemperature(mol[ScriptConstants.RADEX_MOLECULE_TEX])
				radexMolDesc.setDensity(mol[ScriptConstants.RADEX_MOLECULE_NMOL])
				radexMolDesc.setVelocityDispersion(mol[ScriptConstants.RADEX_MOLECULE_FWHM])
				radexMolDesc.setTKin(mol[ScriptConstants.RADEX_MOLECULE_TKIN])
				radexMolDesc.setCollision(mol[ScriptConstants.RADEX_MOLECULE_COLLISION])
				radexMolDesc.setCompute(True)
				moleculeList.add(radexMolDesc)
			comDesc.getCassisTableMoleculeModel().setList(moleculeList)
			mol = moleculeList.get(0)
			if not (ScriptConstants.RADEX_COMPONENT_TEX in com):
				comDesc.setTex(mol.getTemperature())
			else:
				comDesc.setTex(com[ScriptConstants.RADEX_COMPONENT_TEX])
			if not (ScriptConstants.RADEX_COMPONENT_TKIN in com):
				comDesc.setTkin(mol.getTKin())
			else:
				comDesc.setTex(com[ScriptConstants.RADEX_COMPONENT_TKIN])
			if not (ScriptConstants.RADEX_COMPONENT_SIZE in com):
				comDesc.setSize(mol.getSourceSize())
			else:
				comDesc.setSize(com[ScriptConstants.RADEX_COMPONENT_SIZE])
		
		#absorption model is selected if components not null
		self.model.setLteRadexSelected( len(components) != 0 )
		#warning
		if self.choice == None:
			if warning == False:
				self.choice = JOptionPane.YES_NO_OPTION;

		#run
#		self.control = LineAnalysisControl(self.model, None) #bug because we must put this before manipulate model
		#self.control.invokeSpectrumComputation()
#	
		#self.result = self.control.getResult()
		self.result = self.invokeSpectrumComputation()
		return self.result, self.model

	#========================================
	# plot the result
	def plot(self):
		panel = LineAnalysisPanel(self.model)
		panel.getControl().setResult(self.result)
		#add a model view in Cassis
		lineAnalysisControl = PanelView.getInstance().addLtelineView(panel, False)
		#self.control.getView().refresh()

		#plot in Cassis
		event = LineAnalysisDisplayEvent(panel.getControl(), self.model, self.result)
		if self.result != None and self.result != []:
			panel.getControl().fireLteLineTableDisplayEvent(event)
		return PanelView.getInstance().switchToMoleculeTab().getControl()


	#========================================
	# output the result to 'dir'
	def output(self, dir, prefix, index):
		self.choice = ScriptUtilities.checkExist(dir, self.choice)
		print('choice=', self.choice)

		if self.choice == JOptionPane.NO_OPTION or self.choice == JOptionPane.CLOSED_OPTION:
			self.filename = dir + File.separator + prefix + str(index)
			while True:
				if File(self.filename + '.votable').exists():
					self.filename = self.filename + '_1'
				else:
					break;
			self.filename += '.votable'
		else:
			self.filename = dir + File.separator + prefix + str(index) + '.votable'
		print(self.filename)

		file = File(self.filename)
		saver = FileManagerVOTable(file)
		fsl = self.result.getFileSpectrumList()
		for cs in fsl:
			if isinstance(cs, CommentedSpectrum):
				print('+1')
				saver.save(file, cs)
		return


	#========================================
	# make a config file # TODO or to see old lteLineversion
	def makeConfig(self, configname):
		#self.model.makeConfig(configname, self.filename)
		return

	#========================================
	# read datas from path  directory+moleculeName+transitions[i]+".lis" # TODO only lis for the moment, to generalyse 
	def readData (self, directory, moleculeName, transitions, extensionName, indice_hdu=0):
		commentedData=[]
		for i in range (0, len(transitions)) :
			file = File(directory+moleculeName+transitions[i]+extensionName) 
			print("file = ",file)
			#data = FileManagerAsciiCassis(file)
			#cassisSpectrum = data.read()
			if (extensionName == '.fits' or extensionName == '.fts') and (indice_hdu != -1):
				fileManager = FileManagerFits(file, False)
				print("indice_hdu = " + str(indice_hdu))
				cassisSpectrum = fileManager.read(indice_hdu)
	 		else:
		 		cassisSpectrum = FileReaderCassis.createCassisSpectrumFromFile(file)
			commentedData.append(cassisSpectrum)
		return commentedData


	#========================================
	# compute chi2
	def computechi2 (self, intensityData, intensityModel, rms, cal):
		return ((intensityData - intensityModel) *(intensityData - intensityModel))/ ((rms * rms) + (cal * cal * intensityData * intensityData))

	#========================================
	# rescale data
	def rescale(self, dataArrays, modelArrays) :
		dataFreq = dataArrays.getFrequenciesSignal() 
		modelFreq = modelArrays.getFrequenciesSignal() 
		dataIntensity = dataArrays.getIntensities() 
		modelIntensity = modelArrays.getIntensities() 
		lengthData = len(dataFreq)
		lengthModel = len(modelFreq)
		#print('nbCHaIn = ' +str(lengthData) + ' nbModelIN = ' + str(lengthModel))
		cpt=0
		while (cpt < lengthData) and (dataFreq[cpt] < modelFreq[cpt]) :   
			cpt += 1
		#print('cpt1 = ' + str(cpt))
		if (cpt == 0):
			while (cpt < lengthModel) and (dataFreq[cpt] > modelFreq[cpt]) :   
				cpt += 1
				#print('cpt2 = ' + str(cpt))
			if (cpt != 0) :
				#syncro at the begin
				for i in range (0, cpt) :
					modelFreq.pop(0)
					modelIntensity.pop(0)
			if (len(dataFreq) != len(modelFreq)): # if have to remove the end
				if (len(dataFreq) > len(modelFreq)) : #if more data, remove data
					cpt = len(dataFreq) - len(modelFreq)
					for i in range (0, cpt) :
						dataFreq.pop(-1)
						dataIntensity.pop(-1)
				else : 
					cpt = len(modelFreq) - len(dataFreq)
					for i in range (0, cpt) :
						modelFreq.pop(-1)
						modelIntensity.pop(-1)
				
		else :
			for i in range (0, cpt) :
				dataFreq.pop(0)
				dataIntensity.pop(0)	
			if (len(dataFreq) != len(modelFreq)): # if have to remove the end
					if (len(dataFreq) > len(modelFreq)) : #if more data, remove data
						cpt = len(dataFreq) - len(modelFreq)
						for i in range (0, cpt) :
							dataFreq.pop(-1)
							dataIntensity.pop(-1)
					else : 
						cpt = len(modelFreq) - len(dataFreq)
						for i in range (0, cpt) :
							modelFreq.pop(-1)
							modelIntensity.pop(-1)
	
		dataArrays.setListOfChannels(dataFreq, dataIntensity)
		modelArrays.setListOfChannels(modelFreq, modelIntensity)
