//modified by Vytenis Bivainis, KTU, May 12, 2007

package com.pkc.ui.dialogs;

import java.awt.BorderLayout;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.border.TitledBorder;
import javax.swing.table.AbstractTableModel;

import com.pkc.data.PackingDataSource;
import com.pkc.geom.RectObject;
import com.pkc.settings.Settings;
import com.pkc.ui.component.ContainerPreviewPanel;
import com.pkc.ui.tables.PackingObjectTable;
import com.pkc.packing.PackingAlgorithm;
import com.pkc.util.PackingTask;
import com.pkc.util.Tools;

/**
 * PackDialog shows information about containers, objects to be packed,
 * packing progress and result.
 *
 * @author Mykolas Juraitis
 */
public class PackDialog extends JSplitPane implements Runnable {

	long maxTime;

	int maxIterations;

	long volumeTotal;

	Object[][] stats = new Object[11][2];

	ContainerPreviewPanel packedPanel;

	JTable containersTable;

	JTable objectsTable;

	JTable statsTable;

	PackingTask packingTask;

	PackingAlgorithm packingAlgorithm;

	List loadedResult = new ArrayList();

	String title;

	public JSplitPane leftPanel = new JSplitPane(JSplitPane.VERTICAL_SPLIT);

	public JSplitPane rightPanel = new JSplitPane(JSplitPane.VERTICAL_SPLIT);

	public PackDialog(String title, PackingDataSource.PackingProblem problem) {
		super(JSplitPane.HORIZONTAL_SPLIT);
		setOneTouchExpandable(true);
		leftPanel.setOneTouchExpandable(true);
		rightPanel.setOneTouchExpandable(true);

		this.title = title;

		packingAlgorithm = new PackingAlgorithm(problem, new int[] {Settings.byDimmension,
																	Settings.byVolume,
																	Settings.byRatio,
																	Settings.byMinMax,
																	Settings.byRandom });

		stats[0][0] = "iteration";
		stats[1][0] = "time";
		stats[2][0] = "packed objects";
		stats[3][0] = "packed volume";
		stats[4][0] = "total object volume";
		stats[5][0] = "different objects types";		
		stats[6][0] = "Max-Dimension";                   // naujas
		stats[7][0] = "Max-Value";
		stats[8][0] = "Max-Ratio";
		stats[9][0] = "Max-Min";
		stats[10][0] = "Monte-Carlo";                    // naujas

		JPanel statsPanel = new JPanel(new BorderLayout());
		JPanel resultPanel = new JPanel(new BorderLayout());

		rightPanel.setTopComponent(resultPanel);
		rightPanel.setBottomComponent(statsPanel);

		setLeftComponent(leftPanel);
		setRightComponent(rightPanel);

		RectObject container = (RectObject)problem.getContainers().get(0);

		packedPanel = new ContainerPreviewPanel(container.getMaxDim());

		// Calculate container volume
		volumeTotal = container.getVolume();

		stats[4][1] = new Long(packingAlgorithm.getObjectsVolume()) +  " (" + Tools.percentFormat.format((double)packingAlgorithm.getObjectsVolume() / volumeTotal) + ")";
		stats[5][1] = new Integer(problem.getClassCount());

		JScrollPane scrollPane = new JScrollPane(containersTable = new PackingObjectTable(problem.getContainers()));
		scrollPane.setBorder(new TitledBorder("Containers (" + problem.getContainers().size() + ")"));
		leftPanel.setTopComponent(scrollPane);

		scrollPane = new JScrollPane(objectsTable = new PackingObjectTable(problem.getObjects()));
		scrollPane.setBorder(new TitledBorder("Objects to pack (" + problem.getObjects().size() + ")"));
		//objectsTable.setAutoCreateColumnsFromModel(true);
		leftPanel.setBottomComponent(scrollPane);

		statsPanel.setBorder(new TitledBorder("Progress & Statistics"));
		statsPanel.add(new JScrollPane(statsTable = new JTable(stats, new Object[] {"Parameter", "Value"})));

		packedPanel.setBorder(new TitledBorder("Packed container"));

		resultPanel.add(packedPanel, BorderLayout.CENTER);

		packingTask = new PackingTask(this);

		for (int i = 0; i < packingAlgorithm.getProblem().getObjects().size(); i++) {
			RectObject object = (RectObject)packingAlgorithm.getProblem().getObjects().get(i);
			if (object.getStart(0) != Integer.MIN_VALUE)
				loadedResult.add(object);
		}

		/*addInternalFrameListener(new InternalFrameAdapter() {

				public void internalFrameDeiconified(InternalFrameEvent e) {
					if (loadedResult != null) {
						packedPanel.initialize((RectObject)packingAlgorithm.getProblem().getContainers().get(0), loadedResult);
						loadedResult = null;
					}
				}

				public void internalFrameClosed(InternalFrameEvent e) {
					packingTask.terminate();
					Settings.mainDialog.remove(PackDialog.this);
				}
			});*/

		setVisible(true);
	}

