/*
 VARNA is a tool for the automated drawing, visualization and annotation of the secondary structure of RNA, designed as a companion software for web servers and databases.
 Copyright (C) 2008  Kevin Darty, Alain Denise and Yann Ponty.
 electronic mail : Yann.Ponty@lri.fr
 paper mail : LRI, bat 490 Universit� Paris-Sud 91405 Orsay Cedex France

 This file is part of VARNA version 3.1.
 VARNA version 3.1 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 3 of the License, or (at your option) any later version.

 VARNA version 3.1 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 VARNA version 3.1.
 If not, see http://www.gnu.org/licenses.
 */
package fr.orsay.lri.varna.models.rna;

import java.io.Serializable;
import java.util.Enumeration;
import java.util.Hashtable;

import fr.orsay.lri.varna.exceptions.MappingException;

public class Mapping implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = -3031358968555310380L;

	public static final int UNKNOWN = -1;

	Hashtable<Integer, Integer> _mapping = new Hashtable<Integer, Integer>();
	Hashtable<Integer, Integer> _invMapping = new Hashtable<Integer, Integer>();

	public Mapping() {

	}

	public void addCouple(int i, int j) throws MappingException {
		if (_mapping.containsKey(i) || _invMapping.containsKey(j)) {
			throw new MappingException(
					MappingException.MULTIPLE_PARTNERS_DEFINITION_ATTEMPT);
		}

		_mapping.put(new Integer(i), new Integer(j));
		_invMapping.put(new Integer(j), new Integer(i));
	}

	public int getPartner(int i) {
		if (!_mapping.containsKey(i))
			return UNKNOWN;
		else
			return _mapping.get(i);
	}

	public int getAncestor(int j) {
		if (!_invMapping.containsKey(j))
			return UNKNOWN;
		else
			return _invMapping.get(j);
	}

	public int[] getSourceElems() {
		int[] elems = new int[_mapping.size()];
		Enumeration<Integer> en = _mapping.keys();
		int i = 0;
		while (en.hasMoreElements()) {
			int a = en.nextElement();
			elems[i] = a;
			i++;
		}
		return elems;
	}

	public int[] getTargetElems() {
		int[] elems = new int[_invMapping.size()];
		Enumeration<Integer> en = _invMapping.keys();
		int i = 0;
		while (en.hasMoreElements()) {
			int a = en.nextElement();
			elems[i] = a;
			i++;
		}
		return elems;
	}

	public static Mapping readMappingFromAlignment(String m, String n)
			throws MappingException {
		Mapping map = new Mapping();
		if (m.length() != n.length()) {
			throw new MappingException(MappingException.BAD_ALIGNMENT_INPUT);
		}
		int i = 0;
		int j = 0;
		for (int k = 0; k < m.length(); k++) {
			char a = m.charAt(k);
			char b = n.charAt(k);
			if ((a != '-') && (a != ':') && (b != '-') && (b != ':')) {
				map.addCouple(i, j);
			}

			if ((a != '-') && (a != ':')) {
				j++;
			}
			if ((b != '-') && (b != ':')) {
				i++;
			}
		}
		return map;
	}

	public static Mapping DefaultMapping(int n, int m) {
		Mapping map = new Mapping();
		try {
			for (int i = 0; i < Math.min(n, m); i++) {
				map.addCouple(i, i);
			}
		} catch (MappingException e) {
			e.printStackTrace();
		}
		return map;
	}

	public static Mapping DefaultOutermostMapping(int n, int m) {
		Mapping map = new Mapping();
		try {
			int k = Math.min(n, m);
			int i = 0;
			int j = 0;
			boolean pile = true;
			while (i <= (k - 1) - j) {
				if (pile) {
					map.addCouple(i, i);
					i++;
				} else {
					map.addCouple(n - 1 - j, m - 1 - j);
					j++;
				}
				pile = !pile;
			}
		} catch (MappingException e) {
			e.printStackTrace();
		}
		// System.println(map);
		return map;
	}

	public String toString() {
		Enumeration<Integer> en = _mapping.keys();
		String tmp = "";
		int l1 = 0;
		int l2 = 0;
		int maxIndex = 0;
		while (en.hasMoreElements()) {
			Integer i = en.nextElement();
			Integer j = _mapping.get(i);
			l1 = Math.max(l1,i);
			l2 = Math.max(l2,j);
			tmp += "("+i+","+j+")";
		}
		maxIndex = Math.max(maxIndex,Math.max(l1,l2));
		String tmp1 = ""; 
		String tmp2 = ""; 
		en = _mapping.keys();
		
		int i = l1;
		int j = l2;
		while (en.hasMoreElements()) {
			Integer a = en.nextElement();
			Integer b = _mapping.get(a);
			while(a<i)
			{
				tmp1 = 'x'+tmp1;
				tmp2 = '-'+tmp2;
				i--;
			}
			while(b<j)
			{
				tmp1 = '-'+tmp1;
				tmp2 = 'x'+tmp2;
				j--;
			}
			tmp1 = '|'+tmp1;
			tmp2 = '|'+tmp2;
			i--;j--;
		}
		return tmp+"\n"+tmp1+"\n"+tmp2;
	}
}
