/*  
 *  src/org/metaqtl/main/MMapView.java
 * 
 *  $Author: veyrieras $, $Date: 2006-10-17 15:41:54 $, $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.main;

import java.io.File;
import java.io.IOException;

import org.metaqtl.CMarkerSequence;
import org.metaqtl.ChromCluster;
import org.metaqtl.Chromosome;
import org.metaqtl.IMetaQtlConstants;
import org.metaqtl.MapCluster;
import org.metaqtl.QtlPartition;
import org.metaqtl.algo.CMSAlgorithm;
import org.metaqtl.bio.IBioGenome;
import org.metaqtl.bio.IBioOntology;
import org.metaqtl.graph.ChromGraph;

/**
 * 
 */
public class MMapView extends MetaMain {
	
	private static final String VERSION = IMetaQtlConstants.VERSION; 
	
	private static final String syntax  =  "Syntaxe: MMapView "+
											"[{-m, --mapdir}] "+
											"[{-r, --refmap] "+
											"[{-c, --chr}] "+
											"[{-q, --withqtl}] "+
											"[{--qmode}]"+
											"[{--htest}] "+
											"[{--hth}] "+
											"[{-t, --tonto}] "+
											"[{-p, --par}]" +
											"[{--img}]" +
											"[{-o, --outstem}]] "+										
											MetaMain.generalUsage();
	
	public void printUsage() {
        System.err.println(syntax);
    }
	
	public void printHelp() {
		MetaMain.printLicense("MMapDraw", VERSION);
		System.out.println();
		System.out.println(syntax);
        System.out.println();
        MetaMain.generalHelp();
        System.out.println();
        System.out.println("-m, --mapdir    : the directory of the XML files for the input maps");
        System.out.println("-r, --refmap    : the XML file for the reference map");
        System.out.println("-c, --chr       : the chromosome(s) to draw");
        System.out.println("-q, --withqtl   : draw also the QTL");
        System.out.println("--qmode         : QTL representation mode");
        System.out.println("    --htest     : test distance homogeneity between maps (only with -r)");
        System.out.println("    --hth       : threshold p-value of the homogeneity test");
		System.out.println("-t, --tonto     : the XML file for the trait ontology");
		System.out.println("    --mrkt      : threshold on the occurence of the markers");
        System.out.println("-p, --par       : the file location of the plot parameters");
        System.out.println("-o, --outstem   : the output stem");
        System.out.println("--img           : the format name of the image among this list");
        MetaMain.printImgFormat(16); 
	}
	
