
/* ========================
 * JSynoptic : a free Synoptic editor
 * ========================
 *
 * Project Info:  http://jsynoptic.sourceforge.net/index.html
 * 
 * This program is free software; you can redistribute it and/or modify it under the terms
 * of the GNU Lesser General Public License as published by the Free Software Foundation;
 * either version 2.1 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along with this
 * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 * (C) Copyright 2001-2003, by :
 *     Corporate: 
 *         Astrium SAS 
 *         EADS CRC
 *     Individual: 
 * 		   Christophe Pecquerie
 *         updated for SMI (especially for GHYPS) by Mathias Choquet
 *
 * $Id: TspDataSourceCollection.java,v 1.4 2006/06/04 08:33:45 erk Exp $
 * 
 * Changes ------- 06-Jan-2004 : Creation Date (NB);
 *  
 */
package tsp.consumer.plugin.jsynopticSMI;

import java.util.ArrayList;
import java.util.Collection;

import javax.swing.JOptionPane;

import jsynoptic.ui.JSynoptic;
import simtools.data.CollectiveDataSource;
import simtools.data.DataInfo;
import simtools.data.DataSource;
import simtools.data.DataSourceCollection;
import simtools.data.DynamicDataSourceCollection;
import simtools.data.EndNotificationListener;
import simtools.data.UnsupportedOperation;
import simtools.data.ValueProvider;
import simtools.data.buffer.Buffer;
import simtools.data.buffer.DelayedBuffer;
import tsp.consumer.plugin.jsynopticSMI.impl.TspHandler;
import tsp.consumer.plugin.jsynopticSMI.impl.TspHandler.TspProviderNotFoundException;
import tsp.core.common.TspException;
import tsp.core.common.TspAnswerSample;
import tsp.core.common.TspSample;
import tsp.core.common.TspSampleSet;
import tsp.core.config.TspConfig;
import tsp.core.rpc.TSP_sample_symbol_info_t;

