package geneFinder;

import java.util.Vector;

/**
 * parse cigar, MD and sequence to extract all indels and mismatches
 * @author zickmannf
 *
 */

public class CigarParser {

	public static void main(String[] args){  // main is only for debugging
		String cigar = "3M2I1M1D4M";
		String mdTag = "4^A2C1";
		String rnaSeq = "AAATTATTGT";
		
		Object[] returnArr = extractAllAlignDiffs(cigar, mdTag, rnaSeq);
	}
	
	/*
	 * extract all alignment differences
	 * note: positions are reference-based, insert bases and mismatch bases are read-based (necessary for transcript reconstruction)
	 * note: no clipped alignments are supported
	 */
	
	public static Object[] extractAllAlignDiffs(String cigar, String mdTag, String readSeq){
		
		Vector<int[]> inserts = new Vector<int[]>();
		Vector<int[]> dels = new Vector<int[]>();
		Vector<int[]> mms = new Vector<int[]>();
		
		int[] refToReadPos = new int[readSeq.length()*2];
		for(int pos = 0;pos<refToReadPos.length;++pos){
			refToReadPos[pos] = pos;
		}
		
		/////// first: insertions ///////
		
		if(cigar.contains("I")){
			
			int globalPos = 0;		// in case of more than one intron
			String[] cigarArr_I = cigar.split("I");
			
			for(int pos = 0; pos<(cigarArr_I.length-1);++pos){
				String i_part = cigarArr_I[pos];
				String[] iPart_all = i_part.split("[DIMXN]");
				
				int insertSize = Integer.parseInt(iPart_all[iPart_all.length - 1]);
				
				int pos_local = 0;
				String[] iPart_all2 = i_part.split("[DIMX]");
				
				for(int pos2 = 0;pos2 < iPart_all2.length-1;++pos2){
					String partSmall = iPart_all2[pos2];
					if(!partSmall.contains("N")){
						pos_local = pos_local + Integer.parseInt(partSmall);
					}else{
						String[] partSmall_n = partSmall.split("N");		// do not count N positions
						pos_local = pos_local + Integer.parseInt(partSmall_n[partSmall_n.length - 1]);
					}
				}
				
				globalPos = globalPos + pos_local;
				
				int[] insertTemp = new int[2+insertSize];	// 0=position on ref at that insert is started; 1=insertSize,2etc=base codes for inserted bases
				insertTemp[0] = globalPos;
				insertTemp[1] = insertSize;
				
				for(int posMap = globalPos;posMap < refToReadPos.length;++posMap){
					refToReadPos[posMap] = refToReadPos[posMap] + insertSize;
				}
				
				inserts.add(insertTemp);
			}
		}
		
		/////// second: deletions ///////
		
		if(cigar.contains("D")){
			
			int globalPos = 0;
			String[] cigarArr_D = cigar.split("D");
			for(int pos = 0; pos<(cigarArr_D.length-1);++pos){
				String d_part = cigarArr_D[pos];
				String[] dPart_all = d_part.split("[DIMXN]");
				
				int delSize = Integer.parseInt(dPart_all[dPart_all.length - 1]);
				
				int pos_local = 0;
				String[] dPart_all2 = d_part.split("[DMX]");
				
				for(int pos2 = 0;pos2 < dPart_all2.length-1;++pos2){
					String partSmall = dPart_all2[pos2];
					if(!partSmall.contains("N") && !partSmall.contains("I")){
						pos_local = pos_local + Integer.parseInt(partSmall);
					}else{
						String[] partSmall_split = partSmall.split("[NI]");		// do not count N or I positions
						pos_local = pos_local + Integer.parseInt(partSmall_split[partSmall_split.length - 1]);
					}
				}
				
				globalPos = globalPos + pos_local;
				
				int[] delTemp = new int[2];	// 0=position on ref at that deletion is started; 1=deletionSize
				delTemp[0] = globalPos;
				delTemp[1] = delSize;
				
				/*for(int posMap = globalPos;posMap < Math.min(refToReadPos.length,globalPos + delSize);++posMap){
					refToReadPos[posMap] = -1;
				}*/
				
				for(int posMap = globalPos + delSize;posMap < refToReadPos.length;++posMap){
					refToReadPos[posMap] = refToReadPos[posMap] - delSize;
				}
				
				dels.add(delTemp);
				globalPos = globalPos + delSize;
			}
		}
		
		/////// third: complete inserts ///////
		
		for(int[] insertTemp : inserts){
			for(int pos = 0;pos<insertTemp[1];++pos){
				String base = readSeq.substring((refToReadPos[insertTemp[0]+pos]-insertTemp[1]),(refToReadPos[insertTemp[0]+pos]-insertTemp[1]) + 1);
				insertTemp[2+pos] = SamParser.returnBaseCode(base);
			}
		}
		
		/////// fourth: extract mismatches ///////
		
		String[] mdParts = mdTag.split("");
	
		int posOnRef = 0;
		
		boolean inDeletion = false;
		StringBuffer numString = new StringBuffer("");
		
		for(int posArr = 1; posArr<mdParts.length;++posArr){
			String mdChar = mdParts[posArr];
			if(mdChar.contains("^")){
				inDeletion = true;
				if(numString.length() != 0){
					posOnRef = posOnRef + Integer.parseInt(numString.toString());  // +1 for current position
				}
				numString = new StringBuffer("");
			}else if(mdChar.contains("A") || mdChar.contains("C") || mdChar.contains("G") || mdChar.contains("T") || mdChar.contains("N")){
				if(!inDeletion){
					// mismatch
					//posOnRef++;		
					if(numString.length() != 0){
						posOnRef = posOnRef + Integer.parseInt(numString.toString()) + 1;  // +1 for current position
					}else{
						posOnRef++;
					}
					numString = new StringBuffer("");
					String base = readSeq.substring(refToReadPos[posOnRef-1],refToReadPos[posOnRef-1]+1);
					int[] tempMM = new int[2];
					tempMM[0] = posOnRef-1;
					tempMM[1] = SamParser.returnBaseCode(base);
					mms.add(tempMM);
				}else{
					posOnRef++;
				}
			}else{
				inDeletion = false;
				numString.append(mdChar);
				//posOnRef = posOnRef + Integer.parseInt(mdChar);
			}
		}
		
		return new Object[] {inserts,dels,mms};
		
	}

}
