/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package motifkmer;

/**
 *
 * @author Rahul Semwal
 */

/*{'A': 0.0826, 'B': 1.0000, 'C': 0.0136, 'D': 0.0546, 'E': 0.0675, 'F': 0.0386, 'G': 0.0708,  # @UnusedVariable
                  'H': 0.0227, 'I': 0.0597, 'J': 1.0000, 'K': 0.0585, 'L': 0.0966, 'M': 0.0242, 'N': 0.0406, 
                  '0': 1.0000, 'P': 0.0469, 'Q': 0.0393, 'R': 0.0553, 'S': 0.0655, 'T': 0.0534, 'U': 1.0000, 
                  'V': 0.0687, 'W': 0.0108, 'X': 1.0000, 'Y': 0.0292, 'Z': 1.0}*/
import org.apache.commons.math3.stat.inference.GTest;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class SACMotif 
{
    private static final HashMap<Character,Double> backGround;//initilize it
    static
    {
        backGround = new HashMap<>();
        backGround.put('A',0.0825 );backGround.put('R',0.0553 );backGround.put('N',0.0406 );backGround.put('D',0.0545 );backGround.put('C',0.0137 );backGround.put('Q',0.0393 );
        backGround.put('E',0.0675);backGround.put('G',0.0707 );backGround.put('H',0.0227);backGround.put('I',0.0596 );backGround.put('L',0.0966 );backGround.put('K',0.0584);
        backGround.put('M',0.0242 );backGround.put('F',0.0386 );backGround.put('P',0.0470 );backGround.put('S',0.0656 );backGround.put('T',0.0534);backGround.put('W',0.0108 );
        backGround.put('Y',0.0292 );backGround.put('V',0.0687 );

    }
    @SuppressWarnings("element-type-mismatch")
    public static String SeedMotif(DLinkList<String> Sequences,DLinkList<LinkNode<Integer>>.DLinkNode<LinkNode<Integer>> indexPtr,int kmerLength,int leftgap,int rightgap,int totalSeq,double frequency[])
    {
        String seed="";
        int i=0;
        DLinkList<LinkNode<Integer>>.DLinkNode<LinkNode<Integer>> head;
        DLinkList<String>.DLinkNode<String> Seqhead;
        HashMap<Character,Integer> seedChar=new HashMap<>();
        char ch;
        int count=0;
        boolean checker=true;
        double score=0.0D;
        double strength=0.0D;
        GTest gtest = new GTest();
       
        while(i<kmerLength && (leftgap<4 && rightgap<4))
        {
            head=indexPtr;
            Seqhead=Sequences.getHead();
            while(head != null)
            {
                ch = Seqhead.getValue().charAt(head.data.getValue()+i);
                if(seedChar.containsKey(ch)) 
                    seedChar.put(ch, seedChar.get(ch)+1);
                else
                    seedChar.put(ch, 1);
                head=head.next;
                Seqhead=Seqhead.next;
            }
            
            if(seedChar.size()>1)
            {
                int index = 0;
                @SuppressWarnings("MismatchedReadAndWriteOfArray")
                String charset="";
                @SuppressWarnings("MismatchedReadAndWriteOfArray")
                long observed[] = new long[seedChar.size()];
                @SuppressWarnings("MismatchedReadAndWriteOfArray")
                double expected[] = new double[seedChar.size()];
                Iterator it = seedChar.entrySet().iterator();
                while(it.hasNext())
                {
                    Map.Entry pair = (Map.Entry)it.next();
                    charset += String.valueOf(pair.getKey());
                    observed[index]=(int)pair.getValue();
                    strength+=((int)pair.getValue()*1.0)/totalSeq;

                    expected[index++]=(double)(backGround.get(pair.getKey())*totalSeq); 
                    it.remove();
                }
                seedChar.clear();
                score+=Math.sqrt(((gtest.gTest(expected, observed)*1.0))/totalSeq); 
                boolean regChar = gtest.gTest(expected, observed, <"provide confidence interval value">);
                expected=null;
                observed=null;
                if(!regChar)
                {
                    if((i+1)==kmerLength)
                        seed +="x";
                    else
                        seed+="x-";
                    count++;
                    if(checker)
                        leftgap++;
                    else 
                        rightgap++;
                  
                }
                else
                {
                    if((i+1)==kmerLength)
                        seed +="["+charset+"]";
                    else
                        seed +="["+charset+"]-";
                    checker=false;
                    rightgap=0;
                }
            }
            else
            {
                Iterator it = seedChar.entrySet().iterator();
                Map.Entry pair = (Map.Entry)it.next();
                if((i+1)==kmerLength)
                    seed += String.valueOf(pair.getKey());
                else
                    seed += String.valueOf(pair.getKey())+"-";
                seedChar.clear();
                checker=false;
                rightgap=0;
                strength++;
                score++;
            }
            i++;
        }
        if(count!=kmerLength)
            return (leftgap+","+seed+","+rightgap+","+score+","+strength);
        else
        {
            
            return(leftgap+","+seed+","+rightgap+","+score+","+strength);
        }
    }
    
    
    @SuppressWarnings({"null", "element-type-mismatch"})
    public static String motifElongation(DLinkList<String>.DLinkNode<String> Seqhead,DLinkList<LinkNode<Integer>>.DLinkNode<LinkNode<Integer>> head,int leftint,int rightint,boolean leftflag,boolean rightflag,int leftgap,int rightgap,int totalSeq,double frequency[])
    {
        HashMap<Character,Integer> leftChar=new HashMap<>();
        HashMap<Character,Integer> rightChar=new HashMap<>();
        String leftchar="";
        String rightchar="";
        char ch;
        GTest gtest = new GTest();
        double leftscore=0;
        double rightscore=0;
        double leftstrength=0.0D;
        double rightstrength=0.0D;
      
        while((head!=null) &&(leftflag||rightflag))
        {
            if(((head.data.getValue()+leftint)<0) && leftflag)
                leftflag=false;
            if(leftflag)
            {
                ch=Seqhead.getValue().charAt(head.data.getValue()+leftint);
                if(leftChar.containsKey(ch)) 
                    leftChar.put(ch, leftChar.get(ch)+1);
                else
                    leftChar.put(ch, 1);
            }
            else
            {
                if(leftChar !=null)
                    leftChar.clear();
                leftChar=null;
                leftchar="";
                
            }
            
            if(((head.data.getValue()+rightint)>=(Seqhead.getValue().length())) && rightflag)
                rightflag=false;
            if(rightflag)
            {
                ch=Seqhead.getValue().charAt(head.data.getValue()+rightint);
                if(rightChar.containsKey(ch)) 
                    rightChar.put(ch, rightChar.get(ch)+1);
                else
                    rightChar.put(ch, 1);
            }
            else
            {
                if(rightChar!=null)
                    rightChar.clear();
                rightChar=null;
                rightchar="";
                
            }
            head=head.next;
            Seqhead=Seqhead.next; 
        }
        
        if(leftChar!=null)
        {
            if(leftChar.size()>1)
            {
                @SuppressWarnings("MismatchedReadAndWriteOfArray")
                String charset="";
                @SuppressWarnings("MismatchedReadAndWriteOfArray")
                long observed[] = new long[leftChar.size()];
                @SuppressWarnings("MismatchedReadAndWriteOfArray")
                double expected[] = new double[leftChar.size()];
                Iterator it = leftChar.entrySet().iterator();
                int index=0;
                while(it.hasNext())
                {
                    Map.Entry pair = (Map.Entry)it.next();
                    charset += String.valueOf(pair.getKey());
                    observed[index]=(int)pair.getValue();
                    leftstrength+=((int)pair.getValue()*1.0)/totalSeq;
                    
                    expected[index++]=(double)(backGround.get(pair.getKey())*totalSeq);
                    it.remove();
                }
                leftChar.clear();
                leftscore+=Math.sqrt(((gtest.gTest(expected, observed)*1.0))/totalSeq);
                boolean regChar = gtest.gTest(expected, observed, <"provide confidence interval value">);
                expected=null;
                observed=null;
                if(!regChar)
                {
                    leftchar="x";
                    leftgap++;
                }
                else
                {
                    leftchar="["+charset+"]";
                    leftgap=0;
                    
                }
                
            }
            else
            {
                Iterator it = leftChar.entrySet().iterator();
                Map.Entry pair = (Map.Entry)it.next();
                leftchar= String.valueOf(pair.getKey());
                leftChar.clear();
                leftscore++;                    leftgap=0;
                leftstrength++;
            }
        }
        if(rightChar!=null)
        {
            if(rightChar.size()>1)
            {
                @SuppressWarnings("MismatchedReadAndWriteOfArray")
                String charset="";
                @SuppressWarnings("MismatchedReadAndWriteOfArray")
                long observed[] = new long[rightChar.size()];
                @SuppressWarnings("MismatchedReadAndWriteOfArray")
                double expected[] = new double[rightChar.size()];
                Iterator it = rightChar.entrySet().iterator();
                int index=0;
                while(it.hasNext())
                {
                    Map.Entry pair = (Map.Entry)it.next();
                    charset += String.valueOf(pair.getKey());
                    observed[index]=(int)pair.getValue();
                    rightstrength+=((int)pair.getValue()*1.0)/totalSeq;
                 
                    expected[index++]=(double)(backGround.get(pair.getKey())*totalSeq);
                    it.remove();
                }
                rightChar.clear();
                rightscore+=Math.sqrt(((gtest.gTest(expected, observed)*1.0))/totalSeq);
                boolean regChar = gtest.gTest(expected, observed, <"provide confidence interval value">);
                expected=null;
                observed=null;
                if(!regChar)
                {
                    rightchar="x";
                    rightgap++;
                }
                else
                {
                    rightchar="["+charset+"]";
                    rightgap=0;
                }
            }
            else
            {
                Iterator it = rightChar.entrySet().iterator();
                Map.Entry pair = (Map.Entry)it.next();
                rightchar= String.valueOf(pair.getKey());
                rightChar.clear();
                rightstrength++;                                rightgap=0;
                rightscore++;
            }
        }
        return(leftchar+","+rightchar+","+leftflag+","+rightflag+","+leftgap+","+rightgap+","+leftscore+","+rightscore+","+leftstrength+","+rightstrength);
    }
}
