package lt.ktu.gmj.tasks;

import java.awt.Color;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import lt.ktu.gmj.*;
import lt.ktu.gmj.propertySheet.*;

import com.pkc.data.PackingDataSource;
import com.pkc.data.PackingObject;
import com.pkc.geom.RectObject;
import com.pkc.packing.PackingAlgorithm;
import com.pkc.settings.Settings;
import com.pkc.util.Tools;
import com.plugin.PluginManager;
import plugins.GenByCutting.GenByCutting;

public class cut3D extends AbstractTask
implements TaskWithAnalyzers{

    public cut3D()
    {
        domain = new cut3DDomain();

        //PackingDataSource.PackingProblem problem = new PackingDataSource.PackingProblem(3);

    	int containerCount = 1;
    	int containerLength = 1000;
    	int containerWidth  = 500;
    	int containerHeight = 500 ;
    	int times = 10;
    	//dataGenMethodComboBox = { "equal parts", "random size parts", "non guillotine cut" }
    	int dataGenMethodComboBox = 2;

		//Create containers
		for (int j = 0; j < containerCount; j++) {

			RectObject container = new RectObject(3);
			// Set container position and dimensions
			int containerDims[] = {containerLength, containerWidth, containerHeight };
			for (int i = 0; i < container.getDimension(); i++) {
				container.setStart(i, - containerDims[i] / 2);
				container.setDim(i, containerDims[i]);
			}
			container.setProperty(PackingObject.OBJECT_NAME, "test container");
			container.setProperty("Width", new Integer(container.getDim(0)));
			container.setProperty("Height", new Integer(container.getDim(1)));
			container.setProperty("Depth", new Integer(container.getDim(2)));
			problem.addContainer(container);

			cut(container.getDimension(), problem.getObjects(), /*times - 1*/2, container, dataGenMethodComboBox);
		}
		// Set object properties
		for (int i = 0; i < problem.getObjects().size(); i++) {
			RectObject object = (RectObject)problem.getObjects().get(i);
			object.setObjectClass(i);
			object.setProperty(PackingObject.OBJECT_NAME, "object");
			object.setProperty("Width", new Integer(object.getDim(0)));
			object.setProperty("Height", new Integer(object.getDim(1)));
			object.setProperty("Depth", new Integer(object.getDim(2)));
			object.setProperty(PackingObject.OBJECT_COLOR, new Color(Tools.random.nextFloat(), Tools.random.nextFloat(), Tools.random.nextFloat()));
		}
		problem.setClassCount(problem.getObjects().size());
    }

    public Class[] analyzers()
        throws ClassNotFoundException
    {
        Class class1 = Class.forName("lt.ktu.gmj.analysis.NonGuillotineCTS");
        return (new Class[] {
            class1
        });
    }

    public void customize(PropertyManager propertymanager)
    {
        /*
        String as[] = {
            "sin", "cos"
        };
        propertymanager.add(new DoubleProperty("Multiplier", new FieldProvider(this, "multiplier"), 0.10000000000000001D, 1000D));
        propertymanager.add(new ChoiceProperty("Function", new FieldProvider(this, "function"), as));
    	*/
    }

    public Domain domain()
    {
        return domain;
    }

    final int CUT_TO_EQUAL_PARTS = 0;
	final int CUT_TO_RANDOM_PARTS = 1;
	final int NON_GUILLOTINE_CUT = 2;

	public void cut(int dimensions, List result, int times, RectObject object, int cutMethod) {

		List temp = new ArrayList(5);
		int newObjectCount = cutMethod == NON_GUILLOTINE_CUT ? 5 : 2;
		for (int i = 0; i < newObjectCount; i++) {
			RectObject ro = new RectObject(dimensions);
			for (int j = 0; j < dimensions; j++)
				ro.setDim(j, object.getDim(j));
			temp.add(ro);
		}
		int index = Tools.random.nextInt(dimensions);
		int value;
		if (cutMethod != NON_GUILLOTINE_CUT) {
			if (cutMethod == CUT_TO_EQUAL_PARTS)
				value = object.getDim(index) / 2;
			else
				value = Tools.random.nextInt(object.getDim(index) - times) + times * 2;
			((RectObject)temp.get(0)).setDim(index, value);
			((RectObject)temp.get(1)).setDim(index, object.getDim(index) - value);
		}
		else {
			// choose _another_ random index
			int index2;
			while ((index2 = Tools.random.nextInt(dimensions)) == index) ;

			((RectObject)temp.get(0)).setDim(index, object.getDim(index) / 3);
			((RectObject)temp.get(0)).setDim(index2, object.getDim(index2) * 2 / 3);

			((RectObject)temp.get(1)).setDim(index, object.getDim(index) / 3);
			((RectObject)temp.get(1)).setDim(index2, object.getDim(index2) * 2 / 3);

			((RectObject)temp.get(2)).setDim(index, object.getDim(index) - ((RectObject)temp.get(0)).getDim(index));
			((RectObject)temp.get(2)).setDim(index2, object.getDim(index2) - ((RectObject)temp.get(0)).getDim(index2));

			((RectObject)temp.get(3)).setDim(index, object.getDim(index) - ((RectObject)temp.get(0)).getDim(index));
			((RectObject)temp.get(3)).setDim(index2, object.getDim(index2) - ((RectObject)temp.get(0)).getDim(index2));

			((RectObject)temp.get(4)).setDim(index, ((RectObject)temp.get(2)).getDim(index) - ((RectObject)temp.get(0)).getDim(index));
			((RectObject)temp.get(4)).setDim(index2, ((RectObject)temp.get(0)).getDim(index2) - ((RectObject)temp.get(2)).getDim(index2));
		}
		if (times > 0)
			for (int i = 0; i < newObjectCount; i++)
				cut(dimensions, result, times - 1, (RectObject)temp.get(i), cutMethod);
		else
			result.addAll(temp);
	}

    public double f(Point point)
    {
    	double sum = point.x[0] + point.x[1] + point.x[2] + point.x[3] + point.x[4];
    	point.x[0] = ((double)(point.x[0]/sum)*100);
    	point.x[1] = ((double)(point.x[1]/sum)*100);
    	point.x[2] = ((double)(point.x[2]/sum)*100);
    	point.x[3] = ((double)(point.x[3]/sum)*100);
    	point.x[4] = ((double)(point.x[4]/sum)*100);
    	//System.out.println("problem size: " + problem.getObjects().size());
		//System.out.println(((RectObject)problem.getObjects().get(0)).getDim(0) + " " + ((RectObject)problem.getObjects().get(0)).getDim(1) + " " + ((RectObject)problem.getObjects().get(0)).getDim(2));
    	PackingAlgorithm packingAlgorithm = new PackingAlgorithm(problem, new int[] { (int) point.x[0], //chooseObjectByGivenDimCriterion
    																				  (int) point.x[1], //chooseLargestVolumeObjectCriterion
    																				  (int) point.x[2],  //chooseMaxRatioObjectCriterion
    																				  (int) point.x[3], //chooseMaxMinObjectCriterion
    																				  (int) point.x[4]  //chooseRandomObjectCriterion
																					 });

    	//long value = packingAlgorithm.packGreedy(packingAlgorithm.chooseLargestVolumeObjectCriterion);
		packingAlgorithm.layerChooserByObjDims.reset();
		long value = packingAlgorithm.packUsingLayers(packingAlgorithm.layerChooserByObjDims, 1000);

		//System.out.println(((RectObject)problem.getContainers().get(0)).getDim(0));
		//System.out.println(((RectObject)problem.getContainers().get(0)).getDim(1));
		//System.out.println(((RectObject)problem.getContainers().get(0)).getDim(2));
		//System.out.println(((RectObject)problem.getContainers().get(0)).getVolume());

		//value=((RectObject)problem.getContainers().get(0)).getVolume() - value;
		return -value;
    }

    private cut3DDomain domain;
    private PackingDataSource.PackingProblem problem = new PackingDataSource.PackingProblem(3);
    Vector vector = new Vector();
}

