package j3deditor.bin.hierarchy;


import j3deditor.bin.hierarchy.util.HNodeType;

import java.util.ArrayList;

import javax.media.j3d.Appearance;
import javax.media.j3d.Material;
import javax.media.j3d.Texture;
import javax.media.j3d.TextureAttributes;


/**
 * Contains and manages an instance of
 * <code>javax.media.j3d.Appearance</code>.
 *
 * @author Risto Seene
 * 
 * @see javax.media.j3d.Appearance
 */
public class J3DeAppearance extends HierarchyNode{

	/** number of <code>J3DeAppearance</code> nodes */
	private static long numOfNodes = 0;

	/** subelements of appearance */
	private ArrayList<HierarchyNode> nodes;


	/** actual <code>Appearance</code> object */
	private Appearance appearance;


	/**
	 * Creates an instance of <code>J3DeAppearance</code>
	 * with the given <code>Appearance</code> object
	 * and sets capabilities for it.
	 *
	 * <br>Capabilities:
	 * <ul><li><code>Appearance.ALLOW_COLORING_ATTRIBUTES_READ</code></li>
	 * <li><code>Appearance.ALLOW_COLORING_ATTRIBUTES_WRITE</code></li>
	 * <li><code>Appearance.ALLOW_LINE_ATTRIBUTES_READ</code></li>
	 * <li><code>Appearance.ALLOW_LINE_ATTRIBUTES_WRITE</code></li>
	 * <li><code>Appearance.ALLOW_MATERIAL_READ</code></li>
	 * <li><code>Appearance.ALLOW_MATERIAL_WRITE</code></li>
	 * <li><code>Appearance.ALLOW_POINT_ATTRIBUTES_READ</code></li>
	 * <li><code>Appearance.ALLOW_POINT_ATTRIBUTES_WRITE</code></li>
	 * <li><code>Appearance.ALLOW_POLYGON_ATTRIBUTES_READ</code></li>
	 * <li><code>Appearance.ALLOW_POLYGON_ATTRIBUTES_WRITE</code></li>
	 * <li><code>Appearance.ALLOW_RENDERING_ATTRIBUTES_READ</code></li>
	 * <li><code>Appearance.ALLOW_RENDERING_ATTRIBUTES_WRITE</code></li>
	 * <li><code>Appearance.ALLOW_TEXGEN_READ</code></li>
	 * <li><code>Appearance.ALLOW_TEXGEN_WRITE</code></li>
	 * <li><code>Appearance.ALLOW_TEXTURE_ATTRIBUTES_READ</code></li>
	 * <li><code>Appearance.ALLOW_TEXTURE_ATTRIBUTES_WRITE</code></li>
	 * <li><code>Appearance.ALLOW_TEXTURE_READ</code></li>
	 * <li><code>Appearance.ALLOW_TEXTURE_UNIT_STATE_READ</code></li>
	 * <li><code>Appearance.ALLOW_TEXTURE_UNIT_STATE_WRITE</code></li>
	 * <li><code>Appearance.ALLOW_TEXTURE_WRITE</code></li>
	 * <li><code>Appearance.ALLOW_TRANSPARENCY_ATTRIBUTES_READ</code></li>
	 * <li><code>Appearance.ALLOW_TRANSPARENCY_ATTRIBUTES_WRITE</code></li></ul>
	 *
	 * @param appearance
	 *	an instance of <code>Appearance</code>
	 *
	 * @see javax.media.j3d.Appearance#setCapability(int capability)
	 */
	public J3DeAppearance(Appearance appearance){
		super("Appearance", HNodeType.APPEARANCE, numOfNodes);
		numOfNodes++;
		nodes = new ArrayList<HierarchyNode>();

		this.appearance = appearance;

		appearance.setCapability(Appearance.ALLOW_COLORING_ATTRIBUTES_READ);
		appearance.setCapability(Appearance.ALLOW_COLORING_ATTRIBUTES_WRITE);
		appearance.setCapability(Appearance.ALLOW_LINE_ATTRIBUTES_READ);
		appearance.setCapability(Appearance.ALLOW_LINE_ATTRIBUTES_WRITE);
		appearance.setCapability(Appearance.ALLOW_MATERIAL_READ);
		appearance.setCapability(Appearance.ALLOW_MATERIAL_WRITE);
		appearance.setCapability(Appearance.ALLOW_POINT_ATTRIBUTES_READ);
		appearance.setCapability(Appearance.ALLOW_POINT_ATTRIBUTES_WRITE);
		appearance.setCapability(Appearance.ALLOW_POLYGON_ATTRIBUTES_READ);
		appearance.setCapability(Appearance.ALLOW_POLYGON_ATTRIBUTES_WRITE);
		appearance.setCapability(Appearance.ALLOW_RENDERING_ATTRIBUTES_READ);
		appearance.setCapability(Appearance.ALLOW_RENDERING_ATTRIBUTES_WRITE);
		appearance.setCapability(Appearance.ALLOW_TEXGEN_READ);
		appearance.setCapability(Appearance.ALLOW_TEXGEN_WRITE);
		appearance.setCapability(Appearance.ALLOW_TEXTURE_ATTRIBUTES_READ);
		appearance.setCapability(Appearance.ALLOW_TEXTURE_ATTRIBUTES_WRITE);
		appearance.setCapability(Appearance.ALLOW_TEXTURE_READ);
		appearance.setCapability(Appearance.ALLOW_TEXTURE_UNIT_STATE_READ);
		appearance.setCapability(Appearance.ALLOW_TEXTURE_UNIT_STATE_WRITE);
		appearance.setCapability(Appearance.ALLOW_TEXTURE_WRITE);
		appearance.setCapability(Appearance.ALLOW_TRANSPARENCY_ATTRIBUTES_READ);
		appearance.setCapability(Appearance.ALLOW_TRANSPARENCY_ATTRIBUTES_WRITE);

		initAppearance();
	}


