package j3deditor.bin.hierarchy;


import j3deditor.bin.util.ByteConverter;
import j3deditor.bin.util.Utilities;

import javax.media.j3d.GeometryArray;

import javax.media.j3d.LineArray;
import javax.media.j3d.PointArray;
import javax.media.j3d.QuadArray;
import javax.media.j3d.TriangleArray;

import javax.vecmath.Vector3f;


/**
 * Manages Java 3D <code>javax.media.j3d.GeometryArray</code>
 * object.
 * 
 * @author Risto Seene
 * 
 * @see javax.media.j3d.GeometryArray
 */
public class J3DeGeometryArray extends J3DeGeometry{

	/** vertex data storing mode */
	private int vertexMode;

	/** how are vertices grouped to faces - points(1), lines(2), triangles(3) or quads(4) */
	private int vertexGroupMode;

	/** texture coordinate type - nothing(0), 2D(2), 3D(3) or 4D(4) */
	private int texCoordType;
	
	/** type of vertex colors - nothing(0), COLOR3(3) or COLOR4(4) */
	private int colorType;

	/** true if GeometryArray has vertex normal */
	private boolean normals;

	/** GeometryArray this J3DeGeometryArray manages */
	private GeometryArray geom;

	/** valid vertices */
	private Vertex[] vertices;


	/**
	 * Creates an instance of <code>J3DeGeometryArray</code>.
	 * 
	 * @param geom
	 * 	<code>GeometryArray</code> which data this
	 *        <code>J3DeGeometryArray</code> manages
	 */
	public J3DeGeometryArray(GeometryArray geom){
		super(geom);
		this.geom = geom;

		this.initVertexMode();
		this.initVertexGroupMode();
		this.initTexCoordType();
		this.initNormals();
		this.initColorType();

		this.initVertices();

		if(this.vertexMode == 1 || this.vertexMode == 2){
			this.initVertexReferences();
		}
	}

	/**
	 * Sets neccessary capability bits.
	 * 
	 * @param geom
	 * 	<code>GeometryArray</code> which capability
	 *        bits will be set.
	 *        
	 * @see javax.media.j3d.GeometryArray
	 */
	public static void setCapabilities(GeometryArray geom){
		geom.setCapability(GeometryArray.ALLOW_COLOR_READ);
		geom.setCapability(GeometryArray.ALLOW_COLOR_WRITE);
		geom.setCapability(GeometryArray.ALLOW_COORDINATE_READ);
		geom.setCapability(GeometryArray.ALLOW_COORDINATE_WRITE);
		geom.setCapability(GeometryArray.ALLOW_COUNT_READ);
		geom.setCapability(GeometryArray.ALLOW_COUNT_WRITE);
		geom.setCapability(GeometryArray.ALLOW_FORMAT_READ);
		geom.setCapability(GeometryArray.ALLOW_NORMAL_READ);
		geom.setCapability(GeometryArray.ALLOW_NORMAL_WRITE);
		geom.setCapability(GeometryArray.ALLOW_REF_DATA_READ);
		geom.setCapability(GeometryArray.ALLOW_REF_DATA_WRITE);
		geom.setCapability(GeometryArray.ALLOW_TEXCOORD_READ);
		geom.setCapability(GeometryArray.ALLOW_TEXCOORD_WRITE);
	}

	/**
	 * Initializes the array of vertices.
	 * If array is null creates new <code>Vertex</code> objects,
	 * otherwise copies them and creates new ones only where needed.
	 */
	private void initVertices(){
		int vertCount = geom.getValidVertexCount();
		Vertex[] vs = new Vertex[vertCount];
		if(this.vertices == null){
			for(int i = 0; i < vertCount; i++){
				vs[i] = new Vertex(this, i);
			}
		}
		else {
			for(int i = 0; i < vertCount; i++){
				if(i < vertices.length){
					vs[i] = vertices[i];
				}
				else {
					vs[i] = new Vertex(this, i);
				}
			}
		}

		this.vertices = vs;
	}

	/**
	 * Initialuzes vertex mode.
	 * 0 - normal GeometryArray
	 * 1 - BY_REFERENCE GeometryArray
	 * 2 - INTERLEAVED GeometryArray
	 */
	private void initVertexMode(){
		int format = geom.getVertexFormat();
		if(ByteConverter.isFlagSet(format, GeometryArray.BY_REFERENCE)){
			this.vertexMode = 1;
			if(ByteConverter.isFlagSet(format, GeometryArray.INTERLEAVED)){
				this.vertexMode = 2;
			}
		}
		else {
			this.vertexMode = 0;
		}
	}

