package cz.vutbr.feec.project;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.Vector;

import cz.vutbr.feec.stockElements.AbstractStockCell;
import cz.vutbr.feec.stockElements.CoridorCell;
import cz.vutbr.feec.stockElements.Stock;

public class Edit {

	private LinkedList<AbstractStockCell[][]> undo = new LinkedList<AbstractStockCell[][]>();
	private LinkedList<AbstractStockCell[][]> redo = new LinkedList<AbstractStockCell[][]>();
	private Stock s = Stock.getInstance();

	// jedinacek
	private static final Edit EDIT = new Edit();

	private Edit() {
	}

	public static Edit getInstance() {
		return EDIT;
	}

	public void addStep() {
		int length = GlobalParameters.lengthField;
		int width = GlobalParameters.widthField;
		// musim vytvorit novy object pola
		AbstractStockCell[][] field = new AbstractStockCell[length][width];
		// pole musim kopirovat prvok po prvku - nefunguje to objektovo
		for (int i = 0; i < length; i++) {
			for (int j = 0; j < width; j++) {
				field[i][j] = s.getFieldIndex(i, j);
			}

		}
		undo.add(field);
	}

	public void getUndoStep() {
		int length = GlobalParameters.lengthField;
		int width = GlobalParameters.widthField;
		AbstractStockCell[][] tmp = undo.removeLast(); // vymazem z fronty
														// posledny stav

		// nemozem pridat do redo stav priamo z unda, pretoze to nie je aktualny
		// sklad, ale krok predtym
		AbstractStockCell[][] toRedo = new AbstractStockCell[length][width];

		// redo.add(tmp);
		
		//vektor na porovnavanie ramp
		Vector<AbstractStockCell> tmpRamps = new Vector<AbstractStockCell>();
		
		// vrat posledny stav skladu
		// musim vytvorit novy object pola
		// pole musim kopirovat prvok po prvku - nefunguje to objektovo
		for (int i = 0; i < length; i++) {
			for (int j = 0; j < width; j++) {
				AbstractStockCell cell = s.getFieldIndex(i, j);
				// najskor prekreslim aktualny sklad do reda
				toRedo[i][j] = cell;
				// potom prekreslim sklad na sklad z unda
				s.setFieldIndex(tmp[i][j], i, j);
				//toto su bunky ktore sa vracaju, pridam vsetky rampy do tmp vektora
				if(cell.getClass() == CoridorCell.class){
					CoridorCell c = (CoridorCell) cell;
					if(c.isImage()){
						tmpRamps.add(c);
					}
				}
							
			}
		}
		
		//pridat/odstranit rampy 		
		compareRamps(tmpRamps);
		redo.add(toRedo);
	}

	public void getRedoStep() {
		int length = GlobalParameters.lengthField;
		int width = GlobalParameters.widthField;
		AbstractStockCell[][] tmp = redo.removeLast();
		// do unda musim pridat zase stav ako to vypada
		addStep();
		// undo.add(tmp);
		
		
		//vektor na porovnavanie ramp
		Vector<AbstractStockCell> tmpRamps = new Vector<AbstractStockCell>();
				
		for (int i = 0; i < length; i++) {
			for (int j = 0; j < width; j++) {
				s.setFieldIndex(tmp[i][j], i, j);
				//toto su bunky ktore sa vracaju, pridam vsetky rampy do tmp vektora
				AbstractStockCell cell = s.getFieldIndex(i, j);
				if(cell.getClass() == CoridorCell.class){
					CoridorCell c = (CoridorCell) cell;
					if(c.isImage()){
						tmpRamps.add(c);
					}
				}
			}

		}
		
		//pridat/odstranit rampy 		
		compareRamps(tmpRamps);
	}
	private void compareRamps(Vector<AbstractStockCell> tmpRamps){
		Vector<AbstractStockCell> actualRamps = s.getRamps();
		if(actualRamps.size()==tmpRamps.size())return;
		if(actualRamps.size()>tmpRamps.size()){
			//vymazaz z actual
			HashSet<AbstractStockCell> tmpRampSet = new HashSet<AbstractStockCell>();
			tmpRampSet.addAll(tmpRamps);
			for (int j = 0; j < actualRamps.size(); j++) {
				if(!tmpRampSet.contains(s.getRamps().get(j))){
					System.out.println("mazem rampu "+s.getRamps().get(j).getX()+","+s.getRamps().get(j).getY());
					s.getRamps().remove(j);
				}
			}
		}
		else{
			//pridat do actual
			for (int j = 0; j < tmpRamps.size(); j++) {
				if(!s.containsRamp(tmpRamps.get(j))){
					System.out.println("pridavam "+tmpRamps.get(j).getX()+","+tmpRamps.get(j).getY());
					actualRamps.add(tmpRamps.get(j));
					return;
				}
			}
		}
	}

	

	public boolean undoIsEmpty() {
		if (undo.isEmpty())
			return true;
		return false;
	}

	public boolean redoIsEmpty() {
		if (redo.isEmpty())
			return true;
		return false;
	}

	public LinkedList<AbstractStockCell[][]> getUndo() {
		return undo;
	}

	public LinkedList<AbstractStockCell[][]> getRedo() {
		return redo;
	}
	public void removeAll(){
		undo.removeAll(undo);
		redo.removeAll(redo);
	}
}
