package fragmenter;

import Jama.Matrix;
import geometric.Triangle;
import io.ModelIO;

import java.io.File;
import java.util.*;

import util.Model;

/**
 * This abstracts class provides a basis for mesh segmentation algorithms.
 * 
 */
public abstract class Fragmenter {

	Model[] fragments;
	Model model;

	public abstract void doFragmentation(Model mod);

	/**
	 * Writes the fragments as individual .off-files to the given directory.
	 * 
	 * @param dir
	 */
	public void writeFragments(String dir) {
		Model[] fragments = getFragments();
		for (int i = 0; i < fragments.length; i++) {
			if (fragments[i].getTriangles().length > 1) {
				ModelIO.writeModelToOFF(new File(dir + "_" + i + ".off"), fragments[i]);
			}
		}
	}

	/**
	 * Builds the {@link Model} from the given triangle list.
	 * 
	 * @param arrayList
	 * @return
	 */
	protected Model buildModel(List<Triangle> arrayList) {
		int[] vvalues = new int[model.getVertices().size()];
		for (int i = 0; i < vvalues.length; i++) {
			vvalues[i] = -1;
		}
		ArrayList<Matrix> vertices = new ArrayList<Matrix>();
		ArrayList<Triangle> triangles = new ArrayList<Triangle>(arrayList.size());

		int vCount = 0;

		for (Triangle triangle : arrayList) {
			int[] newPositions = new int[3];

			// point 0
			try {
				if (vvalues[triangle.getP0()] == -1) {
					newPositions[0] = vCount;
					vertices.add(triangle.getV0());
					vvalues[triangle.getP0()] = vCount;
					vCount++;
				} else {
					newPositions[0] = vvalues[triangle.getP0()];
				}
			} catch (ArrayIndexOutOfBoundsException e) {
				System.out.println(model.getVertices().size());
				System.out.println(triangle.getVs().size());
				triangle.getV0().print(2, 2);
				throw new RuntimeException("Just keep throwing...");
			}

			// point 1
			if (vvalues[triangle.getP1()] == -1) {
				newPositions[1] = vCount;
				vertices.add(triangle.getV1());
				vvalues[triangle.getP1()] = vCount;
				vCount++;
			} else {
				newPositions[1] = vvalues[triangle.getP1()];
			}

			// point 2
			if (vvalues[triangle.getP2()] == -1) {
				newPositions[2] = vCount;
				vertices.add(triangle.getV2());
				vvalues[triangle.getP2()] = vCount;
				vCount++;
			} else {
				newPositions[2] = vvalues[triangle.getP2()];
			}

			triangles.add(new Triangle(newPositions[0], newPositions[1], newPositions[2], vertices));
		}

		Model m = new Model(vertices, triangles.toArray(new Triangle[0]));
		return m;
	}

	public int getNumberOfFragments() {
		return fragments.length;
	}

	public Model[] getFragments() {
		return fragments;
	}

	public void setFragments(Model[] fragments) {
		this.fragments = fragments;
	}

	public Model getModel() {
		return model;
	}

	public void setModel(Model model) {
		this.model = model;
	}
}