	/**
	 * Initializes vertex group mode.
	 * 1 - PointArray
	 * 2 - LineArray
	 * 3 - TriangleArray
	 * 4 - QuadArray
	 */
	private void initVertexGroupMode(){
		if(this.geom instanceof PointArray){
			this.vertexGroupMode = 1;
		}
		else if(this.geom instanceof LineArray){
			this.vertexGroupMode = 2;
		}
		else if(this.geom instanceof TriangleArray){
			this.vertexGroupMode = 3;
		}
		else if(this.geom instanceof QuadArray){
			this.vertexGroupMode = 4;
		}
		else {
			this.vertexGroupMode = 0;
		}
	}

	/**
	 * Initializes texture coordinate type.
	 * 0 - no texture coordinates
	 * 2 - TEXTURE_COORDINATE_2
	 * 3 - TEXTURE_COORDINATE_3
	 * 4 - TEXTURE_COORDINATE_4
	 */
	private void initTexCoordType(){
		int format = this.geom.getVertexFormat();
		if(ByteConverter.isFlagSet(format, GeometryArray.TEXTURE_COORDINATE_2)){
			this.texCoordType = 2;
		}
		else if(ByteConverter.isFlagSet(format, GeometryArray.TEXTURE_COORDINATE_3)){
			this.texCoordType = 3;
		}
		else if(ByteConverter.isFlagSet(format, GeometryArray.TEXTURE_COORDINATE_4)){
			this.texCoordType = 4;
		}
		else {
			this.texCoordType = 0;
		}
	}

	/**
	 * Initializes vertex normals.
	 */
	private void initNormals(){
		int format = geom.getVertexFormat();
		if(ByteConverter.isFlagSet(format, GeometryArray.NORMALS)){
			this.normals = true;
		}
		else {
			this.normals = false;
		}
	}
	
	/**
	 * Initializes vertex color type.
	 * 0 - no vertex color
	 * 3 - COLOR_3
	 * 4 - COLOR_4
	 */
	private void initColorType(){
		this.colorType = 0;
	          int format = geom.getVertexFormat();
	          if(ByteConverter.isFlagSet(format, GeometryArray.COLOR_4 - GeometryArray.COLOR_3)){
	                    this.colorType = 4;
	          }
	          else if(ByteConverter.isFlagSet(format, GeometryArray.COLOR_3)){
	                    this.colorType = 3;
	          }
	}

	/**
	 * Initializes vertex arrays if <code>GeometryArray</code>
	 * is BY_REFERENCE or INTERLEAVED.
	 */
	private void initVertexReferences(){
		int vertCount = this.geom.getVertexCount();
	          int texCoordCount = this.texCoordType * this.geom.getTexCoordSetCount();

		if(this.vertexMode == 1){
			if(this.geom.getCoordRefFloat() == null){
				float coords[] = new float[vertCount * 3];
				for(int i = 0; i < coords.length; i++){
					coords[i] = 0;
				}
				this.geom.setCoordRefFloat(coords);
			}
			for(int i = 0; i < this.geom.getTexCoordSetCount(); i++){
				if(texCoordCount > 0 && this.geom.getTexCoordRefFloat(i) == null){
					float[] coords = new float[vertCount * this.texCoordType];
					for(int j=0; j<coords.length; j++){
						coords[j] = 0;
					}
					this.geom.setTexCoordRefFloat(i, coords);
				}
			}
			if(this.hasNormals() && this.geom.getNormalRefFloat() == null){
				float[] coords = new float[vertCount * 3];
			          for(int i = 0; i < coords.length; i++){
			                    coords[i] = 0;
			          }
			          this.geom.setNormalRefFloat(coords);
			}
			if(this.hasColor() && this.geom.getColorRefFloat() == null){
				float[] color = new float[vertCount * this.colorType];
				for(int i=0; i<color.length; i++){
					color[i] = 0;
				}
				this.geom.setColorRefFloat(color);
			}
		}
		else if(this.vertexMode == 2 && this.geom.getInterleavedVertices() == null){
		          int normalCoordCount = 0;
		          if(this.hasNormals()){
		                    normalCoordCount = 3;
		          }
			float[] coords = new float[vertCount * (3 + texCoordCount + normalCoordCount + this.colorType)];
			for(int i = 0; i < coords.length; i++){
				coords[i] = 0;
			}
			this.geom.setInterleavedVertices(coords);
		}
	}


