package com.framsticks.net.client3D;

import pl.vorg.mowa.core.graphics.BoundingBox;
import pl.vorg.mowa.core.graphics.Vec3;

/**
 * Framstick creature body class.
 * @author MoMaT, modified by Vorg @ 2007-01-01
 */
public class Creature {
	private String name;
	private String genotype;
	
	public static enum ModelType {
		Parts,
		MechParts
	}

	private int[][] joints = null;
	private float[][] parts = null;
	private float[][] mechParts = null;
	private NeuroDef[] neuroDefs = null;
	private BoundingBox boundingBox;
	private BoundingBox mechBoundingBox;
	
	private int group;
	private int index;
	
	/**
	 * Class constructor. Initializes data structure.
	 * @param name
	 * @param partsCount number of parts
	 * @param jointsCount number of joints
	 * @param group creature group
	 * @param index position in a group
	 */
	public Creature(String name, int group, int index) {
		this.name = name;
		this.group = group;
		this.index = index;
	}
	
	public String toString() {
		return "/" + group + "/" + index + "/" + name;		
	}	
	
	public String getName() {
		return name;
	}
	
	public int getGroup() {
		return group;
	}

	public int getIndex() {
		return index;
	}

	public String getGenotype() {
		return genotype;
	}

	public void setGenotype(String genotype) {
		this.genotype = genotype;
	}

	public int[][] getJoints() {
		return joints;
	}

	public void setJoints(int[][] joints) {
		this.joints = joints;
	}

	public float[][] getParts(ModelType modelType) {
		return (modelType == ModelType.Parts) ? parts : mechParts;
	}

	public void setParts(float[][] value, ModelType modelType) {
		if (modelType == ModelType.Parts)
			parts = value;
		else {
			mechParts = value;
		}
	}

	public void setNeuroDefs(NeuroDef[] defs)
	{ neuroDefs=defs; }

	public NeuroDef[] getNeuroDefs()
	{ return neuroDefs; }
	
	/**
	 * Gets translation vector to the middle point of a joint.
	 * @param index index of joint in a joints array
	 * @return translation vector
	 */
	public float[] jointTranslation(int index, ModelType modelType) {
		float[][] arr = (modelType == ModelType.Parts) ? parts : mechParts;
		Vec3 p1 = new Vec3(arr[joints[index][0]]);
		Vec3 p2 = new Vec3(arr[joints[index][1]]);		
		Vec3 vector = Vec3.sub(p2, p1);
		
		vector.mul(0.5f);
		p1.add(vector);		
		return p1.getVector();
	}	
	/**
	 * Calculates the length of vector between two joint points. 
	 * @param index index of joint in a joints array
	 * @return length of vector
	 */
	public float jointLength(int index, ModelType modelType) {
		float[][] arr = (modelType == ModelType.Parts) ? parts : mechParts;
		Vec3 p1 = new Vec3(arr[joints[index][0]]);
		Vec3 p2 = new Vec3(arr[joints[index][1]]);		
		Vec3 vector = Vec3.sub(p2, p1);
		
		return vector.length();
	}	
	/**
	 * Calculates the angle and the rotation axis between a joint and the base vector. 
	 * @param index index of joint in a joints array
	 * @return the array of angle and axis x, y, z coordinates
	 */
	public float[] jointRotation(int index, ModelType modelType) {
		float[][] arr = (modelType == ModelType.Parts) ? parts : mechParts;
		Vec3 p1 = new Vec3(arr[joints[index][0]]);
		Vec3 p2 = new Vec3(arr[joints[index][1]]);		
		//Vec3 vector = p1.vector(p2);
		Vec3 vector = Vec3.sub(p2, p1);
		Vec3 base = new Vec3(0, 0, 1);

		float cos = Vec3.dot(vector, base)/vector.length();
		float angle = (float)(-Math.acos(cos)*180/Math.PI);

		Vec3 cross = Vec3.cross(vector,base);				
		float[] v = cross.getVector();
		float[] result = new float[4];		
		result[0] = angle;
		result[1] = v[0];
		result[2] = v[1];
		result[3] = v[2];
		return result;
	}
	
	/**
	 * Calculates boundingBox of creature's model
	 * @author vorg
	 * @param modelType
	 * @return boudingBox
	 */
	public BoundingBox getBoundingBox(ModelType modelType) {
		BoundingBox bbox = (modelType == ModelType.Parts) ? boundingBox : mechBoundingBox;
		if (bbox == null) {
			bbox = new BoundingBox();
			float[][] arr = (modelType == ModelType.Parts) ? parts : mechParts;
			for(int i=0; i<arr.length; i++) {
				bbox.add(arr[i][0], arr[i][1], arr[i][2]);
			}
			if (modelType == ModelType.Parts) boundingBox = bbox;
			else mechBoundingBox = bbox;
		}
		return bbox;
	}
}
