import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class KDECluster {
	private long _startPosition;
	private long _endPosition;
	private String _sequence;
	private double _modeScore = 0;
	private long _modePosition;
	private ArrayList<AlignedPARCLIPread> _readList = new ArrayList<AlignedPARCLIPread>(10);
	private HashMap<Long, Integer> _conversionMap = new HashMap<Long, Integer>(30, (float) 0.99);
	private TreeMap<MIRNAseedMatch, String> _matchList = new TreeMap<MIRNAseedMatch, String>();
	private HashMap<Long, Integer> _countMap = new HashMap<Long, Integer>(30, (float) 0.99);
	private static final Transliteration _oppositeStrandTransliterate = Transliteration.compile("ACGT", "TGCA");

	
	public void setStartPosition( long startPosition ) {
		_startPosition = startPosition;
	}
	public void setEndPosition( long endPosition ) {
		_endPosition = endPosition;
	}
	public void setMode( long modePosition, double modeScore ) {
		_modePosition = modePosition;
		_modeScore = modeScore;
	}
	public void setSequence( String sequence ) {
		_sequence = sequence;
	}
	public long getModePosition() {
		return _modePosition;
	}
	public long getStartPosition() {
		return _startPosition;
	}
	public long getEndPosition() {
		return _endPosition;
	}
	public double getModeScore() {
		return _modeScore;
	}
	public String getSequence() {
		return _sequence;
	}
	public int getReadCount() {
		int sum = 0;
		Iterator<AlignedPARCLIPread> readIt = _readList.iterator();
		while( readIt.hasNext() ) {
			AlignedPARCLIPread currentRead = readIt.next();
			sum += currentRead.getReadCount();
		}
		return sum;
	}
	public int getConversionCount() {
		int sum = 0;
		Iterator<Long> longIt = _conversionMap.keySet().iterator();
		while( longIt.hasNext() ) {
			sum += _conversionMap.get(longIt.next());
		}
		return sum;
	}
	public int getNumberOfConversionlocations() {
		return _conversionMap.keySet().size();
	}
	public void addRead( AlignedPARCLIPread read ) {
		incorporateConversionMap(read.getStartPosition(), read.getEndPosition(), read.getConversionMap());
// Added for Neel
		Long location = Math.max(read.getStartPosition(), _startPosition);
		Long maxLocation = Math.min(read.getEndPosition(), _endPosition);
		while( location <= maxLocation ) {
			if( _countMap.containsKey(location) ) {
				_countMap.put(location, _countMap.get(location) + read.getReadCount() );
			} else {
				_countMap.put(location, read.getReadCount());
			}
			location++;
		}
//**************		
		_readList.add(read);
	}
	
	public int getNumberOfNonConversions(char strand) {
		int sum = 0;
		String sequence = _sequence;
		if( strand == '-' ) {
			sequence = new StringBuffer(sequence).reverse().toString();
		}
		long location = _startPosition;
 		while( location <= _endPosition ) {
			if(sequence.substring((int) (location - _startPosition), (int) (location - _startPosition + 1)).equals("T") ) {
					if( _conversionMap.containsKey(location) ) {
						sum += _countMap.get(location) - _conversionMap.get(location);
					} else { sum += _countMap.get(location); }
			}
			location++;
		}
		return sum;
	}
	
	
	
//***********************************************************************	
// Incorporate conversion information from reads..		
	private void incorporateConversionMap( long readStartPosition, long readEndPosition, HashMap<Byte, Integer> readConversionMap ) {
		Iterator<Byte> locIt = readConversionMap.keySet().iterator();
		while( locIt.hasNext() ) {
			Byte readLocation = locIt.next();
			long location = readStartPosition + (long) readLocation;
			if( location >= _startPosition && location <= _endPosition ) {
				if( _conversionMap.containsKey(location) ) {
					_conversionMap.put(location, _conversionMap.get(location) + readConversionMap.get(readLocation));
				}
				else {
					_conversionMap.put(location,readConversionMap.get(readLocation));
				}
			}
		}
	}
//***********************************************************************	


	
//***********************************************************************	
// Identify any potential miRNA binding sites
	public void findmiRNAsites(HashMap<String, MIRNA> miRNAlist, int maximumSeedMatchLength) {
		Iterator<String> listIt = miRNAlist.keySet().iterator();
		while( listIt.hasNext() ) {
			HashMap<Integer, String> seedMatchHash = new HashMap<Integer, String>();
			MIRNA currentMiR = miRNAlist.get(listIt.next());
			int maxMatch = Math.min(maximumSeedMatchLength, currentMiR.getSequence().length());
			for( int j = maxMatch; j >= 7; j-- ) {
				String nMer = currentMiR.getSequence().substring(1,j+1);				
				String nMer1A = "T"+currentMiR.getSequence().substring(1,j);
				nMer =  _oppositeStrandTransliterate.translate(nMer);
				nMer = new StringBuffer(nMer).reverse().toString();
				nMer1A =  _oppositeStrandTransliterate.translate(nMer1A);
				nMer1A = new StringBuffer(nMer1A).reverse().toString();
				Pattern nMerPattern = Pattern.compile(nMer);
				Pattern nMerPattern1A = Pattern.compile(nMer1A);
				Matcher matchSeed = nMerPattern.matcher(_sequence);
				Matcher matchSeed1A = nMerPattern1A.matcher(_sequence);
				
				boolean found = false;
				boolean foundSeed = matchSeed1A.find();
				while( foundSeed ) {
					foundSeed = false;
					int location = matchSeed1A.start();
					for(int k = 0; k < _readList.size(); k++ ) {
						if( _readList.get(k).getStartPosition() - _startPosition <= location 
								&& _readList.get(k).getEndPosition() - _startPosition >= location + j
						) {
							seedMatchHash.put(location + j, Integer.toString(j - 1)+"mer1A");
							found = true;
							foundSeed = matchSeed1A.find();
							break;
						}
					}
				}
				foundSeed = matchSeed.find();
				while( foundSeed ) {
					foundSeed = false;
					Integer location = matchSeed.start();
					for(int k = 0; k < _readList.size(); k++ ) {
						if( _readList.get(k).getStartPosition() - _startPosition <= location 
								&& _readList.get(k).getEndPosition() - _startPosition >= location + j
						) {
							seedMatchHash.put(location + j, Integer.toString(j)+"mer");
							found = true;
							foundSeed = matchSeed.find();
							break;
						}
					}
				}
				if( found ) { break; }
			}
			Iterator<Integer> seedIt = seedMatchHash.keySet().iterator();
			while( seedIt.hasNext() ) {
				int location = seedIt.next();
				MIRNAseedMatch currentMatch = new MIRNAseedMatch(location, seedMatchHash.get(location));
				if( _matchList.containsKey(currentMatch) ) {						
					_matchList.put(currentMatch, _matchList.get(currentMatch) + ";" + currentMiR.getName());
				}
				else {
					_matchList.put(currentMatch, currentMiR.getName());
				}
			}
		}
	}	
	public boolean foundSites() {
		if( _matchList.size() > 0 ) { return true; }
		else { return false; }
	}
	public TreeMap<MIRNAseedMatch, String> getMiRsiteTree() {
		return _matchList;
	}
//***********************************************************************	
	
}