	/**
	 * Initializes the components of this appearance object
	 */
	private void initAppearance(){
		if(appearance.getMaterial() != null){
			J3DeMaterial material = new J3DeMaterial(appearance);
			nodes.add(material);
			material.setParent(this);
		}
		if(appearance.getTexture() != null){
			J3DeTexture texture = new J3DeTexture(appearance);
			nodes.add(texture);
			texture.setParent(this);
		}
		if(appearance.getTextureAttributes() != null){
			J3DeTextureAttributes ta = new J3DeTextureAttributes(appearance);
			nodes.add(ta);
			ta.setParent(this);
		}

		//appearance.setPolygonAttributes(new PolygonAttributes(PolygonAttributes.POLYGON_POINT, PolygonAttributes.CULL_NONE, 0));
		//appearance.setPointAttributes(new PointAttributes(2, false));
	}


	/**
	 * Returns the child at the specified index.
	 *
	 * @param index
	 *	index of child
	 * @return Returns the child with the specified index
	 */
	public HierarchyNode getChild(int index){
		return nodes.get(index);
	}


	/**
	 * Returns the number of children.
	 *
	 * @return Returns the number of children as integer
	 */
	public int getNumberOfChildren(){
		return nodes.size();
	}


	/**
	 * Returns the index of specified child.
	 *
	 * @param child
	 *	child node which index will be returned
	 * @return Returns the index of specified child
	 */
	public int getIndexOfChild(HierarchyNode child){
		return nodes.indexOf(child);
	}


	/**
	 * Tests if the <code>Material</code> component of this node exists.
	 *
	 * @return Returns <code>true</code> if the material component of
	 *	this appearance node exists,
	 *	otherwise <code>false</code>
	 */
	public boolean hasMaterial(){
		if(appearance.getMaterial() != null){
			return true;
		}
		return false;
	}


	/**
	 * Applies new material component to this appearance node
	 * if none exists.
	 */
	public void setMaterial(){
		if(!hasMaterial()){
			J3DeMaterial material = new J3DeMaterial(appearance);
			nodes.add(material);
			material.setParent(this);
		}
	}


	/**
	 * Applies the given material component to this appearance node.
	 *
	 * @param material
	 *	new material
	 */
	public void setMaterial(Material material){
		appearance.setMaterial(material);
	}


	/**
	 * Tests if this appearance node has texture component.
	 *
	 * @return Returns <code>true</code> if the texture component of
	 *	this appearance node exists,
	 *	otherwise <code>false</code>
	 */
	public boolean hasTexture(){
		if(appearance.getTexture() != null){
			return true;
		}
		return false;
	}

	/**
	 * Returns texture.
	 * 
	 * @return texture
	 */
	public J3DeTexture getTexture(){
		if(hasTexture()){
			for(int i = 0; i < nodes.size(); i++){
				if(nodes.get(i) instanceof J3DeTexture){
					return (J3DeTexture)nodes.get(i);
				}
			}
		}
		return null;
	}


	/**
	 * Applies the given texture component to this appearance node.
	 *
	 * @param texture
	 *	new texture
	 */
	public void setTexture(Texture texture){
		if(hasTexture()){
		          this.getTexture().setTexture(texture);
		}
		else {
		          J3DeTexture tex = new J3DeTexture(appearance);
			tex.setTexture(texture);
		          nodes.add(tex);
		          tex.setParent(this);
		}
	          appearance.setTexture(texture);
	}


	/**
	 * Tests if this appearance node has texture attributes component.
	 *
	 * @return Returns <code>true</code> if the texture attributes
	 *	component of this appearance node exists,
	 *	otherwise <code>false</code>
	 */
	public boolean hasTextureAttributes(){
		if(appearance.getTextureAttributes() != null){
			return true;
		}
		return false;
	}


	/**
	 * Applies new texture attributes component to this appearance node.
	 */
	public void setTextureAttributes(){
		if(!hasTextureAttributes()){
			J3DeTextureAttributes ta = new J3DeTextureAttributes(appearance);
			nodes.add(ta);
			ta.setParent(this);
		}
	}


	/**
	 * Applies the given texture attributes component to this appearance node.
	 *
	 * @param ta
	 *	new texture attributes component
	 */
	public void setTextureAttributes(TextureAttributes ta){
		appearance.setTextureAttributes(ta);
	}

	/**
	 * Returns the <code>Appearance</code> object.
	 * @return the <code>Appearance</code> object
	 */
	public Appearance getAppearance(){
		return this.appearance;
	}

	/**
	 * Removes the specified child.
	 * 
	 * @param child
	 * 	child that will be removed
	 */
	@Override
	protected void removeChild(HierarchyNode child){
		this.nodes.remove(child);
	}
}