	/**
	 * Returns all valid vertices.
	 * 
	 * @return all valid vertices
	 */
	protected Vertex[] getVertices(){
		return vertices;
	}
	
	/**
	 * Deletes specified vertices.
	 * 
	 * @param vertices
	 * 	vertices that will be deleted
	 */
	protected void deleteVertices(Vertex[] vertices){
		for(int i=0; i<vertices.length; i++){
			try{
				this.vertices[vertices[i].getIndex()] = null;
			} catch(Throwable t){
				Utilities.out.throwWarning(t);
			}
		}
		int index = 0;
		for(int i=0; i<this.vertices.length; i++){
		          Vertex v = this.vertices[i];
			if(v != null){
				Vertex vv = new VirtualVertex(v);
				this.vertices[index] = new Vertex(this, index);
				this.vertices[index].setData(vv);
				index++;
			}
		}
		this.changeValidVCount(index);
	}

	/**
	 * Changes the amount of valid vertices (and restructures
	 * the array of vertices (Vertex[])).
	 * 
	 * @param newValue
	 * 	new amount of valid vertices
	 */
	protected void changeValidVCount(int newValue){
		if(newValue > this.geom.getVertexCount()){
			newValue = this.geom.getVertexCount();
		}
		this.geom.setValidVertexCount(newValue);
		this.initVertices();
	}

	/**
	 * Returns the amount of all vertices.
	 * 
	 * @return the amount of all vertices
	 * 
	 * @see javax.media.j3d.GeometryArray#getVertexCount()
	 */
	protected int getVertexCount(){
		return this.geom.getVertexCount();
	}


	/**
	 * Returns the coordinates of the specified vertex.
	 * 
	 * @param index
	 * 	index of the vertex
	 * @param axes
	 * 	requested coordinate axes.<br/>
	 *        0 - X-axis<br/>
	 *        1 - Y-axis<br/>
	 *        2 - Z-axis
	 * @return the coordinates of the specified vertex
	 */
	protected float[] getVertexCoordinates(int index, int[] axes){
		float[] coordinates = new float[axes.length];
		if(this.vertexMode == 0){
			float[] coords = new float[3];
			geom.getCoordinate(index, coords);
			for(int i = 0; i < axes.length; i++){
				coordinates[i] = coords[axes[i]];
			}
		}
		else if(this.vertexMode == 1){
			float[] coords = geom.getCoordRefFloat();
			for(int i = 0; i < axes.length; i++){
				coordinates[i] = coords[3 * index + axes[i]];
			}
		}
		else if(this.vertexMode == 2){
			int vertCount = geom.getVertexCount();
			float[] coords = geom.getInterleavedVertices();
			int between = coords.length / vertCount;
			for(int i = 0; i < axes.length; i++){
				coordinates[i] = coords[(index + 1) * between - (3 - axes[i])];
			}
		}
		return coordinates;
	}

	/**
	 * Sets the coordinates of the specified vertex.
	 * 
	 * @param index
	 * 	index of the vertex
	 * @param coordinates
	 * 	new coordinates (only those axes set by <code>axes</code>)
	 * @param axes
	 * 	coordinate axes which will be updated.<br/>
	 *        0 - X-axis<br/>
	 *        1 - Y-axis<br/>
	 *        2 - Z-axis
	 */
	protected void setVertexCoordinates(int index, float[] coordinates, int[] axes){
		if(this.vertexMode == 0){
			float[] coords = new float[3];
			if(coordinates.length == 3){
				coords = coordinates;
			}
			else {
				geom.getCoordinate(index, coords);
				for(int i = 0; i < axes.length; i++){
					coords[axes[i]] = coordinates[i];
				}
			}
			geom.setCoordinate(index, coords);
		}
		else if(this.vertexMode == 1){
			float[] coords = geom.getCoordRefFloat();
			for(int i = 0; i < axes.length; i++){
				coords[3 * index + axes[i]] = coordinates[i];
			}
		}
		else if(this.vertexMode == 2){
			int vertCount = geom.getVertexCount();
			float[] coords = geom.getInterleavedVertices();
			int between = coords.length / vertCount;
			for(int i = 0; i < axes.length; i++){
				coords[(index + 1) * between - (3 - axes[i])] = coordinates[i];
			}
		}
	}


