/*  
 *  src/org/metaqtl/factory/MetaQtlModelFactory.java
 * 
 *  $Author: veyrieras $, $Date: 2006-10-17 15:41:55 $, $Version$
 *
 *  MetaQTL : a Java package for QTL Meta-Analysis
 * 
 *  Copyright (C) 2003-2006  Jean-Baptiste Veyrieras, INRA, France.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU 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 * 
 */
package org.metaqtl.factory;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.StringTokenizer;

import org.metaqtl.MetaQtlModel;

/**
 * 
 */
public class MetaQtlModelFactory {
	
	public static final String SEPARATOR = "\t";
	
	/**
	 * This method reads a file formated as follows :
	 * 
	 * Chromosome \t Trait \t Model
	 *  
	 * 
	 */
	public static MetaQtlModel read(Reader reader) throws IOException {
		if (reader == null) return null;
		
		int i,j,cnt,cidx,tidx,midx,model;
		BufferedReader buffer=null;
		StringTokenizer token=null;
		String line=null,sbuff=null,chromName,traitName;
		Hashtable chromHash=null,traitHash=null;
		MetaQtlModel metaModel = null;
		
		buffer = new BufferedReader(reader);
		
		/* First read the header */
		line = buffer.readLine();
		if (line == null) return null;
		token = new StringTokenizer(line, "\t");
		/* Check if the header is valid, i.e if the 
		 * first token is the map name
		 */
		cidx=tidx=midx=-1;
		if (token.countTokens() >= 1) {
			i=0;
			while(token.hasMoreTokens()) {
				sbuff = token.nextToken();
				if (sbuff.equalsIgnoreCase("Chromosome"))
					cidx = i;
				if (sbuff.equalsIgnoreCase("Trait"))
					tidx = i;
				if (sbuff.equalsIgnoreCase("Model"))
					midx = i;
				i++;
			}
			if (cidx==-1 || tidx==-1 || midx == -1)
				throw new IOException("Bad header format");
		} else 
			throw new IOException("Bad header format");
		/* Now read the rows */
		cnt=1;
		while ((line = buffer.readLine()) != null) {
			token = new StringTokenizer(line);
			/* Test if the number of token equals to expected
			 * number.
			 */
			if (token.countTokens()>=1) {
				i=0;
				chromName=traitName=null;
				model=0;
				while(token.hasMoreTokens()) {
					if (i==cidx) {
						chromName = token.nextToken();
					} else if (i==tidx) {
						traitName = token.nextToken();
					} else if (i==midx) {
						model     = Integer.parseInt(token.nextToken());
					}
					i++;
				}
				if (chromName==null || traitName==null || model==0) {
					throw new IOException("Bad line format at " + cnt);
				} else {
					if (chromHash ==null)
						chromHash = new Hashtable();
					if (!chromHash.containsKey(chromName)) {
						traitHash = new Hashtable();
						chromHash.put(chromName, traitHash);
					} else {
						traitHash = (Hashtable) chromHash.get(chromName);
					}
					traitHash.put(traitName, new Integer(model));
				}
			} else {
				throw new IOException("Bad line format at " + cnt);
			}
			cnt++;
		}
		
		buffer.close();
		reader.close();
		
		if (chromHash != null) {
			
			metaModel = new MetaQtlModel();
			metaModel.chromNames = new String[chromHash.size()];
			metaModel.traitNames = new String[chromHash.size()][];
			metaModel.models     = new int[chromHash.size()][];
			
			Enumeration e = chromHash.keys();
			
			i=0;
			
			while(e.hasMoreElements()) {
				chromName = (String) e.nextElement();
				traitHash = (Hashtable) chromHash.get(chromName);
				
				metaModel.chromNames[i]=chromName;
				metaModel.traitNames[i]=new String[traitHash.size()];
				metaModel.models[i]=new int[traitHash.size()];
				
				Enumeration e1 = traitHash.keys();
				
				j=0;
				
				while(e1.hasMoreElements()) {
					
					traitName = (String) e1.nextElement();
					model     = ((Integer)traitHash.get(traitName)).intValue();
					
					metaModel.traitNames[i][j]	= traitName;
					metaModel.models[i][j] 		= model;
					
					j++;
					
				}
				
				i++;
				
			}
			
		}
		
		return metaModel;
	}
	
	public static void write(MetaQtlModel model, OutputStream stream) {
		if (model == null) return;
		if (stream == null) return;
		
		PrintWriter writer = new PrintWriter(stream);
		
		write(model,writer);		
	}
	/**
	 * @param model
	 * @param writer
	 */
	public static void write(MetaQtlModel model, Writer writer) {
		if (model == null) return;
		if (writer == null) return;
		
		PrintWriter pw = new PrintWriter(writer);
		
		String criterion = model.getCriterion();
		
		String[] chrom   = model.getChromNames();
		
		if (criterion != null)  {
			pw.print("Criterion");
			pw.print(SEPARATOR);
		}
		pw.print("Chromosome");pw.print(SEPARATOR);
		pw.print("Trait");pw.print(SEPARATOR);
		pw.print("Model");pw.println();
		
		for(int i=0;i<chrom.length;i++) {
			
			String[] traits = model.getTraitNames(i);
			
			for(int j=0;j<traits.length;j++) {
				
				int k = model.getModel(i,j);
				
				if (criterion != null)  {
					pw.print(criterion);
					pw.print(SEPARATOR);
				}
				
				pw.print(chrom[i]);pw.print(SEPARATOR);
				pw.print(traits[j]);pw.print(SEPARATOR);
				pw.print(k);pw.println();
				pw.flush();
				
			}
			
		}
		
	}

}
