
package org.fda.intervaltree;

import java.util.ArrayList;
import java.util.List;
import org.fda.exceptions.IllegalIntervalException;


/**
 *
 * @author Gokhan.Yavas
 */
public class MergedIntervalSearchTree extends IntervalSearchTree {
    private static final long serialVersionUID = 112414357102382689L;
    
    private long totalSize=0L;
    
    public long getTotalSize(){
        return totalSize;
    }
    
    public synchronized boolean put(Interval interval, boolean generateSubs) {
        List<Interval> ist = new ArrayList<Interval>();
        interval.incrementCount();
        if (!contains(interval, ist)) { 
            List<Interval> intersectingIntervals = searchAll(interval);
            mergeIntervals(intersectingIntervals, interval, generateSubs);
            return true;
        }
        else{
            ist.get(0).incrementCount();
            return false;
        }
    }
    private void mergeIntervals(List<Interval> intersectingIntervals, Interval newInterval, boolean generateSubs){
        if(!intersectingIntervals.isEmpty()){
            int smallestStCoord = newInterval.getlow(), largestEndCoord = newInterval.gethigh();
            for(Interval it : intersectingIntervals){
                if(it.getlow() < smallestStCoord)
                    smallestStCoord = it.getlow();
                if(it.gethigh() > largestEndCoord)
                    largestEndCoord = it.gethigh();
                this.remove(it);
                totalSize-=it.getlength();
            }
            try{
                Interval id2Insert;
                boolean safeToadd=true;
                if(!generateSubs)
                    id2Insert = new Interval(smallestStCoord, largestEndCoord, (intersectingIntervals.size() > 0));
                else{
                    id2Insert = new Interval(smallestStCoord, largestEndCoord, (intersectingIntervals.size() > 0));
                
                    // We need to keep track of the subintervals for this project, for depth of coverage compute and genes, exons
                    //intersectingIntervals.add(new Interval(newInterval));
                    
                    for(Interval it : intersectingIntervals){
                        if(it.getMerged()){
                            for(Interval it2: ((Interval)it).getsubIntervals()){
                                if(it2.compareTo(newInterval)==0){
                                    it2.incrementCount();
                                    safeToadd = false;
                                }
                                id2Insert.add2SubIntervals(it2);
                            }
                        }
                        else{
                            id2Insert.add2SubIntervals((Interval)it);
                        }
                    }
                    if(safeToadd)
                        id2Insert.add2SubIntervals(newInterval);
                }
                totalSize +=id2Insert.getlength();
                //super.put(id2Insert);
                putWOCheck4DuplicateEntry(id2Insert, generateSubs);       
            }
            catch(IllegalIntervalException e){e.printStackTrace(); System.out.println("Illegal subintervals"); System.exit(1);}
        }
        else{
            totalSize += newInterval.getlength();
            //super.put(newInterval);
            putWOCheck4DuplicateEntry(newInterval, generateSubs);            
        }
    }
    protected void putWOCheck4DuplicateEntry(Interval interval, boolean generateSubs) {

        root=randomizedInsert(root, interval);
    }       
    public static void main(String[] args){
        MergedIntervalSearchTree mst = new MergedIntervalSearchTree();
        try{
//            for(int i=0; i< 10; i++){
                mst.put(new Interval(1,10,false), true);
                mst.put(new Interval(2,11,false), true);
                mst.put(new Interval(1,10,false), true);
                mst.put(new Interval(11,12,false), true);
                mst.put(new Interval(1,12,false), true);
                mst.put(new Interval(1,12,false), true);
                mst.put(new Interval(15,18,false), true);
                mst.put(new Interval(15,16,false), true);
                mst.put(new Interval(15,16,false), true);
                //mst.put(new Interval(2,10,false), true);
//            }
        }
        catch(Exception e){e.printStackTrace();}
        List<Interval> i = mst.inOrder();
        for(Interval v : i){
            System.out.println(v.toStringWSubIntervals());
        }
        System.out.println(mst.getTotalSize());
    }
}