	public static void main(String[] args) {
		
		MMapView program = new MMapView();
		
		program.initCmdLineParser();
		
		CmdLineParser parser = program.parser;
		
        CmdLineParser.Option amapDir   = parser.addStringOption('m', "mapdir");
        CmdLineParser.Option arefFile  = parser.addStringOption('r', "refmap");
        CmdLineParser.Option achrName  = parser.addStringOption('c', "chr");
        CmdLineParser.Option awithQtl  = parser.addBooleanOption('q', "withqtl");
        CmdLineParser.Option amodeQtl	= parser.addIntegerOption("qmode");
        CmdLineParser.Option ahDist    = parser.addBooleanOption("htest");
        CmdLineParser.Option ahThresh    = parser.addDoubleOption("hth");
        CmdLineParser.Option aontoFile	= parser.addStringOption('t', "tonto");
        CmdLineParser.Option amrkThresh	= parser.addIntegerOption("mrkt");
        CmdLineParser.Option aparFile  = parser.addStringOption('p', "par");
        CmdLineParser.Option aimgFormat= parser.addStringOption("img");
        CmdLineParser.Option aoutStem  = parser.addStringOption('o', "outstem");
        
        program.parseCmdLine(args);
        
        // Mandatory
        String mapDir 	 	 =  (String)parser.getOptionValue(amapDir);
        String refFile	     =  (String)parser.getOptionValue(arefFile);
        String chrList 	     =  (String)parser.getOptionValue(achrName);
        Boolean withQtl      = (Boolean) parser.getOptionValue(awithQtl, new Boolean(false));
        Integer modeQtl 	 =  (Integer)parser.getOptionValue(amodeQtl, new Integer(QtlPartition.VERTICAL_MODE));
        Boolean hDist        = (Boolean) parser.getOptionValue(ahDist, new Boolean(false));
        Double  hThresh        = (Double) parser.getOptionValue(ahThresh, new Double(0));
        String ontoFile  	 =  (String)parser.getOptionValue(aontoFile);
        Integer mrkThresh    = (Integer)parser.getOptionValue(amrkThresh, new Integer(1));
        String parFile  	 =  (String)parser.getOptionValue(aparFile);
        String imgFormat	 =  (String)parser.getOptionValue(aimgFormat, "jpeg");
        String outStem     	 =  (String)parser.getOptionValue(aoutStem);
        
        if (mapDir == null) {
        	System.err.println("[ ERROR ] No map directory defined");
        	System.exit(2);
		}
        if (outStem == null) {
        	System.err.println("[ ERROR ] No output stem defined");
        	System.exit(2);
        }
        
        IBioGenome[] maps     = null;
        IBioGenome   refmap   = null;
		IBioOntology ontology = null;
		String[] chromNames   = null;
        
		try {
			refmap     = getMap(refFile);
			maps       = getMaps(mapDir);
			ontology   = getOntology(ontoFile, 'x');
			chromNames = parseChromList(chrList);
			setParameter(parFile);
		} catch (IOException e) {
			System.err.println(e.getMessage());
			System.exit(3);
		}
        
		if (maps == null) {
			System.err.println("[ ERROR ] Unable to load maps from " + mapDir);
        	System.exit(3);
		}
		
		MapCluster mapCluster=new MapCluster();
		for(int i=0;i<maps.length;i++) mapCluster.addMap(maps[i], false);
		if (refmap != null) mapCluster.addMap(refmap, true);
		ChromCluster[] clusters  = mapCluster.getClusters();
		ChromCluster[] clust2draw = getClusterByNames(clusters, chromNames);
		if (clust2draw==null) clust2draw = clusters;
		
		for(int i=0;i<clust2draw.length;i++) {
			clust2draw[i].setMrkThresh(mrkThresh.intValue());
    		clust2draw[i].fixCluster();
    		Chromosome[] chromosomes = clust2draw[i].getClusterMembers();
    		if (refmap != null && hDist.booleanValue())
    			testDistanceHomogeneity(chromosomes, hThresh.doubleValue());
    		ChromGraph[] chromGraphs = getChromGraph(chromosomes, withQtl.booleanValue(), modeQtl.intValue(), ontology, null);
        	try {
				// Draw
        		File outFile = getOutFile(outStem, clust2draw[i].getName(), imgFormat);
        		writeImg(chromGraphs, outFile, imgFormat);
        		outFile = getParFile(outStem, clust2draw[i].getName());
        		writePar(outFile);
			} catch (IOException e) {
				e.printStackTrace();
			}    	
        }

		System.exit(0);
	}
	
	private static void testDistanceHomogeneity(Chromosome[] chromosomes, double thresh) {
		boolean doThresh = (thresh > 0 && thresh < 1); 
		Chromosome   skeleton    = getSkeleton(chromosomes);
		Chromosome[] others      = getOthers(chromosomes, skeleton);
		// Set the common marker sequences
		for(int j=0;j<others.length;j++) {
		 	CMarkerSequence cms = CMSAlgorithm.run(others[j], skeleton);
		 	double[] hetero     = Chromosome.getDistHeterogeneity(cms.nmc, cms.mcidx, others[j], skeleton);
			double[][] proba    = new double[cms.nmc-1][3];
			for(int k=0;k<cms.nmc-1;k++) {
				proba[k][0]=others[j].getDistance(cms.mcidx[0][k]);
				proba[k][1]=others[j].getDistance(cms.mcidx[0][k+1]);
				if (doThresh && hetero[k] >= thresh) proba[k][2]=1;
				if (doThresh && hetero[k] < thresh)  proba[k][2]=0;
				else proba[k][2]=hetero[k];
			}
			others[j].setProba(proba);
	    }
	}
	
	private static Chromosome getSkeleton(Chromosome[] chroms) {
		if (chroms==null) return null;
		for(int i=0;i<chroms.length;i++)
			if (chroms[i].skeleton) return chroms[i];
		return null;
	}
	
	private static Chromosome[] getOthers(Chromosome[] chroms, Chromosome skeleton) {
		if (chroms==null || chroms.length<=1) return null;
		Chromosome[] others = new Chromosome[chroms.length-1];
		for(int j=0,i=0;i<chroms.length;i++)
			if (!chroms[i].equals(skeleton))
				others[j++]=chroms[i];
		return others;
	}
	
	/**
	* @param name
	* @param string
	* @param imgFormat
	* @return
	*/
	private static File getOutFile(String outStem, String name, String imgFormat) {
		return new File(outStem+"_"+name+"."+imgFormat);
	}
	
	private static File getParFile(String outStem, String name) {
		return new File(outStem+"_"+name+".par");
	}
}