	/**
	 * Returns texture coordinates of the specified vertex.
	 * 
	 * @param index
	 * 	index of the vertex
	 * @param axes
	 * 	requested texture coordinate axes.<br/>
	 *        0 - S-axis<br/>
	 *        1 - T-axis<br/>
	 *        2 - R-axis<br/>
	 *        3 - Q-axis
	 * @param texCoordSet
	 * 	index of the texture coordinate set
	 * @return texture coordinates of the specified vertex
	 */
	protected float[] getTextureCoordinates(int index, int[] axes, int texCoordSet){
		float[] coordinates = new float[axes.length];
		if(this.vertexMode == 0){
			float[] coords = new float[this.texCoordType];
			geom.getTextureCoordinate(texCoordSet, index, coords);
			for(int i = 0; i < axes.length; i++){
				coordinates[i] = coords[axes[i]];
			}
		}
		else if(this.vertexMode == 1){
			float[] coords = geom.getTexCoordRefFloat(texCoordSet);
			for(int i = 0; i < axes.length; i++){
				coordinates[i] = coords[this.texCoordType * index + axes[i]];
			}
		}
		else if(this.vertexMode == 2){
			int vertCount = geom.getVertexCount();
			float[] coords = geom.getInterleavedVertices();
			int between = coords.length / vertCount;
			for(int i = 0; i < axes.length; i++){
				coordinates[i] = coords[index * between + axes[i] + texCoordSet * texCoordType];
			}
		}
		return coordinates;
	}

	/**
	 * Sets texture coordinates of the specified vertex.
	 * 
	 * @param index
	 * 	index of the vertex
	 * @param coordinates
	 * 	new coordinates (only those axes set by <code>axes</code>).
	 * @param axes
	 * 	texture coordinate axes which will be updated.<br/>
	 *        0 - S-axis<br/>
	 *        1 - T-axis<br/>
	 *        2 - R-axis<br/>
	 *        3 - Q-axis
	 * @param texCoordSet
	 * 	index of the texture coordinate set
	 */
	protected void setTextureCoordinates(int index, float[] coordinates, int[] axes, int texCoordSet){
		if(this.vertexMode == 0){
			float[] coords = new float[this.texCoordType];
			if(coordinates.length == this.texCoordType){
				coords = coordinates;
			}
			else {
				geom.getTextureCoordinate(texCoordSet, index, coords);
				for(int i = 0; i < axes.length; i++){
					coords[axes[i]] = coordinates[i];
				}
			}
			geom.setTextureCoordinate(texCoordSet, index, coords);
		}
		else if(this.vertexMode == 1){
			float[] coords = geom.getTexCoordRefFloat(texCoordSet);
			for(int i = 0; i < axes.length; i++){
				coords[this.texCoordType * index + axes[i]] = coordinates[i];
			}
		}
		else if(this.vertexMode == 2){
			int vertCount = geom.getVertexCount();
			float[] coords = geom.getInterleavedVertices();
			int between = coords.length / vertCount;
			for(int i = 0; i < axes.length; i++){
				coords[index * between + axes[i] + texCoordSet * texCoordType] = coordinates[i];
			}
		}
	}


	/**
	 * Returns the vertex normal of the specified vertex.
	 * 
	 * @param index
	 * 	index of the vertex
	 * @return vertex normal of the specified vertex
	 */
	protected float[] getNormal(int index){
		float[] coordinates = new float[]{ 0, 0, 0 };
		if(this.vertexMode == 0){
			geom.getNormal(index, coordinates);
		}
		else if(this.vertexMode == 1){
			float[] coords = geom.getNormalRefFloat();
			coordinates[0] = coords[index * 3];
			coordinates[1] = coords[index * 3 + 1];
			coordinates[2] = coords[index * 3 + 2];
		}
		else if(this.vertexMode == 2){
			int vertCount = geom.getVertexCount();
			float[] coords = geom.getInterleavedVertices();
			int between = coords.length / vertCount;
			coordinates[0] = coords[(index + 1) * between - 6];
			coordinates[1] = coords[(index + 1) * between - 5];
			coordinates[2] = coords[(index + 1) * between - 4];
		}

		return coordinates;
	}

