package org.openpixi.pixi.physics.collision.detectors;

import org.openpixi.pixi.physics.*;
import org.openpixi.pixi.physics.collision.util.*;
import org.openpixi.pixi.physics.particles.Particle;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;

public class SweepAndPrune extends Detector{
	
	private ArrayList<Pair<Particle, Particle>> overlappedPairs = new ArrayList<Pair<Particle, Particle>>();

	private ArrayList<BoundingBox> boxlist = new ArrayList<BoundingBox>();
	
	private ArrayList<SweepParticle> axisX = new ArrayList<SweepParticle>();
	private ArrayList<SweepParticle> axisY = new ArrayList<SweepParticle>();
	
	private ArrayList<Pair<BoundingBox, BoundingBox>> overlaps = new ArrayList<Pair<BoundingBox, BoundingBox>>();
	
	//private ArrayList<Pair<Particle2D, Particle2D>> overlappedPairs = new ArrayList<Pair<Particle2D, Particle2D>>();
	
	private Map<Pair<BoundingBox, BoundingBox>, OverlapCounter> overlapCounter = 
			new HashMap<Pair<BoundingBox, BoundingBox>, OverlapCounter>();
	
	//constructor
	public SweepAndPrune(ArrayList<Particle> parlist) {
		
		boxlist.clear();
		axisX.clear();
		axisY.clear();
		overlaps.clear();
		overlappedPairs.clear();
		overlapCounter.clear();
		
		for(int i = 0; i < parlist.size(); i++) {
			Particle par = (Particle) parlist.get(i);
			BoundingBox box = new BoundingBox(par);
		
			if(!boxlist.contains(box)) {
				boxlist.add(box);
				
				axisX.add(new SweepParticle(box, 0, true));
				axisX.add(new SweepParticle(box, 0, false));
				axisY.add(new SweepParticle(box, 1, true));
				axisY.add(new SweepParticle(box, 1, false));
				//System.out.println("Particles added");
			}
		}
	}
	
	
	//adding a method for sorting the lists
	private void sortList(ArrayList<SweepParticle> list) {
		
		for(int i = 1; i < list.size(); i++) {
			
			SweepParticle sweepPar = list.get(i);
			double sweepParValue = sweepPar.updateGetValue();
			
			int j = i - 1;
			
			while(j >= 0 && (list.get(j).updateGetValue() > sweepParValue)) {
				
				SweepParticle swapPar = list.get(j);
				
				//creating a pair of the possibly overlapping particles
				Pair<BoundingBox, BoundingBox> pairbox = new Pair<BoundingBox, BoundingBox>(sweepPar.bb, swapPar.bb);
				
				if(sweepPar.begin && !swapPar.begin) {
					
					//setting them into a list
					if(overlapCounter.containsKey(pairbox)) {
						overlapCounter.get(pairbox).overlaps++;
					}
					else {
						OverlapCounter newOverlapCounter = new OverlapCounter();
						newOverlapCounter.overlaps = 1;
						overlapCounter.put(pairbox, newOverlapCounter);
					}
				}
				if(!sweepPar.begin && swapPar.begin) {
					if(overlapCounter.containsKey(pairbox)) {
						overlapCounter.get(pairbox).overlaps--;
					}
				}
				
				list.set(j + 1, swapPar);
				j = j - 1;
			}
			
			list.set(j + 1, sweepPar);
			//System.out.println("Particles swapped");
		}
	}
	
	public void run() {
		
		//sorting the axes lists
		sortList(axisX);
		sortList(axisY);
		//System.out.println("Axes sorted");
		
		//one needs to look at the counters (similar like with the remove method)
		Iterator<Entry<Pair<BoundingBox, BoundingBox>, OverlapCounter>> iterator = overlapCounter.entrySet().iterator();
		
		while(iterator.hasNext()) {
			Entry<Pair<BoundingBox, BoundingBox>, OverlapCounter> entry = iterator.next();
			OverlapCounter counter = entry.getValue();
			Pair<BoundingBox, BoundingBox> pairbox = entry.getKey();
			
			//System.out.println(counter.overlaps);
			if(counter.overlappedBoolean) {
				if(counter.overlaps < 2) {
					overlaps.remove(pairbox);
					counter.overlappedBoolean = false;

				}
				else if (counter.overlaps > 1) {
				}
			}
			else {
				if(counter.overlaps > 1) {
					overlaps.add(pairbox);
					counter.overlappedBoolean = true;
				}
			}
			if(counter.overlaps < 1) {
				iterator.remove();
			}
		}
	}
	
	public ArrayList<Pair<Particle, Particle>> getOverlappedPairs() {
		
		overlappedPairs.clear();
		
		for(int i = 0; i < overlaps.size(); i++) {
			BoundingBox box1 = (BoundingBox) overlaps.get(i).getFirst();
			BoundingBox box2 = (BoundingBox) overlaps.get(i).getSecond();
			Pair<Particle, Particle> pairpar = new Pair<Particle, Particle>(box1.particle, box2.particle);
			overlappedPairs.add(pairpar);
		}
		return overlappedPairs;
		
	}

}