	/**
	 * Start packing.
	 */
	public void startPacking() {
		long value;

		//ListMan.copyObjectList(objectList, packingAlgorithm.getProblem().getObjects());

		// Set stop conditions
		maxTime = packingTask.getRunTime() + Settings.stopTime * 1000;
		maxIterations = packingTask.getIteration() + Settings.stopIterations;

		// Get greedy packing by random
		value = packingAlgorithm.packGreedy(packingAlgorithm.chooseObjectByGivenDimCriterion);                                   // naujas
		stats[6][1] = value + " of " + volumeTotal + " (" +Tools.percentFormat.format((double) value / volumeTotal) + ")";       // naujas
		
		// Get greedy packing by volume
		value = packingAlgorithm.packGreedy(packingAlgorithm.chooseLargestVolumeObjectCriterion);
		stats[7][1] = value + " of " + volumeTotal + " (" + Tools.percentFormat.format((double)value / volumeTotal) + ")";

		// Get greedy packing by ratio
		value = packingAlgorithm.packGreedy(packingAlgorithm.chooseMaxRatioObjectCriterion);
		stats[8][1] = value + " of " + volumeTotal + " (" + Tools.percentFormat.format((double)value / volumeTotal) + ")";

		// Get greedy packing by min. dimension
		value = packingAlgorithm.packGreedy(packingAlgorithm.chooseMaxMinObjectCriterion);
		stats[9][1] = value + " of " + volumeTotal + " (" +Tools.percentFormat.format((double) value / volumeTotal) + ")";
		
		// Get greedy packing by random
		value = packingAlgorithm.packGreedy(packingAlgorithm.chooseRandomObjectCriterion);                                       // naujas
		stats[10][1] = value + " of " + volumeTotal + " (" +Tools.percentFormat.format((double) value / volumeTotal) + ")";       // naujas

		updateStatus();

		// Start packing
		packingTask.setStopped(false);
	}

	/**
	 * Stop packing.
	 */
	public void stopPacking() {
		packingTask.setStopped(true);

		// Render new scene
		packedPanel.initialize((RectObject)packingAlgorithm.getProblem().getContainers().get(0), packingAlgorithm.getBestPacking());

		updateStatus();

		Rectangle oldBounds = getBounds();
		Rectangle newBounds = getBounds();
		newBounds.setSize(newBounds.getSize().width, newBounds.getSize().height - 1);
		setBounds(newBounds);
		setBounds(oldBounds);
	}

	/**
	 * Update status panel information.
	 */
	protected void updateStatus() {
		long volumePacked = 0;
		for (int i = 0; i < packingAlgorithm.getBestPacking().size(); i++) {
			RectObject o = (RectObject)packingAlgorithm.getBestPacking().get(i);
			volumePacked += o.getVolume();
		}

		stats[0][1] = new Integer(packingTask.getIteration());
		stats[1][1] = Tools.flonumFormat.format((double)packingTask.getRunTime() / 1000) + " seconds";
		stats[2][1] = packingAlgorithm.getBestPacking().size() + " of " + packingAlgorithm.getProblem().getObjects().size() + " (" + Tools.percentFormat.format((double)packingAlgorithm.getBestPacking().size() / packingAlgorithm.getProblem().getObjects().size()) + ")";
		stats[3][1] = volumePacked + " of " + volumeTotal + " (" + Tools.percentFormat.format((double)volumePacked / volumeTotal) + ")";

		((AbstractTableModel)statsTable.getModel()).fireTableDataChanged();
	}

	public String toString() {
		return title;
	}

	/**
	 * Runable implementation. This function does actual packing.
	 */
	public void run() {
		updateStatus();
		packingAlgorithm.layerChooserByObjDims.reset();
		packingAlgorithm.packUsingLayers(packingAlgorithm.layerChooserByObjDims, 1000);
		//packingAlgorithm.equalLayerChooser.reset(packingTask.getIteration() + 1);
		//packingAlgorithm.packUsingLayers(packingAlgorithm.equalLayerChooser, 500);

		if ((Settings.stopCondition == Settings.STOP_AFTER_GIVEN_TIME) && (packingTask.getRunTime() >= maxTime) ||
		    (Settings.stopCondition == Settings.STOP_AFTER_GIVEN_ITERATION_COUNT) && (packingTask.getIteration() >= maxIterations) ||
		    (packingAlgorithm.getBestPacking().size() == packingAlgorithm.getProblem().getObjects().size()) ||
		    (packingAlgorithm.getBestValue() == volumeTotal)) {
			stopPacking();
		}

		updateStatus();
	}
}