public class TspDataSourceCollection
extends DynamicDataSourceCollection implements TspSampleSet
{
	/*Made the conversion in the pgi (tsp) and the index (jsynoptic)*/ 
	private int[] pgiToIndex;
	/*Indicate if the pgi is selected by the user*/ 
	boolean[] selected;
	/*tsp handler*/
	public TspHandler tspHandler_;
	/*jsynoptic collection */
	private DataInfo collectionInfo_;
	/*Root of the board of TSP data's of the tab source*/
	ArrayList Racine;
	/*the list send to the provider*/
	TSP_sample_symbol_info_t[] symbolTab;
	/*Indicate the current value of the timestamp for the*/ 
	/*sending of the data*/
	int timeStampTmp = -1;
	int IndexRunPtr = 1;
	
	/*source info jsynoptic*/
	SourceInfo[] dataInfoCache = new SourceInfo[5000];
	int dataInfoCacheLength=0;
	
	
	public TspDataSourceCollection(TspHandler tspHandler) {
		symbolTab = new TSP_sample_symbol_info_t[0]; 
		tspHandler_ = tspHandler;
		tspHandler.setDataSource(this);
		selected= new boolean[tspHandler_.getProviderNbSymbols()];;
		pgiToIndex= new int[tspHandler_.getProviderNbSymbols()];
		collectionInfo_ = new DataInfo(tspHandler_.getId());
		Racine = new ArrayList();
		
		/*construction of the hierachized list*/
		if (sMI_2_Containers()){
			generateSourceInfoAndBuffer();
		}else{
			/* not a Standard Model Interface*/
			JOptionPane.showMessageDialog(
					JSynoptic.gui, "data do not respect the Standart Model Interface",null, JOptionPane.ERROR_MESSAGE, null);
		}
	}
	
	/**
	 * surchage of the method to add the pgi and to make the 
	 * correpondance pgi-> dsnum 
	 */
	protected DataSource createDataSource(DataInfo info,int pgi) {
		int index = size();
		pgiToIndex[pgi] = index;
		DataSource ret = new CollectiveDataSource(this, index){
			boolean first=true;
			public void addEndNotificationListener(EndNotificationListener enl) {
				if(first){
					aliveDataSource(myIndex);
					first = false;
				}
				super.addEndNotificationListener(enl);
			}
		};
		add(ret);
		class TSPSourceInfo extends SourceInfo{};
		TSPSourceInfo s = new TSPSourceInfo();
		s.info = info;
		s.kind = ValueProvider.DoubleProvider;
		if(dataInfoCacheLength>=dataInfoCache.length){
			SourceInfo[] tmp=new SourceInfo[dataInfoCache.length*2];
			System.arraycopy(dataInfoCache, 0, tmp, 0, dataInfoCache.length);
			dataInfoCache=tmp;
		}
		dataInfoCache[dataInfoCacheLength]=s;
		dataInfoCacheLength++;
		return ret;
	}
	
	private void generateSourceInfoAndBuffer(){
		sourceInfo=new SourceInfo[size()];
		System.arraycopy(dataInfoCache, 0, sourceInfo, 0, size());
		dataInfoCache = null;
		buffers = new Buffer[size()];
		notifyListenersForDataSourceAdded((DataSource)lastElement());
	}
	
	/**
	 * method for simulation commanding
	 */
	//TODO improve the commanding of simulation by using TSP_WRITE
	public void run(){
		for(int i = 0 ; i< sourceInfo.length ; i++){
			if(tspHandler_.getSymbolTab()[tspHandler_.getSymbolTab().length-IndexRunPtr].name.equals(sourceInfo[i].info.id)){
				aliveDataSource(i);
			}
		}
		IndexRunPtr++;
	}
	
	/**
	 * this method is called when a TSP source is solicited by JSynoptic 
	 */
	private void aliveDataSource(int index){
		/*Calculation of the buffer and the reproduction by 100*/
		int bufferSize = (int) (tspHandler_.getBufferDuration_() * tspHandler_.getSamplingFrequency()*100);
		try {
			bufferize(index,new DelayedBuffer(ValueProvider.DoubleProvider,bufferSize));
		} catch (UnsupportedOperation e) {
			e.printStackTrace();
		}
		/* ask tsp for samples */ 
		TSP_sample_symbol_info_t[] symbolTabTemp = new TSP_sample_symbol_info_t[symbolTab.length+1];
		
		for(int i = 0; i<symbolTabTemp.length ;i++)
			symbolTabTemp[i] = new TSP_sample_symbol_info_t();
		int ind = 0;
		for (int i = 0 ;i <tspHandler_.getSymbolTab().length ;i++){
			if(tspHandler_.getSymbolTab()[i].name.equals(sourceInfo[index].info.id)){
				selected[i] = true;
			}
			if(selected[i]==true){
				symbolTabTemp[ind].name = tspHandler_.getSymbolTab()[i].name;
				symbolTabTemp[ind].dimension = tspHandler_.getSymbolTab()[i].dimension;
				symbolTabTemp[ind].period = tspHandler_.getSymbolTab()[i].period;
				symbolTabTemp[ind].phase = tspHandler_.getSymbolTab()[i].phase;
				symbolTabTemp[ind].provider_global_index = tspHandler_.getSymbolTab()[i].provider_global_index;
				symbolTabTemp[ind].provider_group_index = tspHandler_.getSymbolTab()[i].provider_group_index ;
				symbolTabTemp[ind].provider_group_rank = tspHandler_.getSymbolTab()[i].provider_group_rank;
				symbolTabTemp[ind].type = tspHandler_.getSymbolTab()[i].type;
				ind++;
			}
		}
		
		symbolTab = symbolTabTemp;
		
		/*sampling temporarily stopped*/	
		try {
			if(tspHandler_.isSampling()==true){
				tspHandler_.stopSampling();
			}
			/*waiting for an answer*/
			TspAnswerSample ans = tspHandler_.updateRequestSampleList(symbolTab);
			tspHandler_.startSampling();
		} catch (TspProviderNotFoundException e1) {
			e1.printStackTrace();
		}
	}
	
	
	
	/**
	 *	Creation of the hierachized list and initialization of Container (for Jsynoptic) 
	 */
	private boolean sMI_2_Containers() {
		String nameModelTemp = "";
		String nameDataTemp = "";
		String nameData=null;
		String nameModel=null;
		String nameSubData=null;
		
		int indicetab= 0;
		
		DataSourceCollection.Container ContModel=null;
		DataSourceCollection.Container ContData=null;
		DataSourceCollection.Container ContSubData=null;
		
		ArrayList ListData=null;
		ArrayList ListSubData=null;
		
		for(int i=0 ; i < tspHandler_.getSymbolTab().length ;i++){
			String nameComplet = tspHandler_.getSymbolTab()[i].name;
			
			//FIXME currently, the indices of the tables are managed by 
			//this method but it is not possible to reach the boxes of the table
			
			/*if it is a table*/
			if (nameComplet.charAt(nameComplet.length()-1)==']'){
				int taillenb = nameComplet.lastIndexOf('[');
				String nametab = nameComplet.substring(0,taillenb);
				String nametabComp = nametab;
				int j=i+1;
				for(;(nametab.compareTo(nametabComp)==0 &&(j<tspHandler_.getSymbolTab().length));){
					nametabComp = tspHandler_.getSymbolTab()[j].name;
					if (nametabComp.charAt(nametabComp.length()-1)==']'){
						taillenb = nametabComp.lastIndexOf('[');
						nametabComp = nametabComp.substring(0,taillenb);
					}
					j++;
				}
				if (j!=tspHandler_.getSymbolTab().length){
					i=j-2;}
				nameComplet = tspHandler_.getSymbolTab()[i].name;
			}
			/*construction of the "Mod�le" level*/
			int lenghNameModel = nameComplet.indexOf(".");
			
			if(lenghNameModel==-1){
				/* not a standart Model Interface*/
				return false;}
			
			nameModel = nameComplet.substring(0, lenghNameModel);
			nameComplet = nameComplet.substring(lenghNameModel+1,nameComplet.length());
			
			/*construction of the "Data" and "SubData" level*/
			int lenghNameData = nameComplet.indexOf(".");
			if (lenghNameData<=0){
				nameData = nameComplet; 
				nameSubData="";
			}
			else{
				nameData = nameComplet.substring(0, lenghNameData);	
				nameSubData = nameComplet.substring(lenghNameData+1,nameComplet.length());	
			}
			if (nameModel.equals(nameModelTemp)) {
				/*same mod�le -> data test*/
				if (nameData.equals(nameDataTemp)){
					/*same mod�le and same data -> subData test*/
					ContData.addDataSource(createDataSource(new DataInfo(nameSubData,tspHandler_.getSymbolTab()[i].name),tspHandler_.getSymbolTab()[i].provider_global_index));
				}
				else{
					/*same mod�le -> new data -> data and subdata construction*/
					if(nameSubData==""){
						/*data is a leaf*/
						ContModel.addDataSource(createDataSource(new DataInfo(nameData,tspHandler_.getSymbolTab()[i].name),tspHandler_.getSymbolTab()[i].provider_global_index));
						
					}else{
						/*data is a node, subdata is a leaf*/ 
						ContData = new DataSourceCollection.Container(nameData);
						ListData.add(ContData);
						nameDataTemp = nameData;
						ContData.addDataSource(createDataSource(new DataInfo(nameSubData,tspHandler_.getSymbolTab()[i].name),tspHandler_.getSymbolTab()[i].provider_global_index));
					}
				}}
			else {
				/*new model -> model, data and subdata construction*/
				ContModel = new DataSourceCollection.Container(nameModel);
				Racine.add(ContModel);
				if(nameSubData==""){
					/*data is a leaf*/
					ListData = new ArrayList();
					ContModel.setChildren(ListData);
					ContModel.addDataSource(createDataSource(new DataInfo(nameData,tspHandler_.getSymbolTab()[i].name),tspHandler_.getSymbolTab()[i].provider_global_index));
				}else{
					/*data is a node, subdata is a leaf*/
					ListData = new ArrayList();
					ContData = new DataSourceCollection.Container(nameData);
					ListData.add(ContData);
					ContModel.setChildren(ListData);
					ContData.addDataSource(createDataSource(new DataInfo(nameSubData,tspHandler_.getSymbolTab()[i].name),tspHandler_.getSymbolTab()[i].provider_global_index));
				}
				nameModelTemp = nameModel;
				nameDataTemp = nameData;
			}
		}/*end of for*/
		
		return true;
	}
	
	public DataInfo getInformation() {
		return collectionInfo_;
	}
	
	public Collection getCollectionContainers(){
		return Racine;
		
	}
	
	public boolean isCompound(){
		return true;
	}
	
	
	public void addSource(DataInfo di) {
		createDataSource(di,ValueProvider.DoubleProvider);
	}
	
	
	/* (non-Javadoc)
	 * send value to JSynoptic
	 * @see tsp.core.common.TspSampleSet#putSample()
	 */
	public void putSample(TspSample s) {
		try {
			if (s.isDouble())
				setDoubleValue(pgiToIndex[s.getPgi()],s.getDoubleValue());
			else if (s.isFloat())
				setFloatValue(pgiToIndex[s.getPgi()],s.getFloatValue());
			else if (s.isLong())
				setLongValue(pgiToIndex[s.getPgi()],s.getLongValue());
			else if (s.isInt())
				setIntegerValue(pgiToIndex[s.getPgi()],s.getIntValue());
			else if (s.isCharacter())
				setIntegerValue(pgiToIndex[s.getPgi()],s.getCharValue());
			else if (s.isRaw())
				setByteValue(pgiToIndex[s.getPgi()],s.getByteValue());
			else
				throw new TspException("Tsp sample type not yet implemented");
		}
		catch (TspException e){
			TspConfig.log(TspConfig.LOG_WARNING,"TspException: Unable to set value in putSample<"+e.getMessage()+">");
		}
		
		int ts = s.getTimeStamp();
		
		if (timeStampTmp != ts){
			timeStampTmp = ts;
			registerNewValues();
		}
	}


	
	/* (non-Javadoc)
	 * @see tsp.core.common.TspSampleSet#getSample()
	 */
	public TspSample getSample() {
		return null;
	}
	
    /* (non-Javadoc) 
	 * @see tsp.core.common.TspSampleSet#nbSample()
	 */
	public int nbSample() {
		return 0;
	}
}