	/**
	 * Sets the vertex normal of the specified vertex.
	 * @param index
	 * 	index of the vertex
	 * @param coordinates
	 * 	normal vector values (X, Y and Z)
	 */
	protected void setNormal(int index, float[] coordinates){
		if(this.vertexMode == 0){
			geom.setNormal(index, coordinates);
		}
		else if(this.vertexMode == 1){
			float[] coords = geom.getNormalRefFloat();
			coords[index * 3] = coordinates[0];
			coords[index * 3 + 1] = coordinates[1];
			coords[index * 3 + 2] = coordinates[2];
		}
		else if(this.vertexMode == 2){
			int vertCount = geom.getVertexCount();
			float[] coords = geom.getInterleavedVertices();
			int between = coords.length / vertCount;
			coords[(index + 1) * between - 6] = coordinates[0];
			coords[(index + 1) * between - 5] = coordinates[1];
			coords[(index + 1) * between - 4] = coordinates[2];
		}
	}


	/**
	 * Returns the color of the specified vertex.
	 * 
	 * @param index
	 * 	index of the vertex
	 * @return the color of the specified vertex
	 */
	protected float[] getColor(int index){
		float[] color = new float[this.colorType];
		if(this.vertexMode == 0){
			geom.getColor(index, color);
		}
		else if(this.vertexMode == 1){
			float[] clr = geom.getColorRefFloat();
			for(int i=0; i<color.length; i++){
				color[i] = clr[index * this.colorType + i];
			}
		}
		else if(this.vertexMode == 2){
			int vertCount = geom.getVertexCount();
			float[] clr = geom.getInterleavedVertices();
			int between = clr.length / vertCount;
			int texCoords = this.getTexCoordSetCount() * this.texCoordType;
			for(int i=0; i<color.length; i++){
				color[i] = clr[index * between + texCoords + i];
			}
		}

		return color;
	}

	/**
	 * Sets the color of the specified vertex.
	 * 
	 * @param index
	 * 	index of the vertex
	 * @param color
	 * 	new color (COLOR_3 or COLOR_4
	 *        according to the type of GeometryArray)
	 */
	protected void setColor(int index, float[] color){
		if(this.vertexMode == 0){
			geom.setColor(index, color);
		}
		else if(this.vertexMode == 1){
			float[] clr = geom.getColorRefFloat();
			for(int i=0; i<this.colorType; i++){
				clr[index * this.colorType + i] = color[i];
			}
		}
		else if(this.vertexMode == 2){
			int vertCount = geom.getVertexCount();
			float[] clr = geom.getInterleavedVertices();
			int between = clr.length / vertCount;
		          int texCoords = this.getTexCoordSetCount() * this.texCoordType;
		          for(int i=0; i<this.colorType; i++){
		                    clr[index * between + texCoords + i] = color[i];
		          }
		}
	}


	/**
	 * Creates new <code>GeometryArray</code> with the specified
	 * properties and sets its valid vertx count to 0.
	 * 
	 * @param type
	 * 	1 - <code>PointArray</code><br/>
	 *        2 - <code>LineArray</code><br/>
	 *        3 - <code>TriangleArray</code><br/>
	 *        4 - <code>QuadArray</code>
	 * @param vertexCount
	 * 	number of vertices
	 * @param vertexFormat
	 * 	a mask indicating which components are present in each vertex,
	 *        see javax.media.j3d.GeometryArray flags
	 * @return <code>J3DeGeometryArray</code> which contains
	 * 	newly created <code>GeometryArray</code>
	 *        
	 * @see javax.media.j3d.GeometryArray
	 */
	public static J3DeGeometryArray createNewGeometryArray(int type, int vertexCount, int vertexFormat){
		GeometryArray geometry = createGeometry(type, vertexCount, vertexFormat);
		geometry.setValidVertexCount(0);
		return new J3DeGeometryArray(geometry);
	}

