/*  
 *  src/org/thalia/bio/entity/factory/MapChartFactory.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.bio.entity.factory;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.StringTokenizer;

import org.metaqtl.bio.IBioEntity;
import org.metaqtl.bio.IBioLocus;
import org.metaqtl.bio.entity.GeneticMap;
import org.metaqtl.bio.entity.LGroup;
import org.metaqtl.bio.entity.Locus;
import org.metaqtl.bio.util.BioUtilities;
import org.metaqtl.bio.util.NumberFormat;
import org.metaqtl.bio.util.StaticLocusPosition;

/**
 * General comments must be added here.
 * 
 * @author Julien Cornouiller
 * 
 * Additions must be added here.
 *  
 */
public class MapChartFactory extends BioEntityFactory {

	/**
	 * TODO (non-Javadoc)
	 * 
	 * @see org.thalia.core.runtime.ITiedPluginFactory#load(java.io.Reader)
	 */
	public IBioEntity load(Reader reader) throws IOException {
		GeneticMap map = new GeneticMap();
		String line, nameLocus, nameGroup;
		BufferedReader red = new BufferedReader(reader);
		LGroup groupTemp = null;
		IBioLocus locusTemp = null;
		boolean groupflag = false;
		boolean qtlflag = false;
		double position, from, to;
		StringTokenizer st;
		try {
			while ((line = red.readLine()) != null) {
				if (line.startsWith("qtls")) {
					groupflag = false;
					qtlflag   = true;
				}				
				else if (groupflag && !line.equals("")) {
					st = new StringTokenizer(line);
					nameLocus = st.nextToken();
					position = Double.parseDouble(st.nextToken());

					locusTemp = Locus.newLocus(IBioLocus.MARKER);
					locusTemp.setGroup(groupTemp);
					locusTemp.setName(nameLocus);
					locusTemp.setPosition(new StaticLocusPosition(position));
					groupTemp.addLocus(locusTemp);
				}
				else if (line.startsWith("group")) {
					nameGroup = line.substring(line.lastIndexOf(" ") + 1);
					groupTemp = new LGroup(nameGroup, map);
					map.addGroup(groupTemp);
					groupflag = true;
					qtlflag   = false;
				}					
				else if (
							qtlflag
							&& !line.equals("")
							&& !line.startsWith("qtls")) {
					st = new StringTokenizer(line);
					nameLocus = st.nextToken();
					from = Double.parseDouble(st.nextToken());
					position = Double.parseDouble(st.nextToken());
					st.nextToken();
					to = Double.parseDouble(st.nextToken());

					locusTemp = Locus.newLocus(IBioLocus.QTL);
					locusTemp.setGroup(groupTemp);
					locusTemp.setName(nameLocus);
					locusTemp.setPosition(new StaticLocusPosition(position));
					locusTemp.getProperties().put("qtl.from", "" + from);
					locusTemp.getProperties().put("qtl.to", "" + to);
					groupTemp.addLocus(locusTemp);
				}						
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
		return map;
	}

	/**
	 * TODO (non-Javadoc)
	 * 
	 * @see org.thalia.core.runtime.ITiedPluginFactory#load(java.io.InputStream)
	 */
	public IBioEntity load(InputStream stream) throws IOException {
		InputStreamReader r = new InputStreamReader(stream);
		return load(r);
	}

	/**
	 * TODO (non-Javadoc)
	 * 
	 * @see org.thalia.core.runtime.ITiedPluginFactory#unload(java.lang.Object,
	 *      java.io.Writer)
	 */
	public void unload(IBioEntity obj, Writer w) throws IOException {
		GeneticMap map = (GeneticMap) obj;
		PrintWriter writer = new PrintWriter(w);
		double from, to, pos;
		int nqtl;

		for (int i = 0; i < map.groups().length; i++) {
			
			writer.println("group " + map.groups()[i].getName());
			/* sort loci */
			IBioLocus[] loci = BioUtilities.sortLociByPosition(map.groups()[i].loci());
			/*
			 * Print the markers but not the qtls
			 */
			nqtl = 0;
			for (int j = 0; j < loci.length; j++) {
				if (loci[j].getLocusType() == IBioLocus.MARKER)
					writer.println(loci[j].getName() + " "
							+ NumberFormat.formatDouble(loci[j].getPosition().absolute()));
				else if (loci[j].getLocusType() == IBioLocus.QTL)
					nqtl++;
			}
			
			if (nqtl > 0) {
				/*
				 * Print the qtls
				 */
				writer.println("qtls");
				
				for (int j = 0; j < loci.length; j++) {
					
					if (loci[j].getLocusType() == IBioLocus.QTL) {
						
						pos = loci[j].getPosition().absolute();
					
						try {
							
							from = Double.parseDouble(loci[j].getProperties()
									.getProperty("qtl.ic.from"));
							to = Double.parseDouble(loci[j].getProperties()
									.getProperty("qtl.ic.to"));
							
							writer.println(loci[j].getName() + " " + from + " "
									+ pos + " "
									+ pos + " "
									+ to);
						} catch (Exception e) {
							writer.println(loci[j].getName() + " "
									+ pos + " "
									+ pos + " "
									+ pos + " "
									+ pos);
						}
					}
				}
			}
			
			writer.println();
		}
		try {
			w.flush();
			w.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/**
	 * TODO (non-Javadoc)
	 * 
	 * @see org.thalia.core.runtime.ITiedPluginFactory#unload(java.lang.Object,
	 *      java.io.OutputStream)
	 */
	public void unload(IBioEntity obj, OutputStream stream) throws IOException {
		unload(obj, new OutputStreamWriter(stream));
	}	
}