/* $Id: TspAggrSessionImpl.java,v 1.4 2005/10/05 00:11:47 sgalles Exp $
 * -----------------------------------------------------------------------
 * 
 * TSP Library - core components for a generic Transport Sampling Protocol.
 * 
 * Copyright (c) 2002 Yves DUFRENNE, Stephane GALLES, Eric NOULARD and Robert PAGNOT 
 * 
 * This library 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 library 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 library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * 
 * -----------------------------------------------------------------------
 * 
 * Project    : TSP
 * SubProject : jTSP
 * Maintainer : tsp@astrium-space.com
 * Component  : Consumer
 * 
 * -----------------------------------------------------------------------
 * 
 * Purpose   : 
 * 
 * -----------------------------------------------------------------------
 */
package tsp.consumer.util.aggregator;


import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;

import tsp.core.consumer.TspConsumerException;
import tsp.core.consumer.simple.TspSimpleAnswerSample;
import tsp.core.consumer.simple.TspSimpleRequestSample;
import tsp.core.consumer.simple.TspSimpleSample;
import tsp.core.consumer.simple.TspSimpleSampleSymbolInfo;
import tsp.core.consumer.simple.TspSimpleSession;
import tsp.core.consumer.simple.TspSimpleSessionImpl;

/**
 * @author steph
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
class TspAggrSessionImpl implements TspSimpleSession {
	
	private final TspAggrSubSession[] sessions;
	private Map sessionsMap = new HashMap();	
			
	/**
	 * @param sessions
	 */
	TspAggrSessionImpl(TspAggrSubSession[] sessions) {
		super();
		this.sessions = sessions;
		for(int i = 0 ; i < sessions.length ; i++){
			sessionsMap.put(sessions[i].getNamespace(),sessions[i].getNamespace()); 
		}		
	}
	
	private TspSimpleSessionImpl getSession(String name) throws TspConsumerException{
		TspSimpleSessionImpl session = (TspSimpleSessionImpl)sessionsMap.get(name);
		if(session == null){
			throw new  TspConsumerException("No provider named '" + name + "'");
		}
		return session;
	}
	
	/**
	 * @throws TspConsumerException
	 */
	public void close() throws TspConsumerException {
		for(int i = 0 ; i < sessions.length ; i++){
			sessions[i].setEquivIndex(null);
			sessions[i].getSession().close();
		}
		
	}
	
	/**
	 * @return
	 * @throws NoSuchElementException
	 */
	public void fetchSample(TspSimpleSample sample) throws NoSuchElementException {
		for(int i = 0 ; i < sessions.length ; i++){
			TspAggrSubSession aggrse = sessions[i];
			TspSimpleSession se = aggrse.getSession();
			if(aggrse.getEquivIndex() != null && se.isDataAvailable()){				
				se.fetchSample(sample);
				
				// set the corrected external index
				Integer externalIndex = (Integer)aggrse.getEquivIndex().get(new Integer(sample.getIndex()));
				if(externalIndex == null) throw new IllegalStateException("Unable to find provider global index " 
										+ sample.getIndex() + 
										" for session " + aggrse.getNamespace());
				sample.setIndex(externalIndex.intValue()); 				
				return;
			}
		}		
		throw new NoSuchElementException();
	}
	
	/**
	 * @return
	 */
	public boolean isDataAvailable() {
		boolean isDataAvailable = false;
		for(int i = 0 ; i < sessions.length && !isDataAvailable; i++){
			if(sessions[i].getEquivIndex() != null){
				isDataAvailable |= sessions[i].getSession().isDataAvailable();
			}
		}
		return isDataAvailable;
	}
	/**
	 * @return
	 * @throws TspConsumerException
	 */
	public TspSimpleAnswerSample requestInfos() throws TspConsumerException {		
		List aggrInfos = new LinkedList();
		for(int i = 0 ; i < sessions.length ; i++){
			TspSimpleSession simpleSession = sessions[i].getSession(); 
			TspSimpleAnswerSample answer = simpleSession.requestInfos();
			for(int j = 0 ; j < answer.getSymbolInfos().length ; j++){				
				TspSimpleSampleSymbolInfo infoWithNamespace = 
					NamespaceHelper.addNamespace(sessions[i].getNamespace(), 
							answer.getSymbolInfos()[j]); 
				aggrInfos.add(infoWithNamespace);
			}			
		}
		TspSimpleSampleSymbolInfo[] aggrInfosArray = (TspSimpleSampleSymbolInfo[])aggrInfos.toArray(new TspSimpleSampleSymbolInfo[0]);
		return new TspSimpleAnswerSample(aggrInfosArray);
	}
	/**
	 * @param req
	 * @return
	 * @throws TspConsumerException
	 */
	public TspSimpleAnswerSample requestSample(TspSimpleRequestSample req)throws TspConsumerException {		
		NamespaceSorter sorter = new NamespaceSorter(req.getSampleInfos());
		// Prepare the array that will receive the returned symbols infos
		TspSimpleSampleSymbolInfo[] resultInfos = new TspSimpleSampleSymbolInfo[req.getSampleInfos().length];;
		for(int i = 0 ; i < sessions.length ; i++){
			// for each used session...
			TspAggrSubSession session = sessions[i];
			TspSimpleSampleSymbolInfo[] requestInfo = sorter.getSampleInfoByNamespace(session.getNamespace());			
			if(requestInfo != null){
				// ...do a request sample only for this namespace info list				
				TspSimpleRequestSample rs = new TspSimpleRequestSample(requestInfo);
				TspSimpleAnswerSample sas = session.getSession().requestSample(rs);				
				
				/*--------------------*/
				/*System.out.println("Symboles demandés");
				for(int k = 0 ; k < rs.getSampleInfos().length ; k++){
					TspSimpleSampleSymbolInfo info = rs.getSampleInfos()[k];
					System.out.println("name=" + info.getName() + " period=" + info.getPeriod());
				}
				System.out.println("\nSymboles retournés");
				for(int k = 0 ; k < sas.getSymbolInfos().length ; k++){
					TspSimpleSampleSymbolInfo info = sas.getSymbolInfos()[k];
					System.out.println("index=" + info.getIndex() + " name=" + info.getName() + " period=" + info.getPeriod());
				}*/
				/*--------------------*/
				
				// FIXME : put == when the bug in TSP C will be fixed
				if(requestInfo.length > sas.getSymbolInfos().length) throw new IllegalStateException("Asked symbols not equals to returned symbols");
								
				
				// compute translation index array
				Map equivIndex = new HashMap();				
				for(int j = 0 ; j < requestInfo.length ; j++){
					// retreive index of returned symbol info in initial list;
					TspSimpleSampleSymbolInfo infoWithNamespace = NamespaceHelper.addNamespace(session.getNamespace(), sas.getSymbolInfos()[j] );
					int externalIndex = sorter.getIndexInInitialArray(infoWithNamespace.getName());
					// Replace the local index with the external, and memorise the equivalence					
					equivIndex.put(new Integer(infoWithNamespace.getIndex()), new Integer(externalIndex));
					infoWithNamespace.setIndex(externalIndex);
					
					// prepare the final result
					resultInfos[externalIndex] = infoWithNamespace;														
				}
				// store the whole computed equivalence
				session.setEquivIndex(equivIndex);
			}
			
		}
		return new TspSimpleAnswerSample(resultInfos);
	}
	
	
	/**
	 * @throws TspConsumerException
	 */
	public void requestSampleFinalize() throws TspConsumerException {
		//	call function only if request sample was called
		for(int i = 0 ; i < sessions.length ; i++){
			if(sessions[i].getEquivIndex() != null){
				sessions[i].setEquivIndex(null);				
				sessions[i].getSession().requestSampleFinalize();
			}
		}
	}
	
	/**
	 * @throws TspConsumerException
	 */
	public void requestSampleInit() throws TspConsumerException {
		// call function only if request sample was called
		for(int i = 0 ; i < sessions.length ; i++){
			if(sessions[i].getEquivIndex() != null){
				sessions[i].getSession().requestSampleInit();
			}
		}
	}
	
	
	/**
	 * 
	 */
	public void waitForData() {						
		while (!isDataAvailable()) {
			try {
				Thread.sleep(100);
			}
			catch (InterruptedException e) {				
			}									
		}
		
	}
	
}