	/**
	 * Creates and returns new <code>J3DeGeometryArray</code>
	 * which has same properties.
	 * 
	 * @param vertexCount
	 * 	number of vertices
	 * @param vertices
	 * 	vertices which will be copied to new <code>J3DeGeometryArray</code>
	 *        (valid vertices)
	 * @return new <code>J3DeGeometryArray</code>
	 * 	which has same properties
	 */
	public J3DeGeometryArray createSimilarGeometryArray(int vertexCount, Vertex[] vertices){
		if(vertexCount < vertices.length){
			vertexCount = vertices.length;
		}

		int vertexFormat = GeometryArray.COORDINATES;

		if(this.vertexMode >= 1){
			vertexFormat = vertexFormat | GeometryArray.BY_REFERENCE;
			if(this.vertexMode == 2){
				vertexFormat = vertexFormat | GeometryArray.INTERLEAVED;
			}
		}

		if(this.hasNormals()){
			vertexFormat = vertexFormat | GeometryArray.NORMALS;
		}

		if(this.texCoordType == 2){
			vertexFormat = vertexFormat | GeometryArray.TEXTURE_COORDINATE_2;
		}
		else if(this.texCoordType == 3){
			vertexFormat = vertexFormat | GeometryArray.TEXTURE_COORDINATE_3;
		}
		else if(this.texCoordType == 4){
			vertexFormat = vertexFormat | GeometryArray.TEXTURE_COORDINATE_4;
		}
		
		if(this.colorType == 3){
			vertexFormat = vertexFormat | GeometryArray.COLOR_3;
		}
	          else if(this.colorType == 4){
	                    vertexFormat = vertexFormat | GeometryArray.COLOR_4;
	          }
		
		return this.createGeometryArray(vertexCount, vertices, vertexFormat);
	}
	
	/**
	 * Creates new <code>GeometryArray</code> with the specified
	 * vertex format and vertex data from this <code>J3DeGeometryArray</code>.
	 * 
	 * @param vertexFormat
	 * 	a mask indicating which components are present in each vertex,
	 *        see javax.media.j3d.GeometryArray flags
	 * @return <code>J3DeGeometryArray</code> which contains
	 * 	newly created <code>GeometryArray</code>
	 *        
	 * @see javax.media.j3d.GeometryArray
	 */
	public J3DeGeometryArray changeGeometryType(int vertexFormat){
		int vertexCount = this.getVertexCount();
		Vertex[] vertices = this.getVertices();

		return this.createGeometryArray(vertexCount, vertices, vertexFormat);
	}
	

	/**
	 * Creates new <code>GeometryArray</code> and copies vertex data from
	 * the specified vertices.
	 * 
	 * @param vertexCount
	 * 	number of vertices
	 * @param vertices
	 * 	vertices where the data will be copied from
	 * @param vertexFormat
	 * 	vertex format
	 * @return <code>J3DeGeometryArray</code> which contains
	 * 	created <code>GeometryArray</code>
	 */
	private J3DeGeometryArray createGeometryArray(int vertexCount, Vertex[] vertices, int vertexFormat){
		GeometryArray geometry = this.createGeometry(this.vertexGroupMode, vertexCount, vertexFormat);
		geometry.setValidVertexCount(vertices.length);
		J3DeGeometryArray ga = new J3DeGeometryArray(geometry);
		
		int texCoordSetCount = Math.min(this.getTexCoordSetCount(), ga.getTexCoordSetCount());
		int textureType = Math.min(this.getTexCoordType(), ga.getTexCoordType());
		boolean hasNormals = this.hasNormals() && ga.hasNormals();
		int color = Math.min(this.getColorType(), ga.getColorType()); 

		for(int i = 0; i < vertices.length; i++){
			Vertex v = vertices[i];
			ga.setVertexCoordinates(i, v.getCoordinates(), new int[]{ 0, 1, 2 });

			if(textureType > 0){
				for(int j = 0; j < texCoordSetCount; j++){
					int[] axes = new int[textureType];
					for(int k=0; k<textureType; k++){
						axes[k] = k;
					}
					ga.setTextureCoordinates(i, v.getTexCoordinates(j), axes, j);
				}
			}

			if(hasNormals){
				Vector3f n = v.getNormal();
				ga.setNormal(i, new float[]{ n.getX(), n.getY(), n.getZ() });
			}
			
			if(color > 0){
				float[] colors = new float[ga.getColorType()];
				float[] oldCols = v.getColor();
				for(int k=0; k<color; k++){
					colors[k] = oldCols[k];
				}
				ga.setColor(i, colors);
			}
		}

		return ga;
	}

