package compbio.data.sequence;


import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlTransient;

import compbio.data.sequence.ScoreManager.ScoreHolder;
import compbio.util.SysPrefs;

@XmlAccessorType(XmlAccessType.FIELD)
public class RNAStructScoreManager extends ScoreManager {

	
	private RNAStructScoreManager() {
		//Default JAXB constructor
	}
	

	public RNAStructScoreManager(List<String> structs, List<TreeSet<Score>> data) {
		
		assert(structs.size() == data.size());
		
		List<ScoreHolder> seqScores = new ArrayList<ScoreHolder>();
		
		for (int i = 0; i < structs.size(); i++) {
			seqScores.add(new ScoreHolder(structs.get(i), data.get(i)));
		}
		this.seqScores = seqScores;
	}
	
	public static RNAStructScoreManager newInstance(List<String> structs, List<TreeSet<Score>> data) {
		return new RNAStructScoreManager(structs, data);
	}
	
	public List<String> getStructs() {
		List<String> structs = new ArrayList<String>();
		for (ScoreHolder sch : this.seqScores) {
			structs.add(sch.id);
		}
		return structs;
	}
	
	public List<TreeSet<Score>> getData() {
		List<TreeSet<Score>> data = new ArrayList<TreeSet<Score>>();
		for (ScoreHolder sch : this.seqScores) {
			data.add(sch.scores);
		}
		return data;
		
	}
	
	/*
	 *  I want to be able to get the information in a ScoreHolder Object by
	 *  
	 */

	// Send this data Structure back to something approximating the stdoutFile
	// with extra information from alifold.out
	@Override
	public String toString() {
		String out = "";
		// The first objects hold the Consensus Alignment and the alifold.out info
		out += this.getStructs().get(0) + SysPrefs.newlinechar;

		// Now the rest of the structures with energies/frequencies
		for (int i = 1; i < this.getStructs().size(); i++) {
			out = out + this.getStructs().get(i).toString();

			if (this.getData().get(i).first().getScores().size() > 0) {
				List<Float> scores = this.getData().get(i).first().getScores();
				if (scores.size() >= 3) {
					out = out + " (" + scores.get(0).toString() + " = " 
							+ scores.get(1).toString() + " + " + scores.get(2).toString()
							+ ")" + SysPrefs.newlinechar;
				}
				else if (this.getData().get(i).first().getMethod().equals("alifoldMEA")) {
					out = out + " { " + scores.get(0).toString() + " MEA=" 
							+ scores.get(1).toString() + "}" + SysPrefs.newlinechar;
				}
				else if (scores.size() >= 2) {
					out = out + " [" + scores.get(0).toString() + ", " 
							+ scores.get(1).toString() + "]" + SysPrefs.newlinechar;

				}
			} else out += SysPrefs.newlinechar; 
		}
		if (this.getData().get(0).first().getScores().size() > 0) {
			Iterator<Score> iScores = this.getData().get(0).iterator();
			out += "Base Pairings followed by probability" + SysPrefs.newlinechar;
			for (int i = 0; i < this.getData().get(0).size(); i++) {
				Score s = iScores.next();
				Range r = s.getRanges().first();
				Float score = s.getScores().get(0);
				out += String.format("%4d  %4d    %.1f%n", r.from, r.to,
						score);
			}
		}


		return out;
	}

	@Override 
	public boolean equals(Object obj) {
		if (obj == null) {
			return false;
		}
		if (!(obj instanceof RNAStructScoreManager)) {
			return false;
		}
		RNAStructScoreManager other = (RNAStructScoreManager) obj;
		if (this.getStructs() == null) {
			if (other.getStructs() != null) {
				return false;
			}
		} else if (!this.getStructs().equals(other.getStructs()))
			return false;
		if (this.getData() == null) {
			if (other.getData() != null)
				return false;
		} else if (!this.getData().equals(other.getData()))
			return false;

		return true;
	}
}