	/**
	 * Creates and returns new GeometryArray (PointArray,
	 * LineArray, TriangleArray or QuadArray) and sets
	 * its capabilities
	 * 
	 * @param type
	 * 	1 - PointArray
	 *        2 - LineArray
	 *        3 - TriangleArray
	 *        4 - QuadArray
	 * @param vertexCount
	 * 	number of vertices
	 * @param vertexFormat
	 * 	vertex format
	 * @return new GeometryArray (PointArray,
	 * 	LineArray, TriangleArray or QuadArray) and sets
	 * 	its capabilities
	 */
	private static GeometryArray createGeometry(int type, int vertexCount, int vertexFormat){
		GeometryArray geometry = null;
		if(type == 1){
			geometry = new PointArray(vertexCount, vertexFormat);
		}
		else if(type == 2){
			geometry = new LineArray(vertexCount, vertexFormat);
		}
		else if(type == 3){
			geometry = new TriangleArray(vertexCount, vertexFormat);
		}
		else if(type == 4){
			geometry = new QuadArray(vertexCount, vertexFormat);
		}
		setCapabilities(geometry);

		return geometry;
	}


	/**
	 * Returns vertex mode.<br/>
	 * 0 - normal <code>GeometryArray</code><br/>
	 * 2 - <code>BY_REFERENCE GeometryArray</code><br/>
	 * 3 - <code>INTERLEAVED GeometryArray</code>
	 * 
	 * @return vertex mode
	 */
	public int getVertexMode(){
		return this.vertexMode;
	}

	/**
	 * Returns vertex group mode.<br/>
	 * 1 - <code>PointArray</code><br/>
	 * 2 - <code>LineArray</code><br/>
	 * 3 - <code>TriangleArray</code><br/>
	 * 4 - <code>QuadArray</code>
	 * 
	 * @return vertex group mode
	 */
	public int getVertexGroupMode(){
		return this.vertexGroupMode;
	}

	/**
	 * Returns the type of texture coordinates.<br/>
	 * 0 - no texture coordinates<br/>
	 * 2 - <code>TEXTURE_COORDINATE_2</code><br/>
	 * 3 - <code>TEXTURE_COORDINATE_3</code><br/>
	 * 4 - <code>TEXTURE_COORDINATE_4</code>
	 * 
	 * @return the type of texture coordinates
	 */
	public int getTexCoordType(){
		return this.texCoordType;
	}

	/**
	 * Returns the amount of texture coordinate sets.
	 * 
	 * @return the amount of texture coordinate sets
	 */
	public int getTexCoordSetCount(){
		return this.geom.getTexCoordSetCount();
	}

	/**
	 * Returns true if vertex normals is enabled, otherwise false.
	 * 
	 * @return true if vertex normals is enabled, otherwise false
	 */
	public boolean hasNormals(){
		return this.normals;
	}
	
	/**
	 * Returns true if vertex colors is enabled, otherwise false.
	 * 
	 * @return true if vertex colors is enabled, otherwise false
	 */
	public boolean hasColor(){
		return this.colorType != 0;
	}
	
	/**
	 * Returns the type of vertex colors.<br/>
	 * 0 - no vertex colors<br/>
	 * 3 - <code>COLOR_3</code><br/>
	 * 4 - <code>COLOR_4</code>
	 * 
	 * @return the type of vertex colors
	 */
	public int getColorType(){
		return this.colorType;
	}
	
	/**
	 * Returns the String representation of this
	 * <code>J3DeGeometryArray</code>.
	 * 
	 * @return the String representation of this
	 * <code>J3DeGeometryArray</code>
	 */
	public String toString(){
		String type = "";
		if(this.vertexMode >= 1){
			type = "(BY REFERENCE";
			if(this.vertexMode >= 2){
				type = type + ", INTERLEAVED";
			}
			type = type + ")";
		}
		
		if(this.vertexGroupMode == 1){
			return "PointArray" + type;
		}
		else if(this.vertexGroupMode == 2){
			return "LineArray" + type;
		}
		else if(this.vertexGroupMode == 3){
			return "TriangleArray" + type;
		}
		else if(this.vertexGroupMode == 4){
			return "QuadArray" + type;
		}
		return "Geometry Array";
	}

}
