package j3deditor.bin.hierarchy;


import j3deditor.bin.hierarchy.util.HNodeType;

import javax.media.j3d.Appearance;
import javax.media.j3d.TextureAttributes;
import javax.media.j3d.Transform3D;


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

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

	/** actual <code>TextureAttributes</code> object */
	private TextureAttributes ta;


	/** current combine scale factor mode */
	private int csfMode = 0;

	/** current combine mode target */
	private int cmTarget = 0;

	/** current combine color source */
	private int ccsTarget = 0;

	/** current combine color function target */
	private int ccfTarget = 0;


	/**
	 * Creates an instance of <code>J3DeTextureAttributes</code>
	 * with the <code>TextureAttributes</code> object from the
	 * given <code>Appearance</code> object.
	 *
	 * @param appearance
	 *	an instance of <code>Appearance</code> which
	 *	texture attributes component is not <code>null</code>
	 */
	public J3DeTextureAttributes(Appearance appearance){
		super("Texture Attributes", HNodeType.TEXTURE_ATTRIBUTES, numOfNodes);
		numOfNodes++;
		if(appearance.getTextureAttributes() != null){
			ta = appearance.getTextureAttributes();
			setCapabilities();
		} else {
			ta = new TextureAttributes();
			setCapabilities();
			appearance.setTextureAttributes(ta);
		}

		updateTransform();
	}


	/**
	 * Sets the capabilities for the <code>TextureAttributes</code> object.
	 *
	 * <br>Capabilities:<br>
	 * <ul><li><code>TextureAttributes.ALLOW_BLEND_COLOR_READ</code></li>
	 * <li><code>TextureAttributes.ALLOW_BLEND_COLOR_WRITE</code></li>
	 * <li><code>TextureAttributes.ALLOW_COLOR_TABLE_READ</code></li>
	 * <li><code>TextureAttributes.ALLOW_COLOR_TABLE_WRITE</code></li>
	 * <li><code>TextureAttributes.ALLOW_COMBINE_READ</code></li>
	 * <li><code>TextureAttributes.ALLOW_COMBINE_WRITE</code></li>
	 * <li><code>TextureAttributes.ALLOW_MODE_READ</code></li>
	 * <li><code>TextureAttributes.ALLOW_MODE_WRITE</code></li>
	 * <li><code>TextureAttributes.ALLOW_TRANSFORM_READ</code></li>
	 * <li><code>TextureAttributes.ALLOW_TRANSFORM_WRITE</code></li></ul>
	 *
	 * @see javax.media.j3d.TextureAttributes#setCapability(int capability)
	 */
	private void setCapabilities(){
		ta.setCapability(TextureAttributes.ALLOW_BLEND_COLOR_READ);
		ta.setCapability(TextureAttributes.ALLOW_BLEND_COLOR_WRITE);
		ta.setCapability(TextureAttributes.ALLOW_COLOR_TABLE_READ);
		ta.setCapability(TextureAttributes.ALLOW_COLOR_TABLE_WRITE);
		ta.setCapability(TextureAttributes.ALLOW_COMBINE_READ);
		ta.setCapability(TextureAttributes.ALLOW_COMBINE_WRITE);
		ta.setCapability(TextureAttributes.ALLOW_MODE_READ);
		ta.setCapability(TextureAttributes.ALLOW_MODE_WRITE);
		ta.setCapability(TextureAttributes.ALLOW_TRANSFORM_READ);
		ta.setCapability(TextureAttributes.ALLOW_TRANSFORM_WRITE);
	}


	/**
	 * @see javax.media.j3d.TextureAttributes#getCombineRgbScale()
	 * @see javax.media.j3d.TextureAttributes#getCombineAlphaScale()
	 */
	public int getCombineScaleFactor(){
		int scale = scale = ta.getCombineRgbScale();
		if(csfMode == 1){
			scale = ta.getCombineAlphaScale();
		}

		if(scale == 4){
			scale = 3;
		}
		return scale;
	}


	/**
	 * @see javax.media.j3d.TextureAttributes#setCombineRgbScale(int s)
	 * @see javax.media.j3d.TextureAttributes#setCombineAlphaScale(int s)
	 */
	public void setCombineScaleFactor(int scale){
		if(scale > 2){
			scale = 4;
		}

		if(csfMode == 0){
			ta.setCombineRgbScale(scale);
		} else {
			ta.setCombineAlphaScale(scale);
		}
	}


	/**
	 * Returns an array of combine scale factor mode names.
	 *
	 * @return Returns an array of combine scale factor mode names
	 */
	public String[] getCombineScaleFactorModeItems(){
		String[] items = new String[2];
		items[0] = "RGB";
		items[1] = "Alpha";
		return items;
	}


	/**
	 * Returns the current combine scale factor mode.
	 *
	 * @return Returns the current combine scale factor mode
	 */
	public int getCombineScaleFactorMode(){
		return csfMode;
	}


	/**
	 * Sets the current combine scale factor mode.
	 *
	 * @param mode
	 *	new mode
	 */
	public void setCombineScaleFactorMode(int mode){
		csfMode = mode;
	}


	/**
	 * Returns an array of texture mode names.
	 *
	 * @return Returns an array of texture mode names
	 */
	public String[] getTextureModeItems(){
		String[] items = new String[5];
		items[0] = "MODULATE";
		items[1] = "DECAL";
		items[2] = "BLEND";
		items[3] = "REPLACE";
		items[4] = "COMBINE";
		return items;
	}


	/**
	 * @see javax.media.j3d.TextureAttributes#getTextureMode()
	 */
	public int getTextureMode(){
		return (ta.getTextureMode() - 2);
	}


	/**
	 * @see javax.media.j3d.TextureAttributes#setTextureMode(int m)
	 */
	public void setTextureMode(int mode){
		ta.setTextureMode(mode + 2);
	}


	/**
	 * Returns an array of combine mode names.
	 *
	 * @return Returns an array of combine mode names
	 */
	public String[] getCombineModeItems(){
		String[] items = new String[7];
		items[0] = "REPLACE";
		items[1] = "MODULATE";
		items[2] = "ADD";
		items[3] = "ADD SIGNED";
		items[4] = "SUBTRACT";
		items[5] = "INTERPOLATE";
		items[6] = "DOT3";
		return items;
	}


	/**
	 * @see javax.media.j3d.TextureAttributes#getCombineRgbMode()
	 * @see javax.media.j3d.TextureAttributes#getCombineAlphaMode()
	 */
	public int getCombineMode(){
		if(cmTarget == 1){
			return ta.getCombineAlphaMode();
		}
		return ta.getCombineRgbMode();
	}


	/**
	 * @see javax.media.j3d.TextureAttributes#setCombineRgbMode(int m)
	 * @see javax.media.j3d.TextureAttributes#setCombineAlphaMode(int m)
	 */
	public void setCombineMode(int mode){
		if(cmTarget == 0){
			ta.setCombineRgbMode(mode);
		} else {
			ta.setCombineAlphaMode(mode);
		}
	}


	/**
	 * Returns an array of combine mode target names.
	 *
	 * @return Returns an array of combine mode target names
	 */
	public String[] getCombineModeTargetItems(){
		String[] items = new String[2];
		items[0] = "RGB";
		items[1] = "Alpha";
		return items;
	}


	/**
	 * Returns the current combine mode target.
	 *
	 * @return Returns the current combine mode target
	 */
	public int getCombineModeTarget(){
		return cmTarget;
	}


	/**
	 * Sets the current combine mode target.
	 *
	 * @param target
	 *	new target
	 */
	public void setCombineModeTarget(int target){
		cmTarget = target;
	}


	/**
	 * Returns an array of combine color source names.
	 *
	 * @return Returns an array of combine color source names
	 */
	public String[] getCombineColorSourceItems(){
		String[] items = new String[4];
		items[0] = "OBJECT COLOR";
		items[1] = "TEXTURE COLOR";
		items[2] = "CONSTANT COLOR";
		items[3] = "PREVIOUS TEXTURE UNIT STATE";
		return items;
	}


	/**
	 * @see javax.media.j3d.TextureAttributes#getCombineRgbSource(int s)
	 * @see javax.media.j3d.TextureAttributes#getCombineAlphaSource(int s)
	 */
	public int getCombineColorSource(){
		if(ccsTarget < 3){
			return ta.getCombineRgbSource(ccsTarget);
		}
		return ta.getCombineAlphaSource(ccsTarget - 3);
	}


	/**
	 * @see javax.media.j3d.TextureAttributes#setCombineRgbSource(int t, int s)
	 * @see javax.media.j3d.TextureAttributes#setCombineAlphaSource(int t, int s)
	 */
	public void setCombineColorSource(int src){
		if(ccsTarget < 3){
			ta.setCombineRgbSource(ccsTarget, src);
		} else {
			ta.setCombineAlphaSource(ccsTarget - 3, src);
		}
	}


	/**
	 * Returns an array of combine color source target names.
	 *
	 * @return Returns an array of combine color source target names
	 */
	public String[] getCombineColorSourceTargetItems(){
		String[] items = new String[6];
		items[0] = "RGB-1";
		items[1] = "RGB-2";
		items[2] = "RGB-3";
		items[3] = "Alpha-1";
		items[4] = "Alpha-2";
		items[5] = "Alpha-3";
		return items;
	}


	/**
	 * Returns the current combine color source target.
	 *
	 * @return Returns the current combine color source target
	 */
	public int getCombineColorSourceTarget(){
		return ccsTarget;
	}


	/**
	 * Sets the current combine color source target.
	 *
	 * @param target
	 *	new target	
	 */
	public void setCombineColorSourceTarget(int target){
		ccsTarget = target;
	}


	/**
	 * Returns combine color function names.
	 *
	 * @return Returns combine color function names
	 */
	public String[] getCombineColorFunctionItems(){
		String[] items = new String[4];
		items[0] = "SRC COLOR";
		items[1] = "ONE MINUS SRC COLOR";
		items[2] = "SRC ALPHA";
		items[3] = "ONE MINUS SRC ALPHA";
		return items;
	}


	/**
	 * @see javax.media.j3d.TextureAttributes#getCombineRgbFunction(int f)
	 * @see javax.media.j3d.TextureAttributes#getCombineAlphaFunction(int f)
	 */
	public int getCombineColorFunction(){
		if(ccfTarget < 3){
			return ta.getCombineRgbFunction(ccfTarget);
		}
		return ta.getCombineAlphaFunction(ccfTarget - 3);
	}


	/**
	 * @see javax.media.j3d.TextureAttributes#setCombineRgbFunction(int t, int f)
	 * @see javax.media.j3d.TextureAttributes#setCombineAlphaFunction(int t, int f)
	 */
	public void setCombineColorFunction(int function){
		if(ccfTarget < 3){
			ta.setCombineRgbFunction(ccfTarget, function);
		} else {
			ta.setCombineAlphaFunction(ccfTarget - 3, function);
		}
	}


	/**
	 * Returns combine color function target names.
	 *
	 * @return Returns combine color function target names
	 */
	public String[] getCombineColorFunctionTargetItems(){
		String[] items = new String[6];
		items[0] = "RGB-1";
		items[1] = "RGB-2";
		items[2] = "RGB-3";
		items[3] = "Alpha-1";
		items[4] = "Alpha-2";
		items[5] = "Alpha-3";
		return items;
	}


	/**
	 * Returns current combine color function target.
	 *
	 * @return Returns current combine color function target
	 */
	public int getCombineColorFunctionTarget(){
		return ccfTarget;
	}


	/**
	 * Sets the current combine color function target.
	 *
	 * @param target
	 *	new target
	 */
	public void setCombineColorFunctionTarget(int target){
		ccfTarget = target;
	}


	/**
	 * Manipulates the position of texture image.
	 * 
	 * @param x
	 * 	change of position on X-axis
	 * @param isLocal
	 * 	if true transformed in local coordinate system, otherwise global
	 * 
	 * @see j3deditor.bin.hierarchy.J3DeObject#translateX(float x, boolean isLocal)
	 */
	public void translateX(float x, boolean isLocal){
		super.translateX(0.01f * x, isLocal);
		updateTransform();
	}

	/**
	 * Manipulates the position of texture image.
	 * 
	 * @param y
	 * 	change of position on Y-axis
	 * @param isLocal
	 * 	if true transformed in local coordinate system, otherwise global
	 * 
	 * @see j3deditor.bin.hierarchy.J3DeObject#translateY(float y, boolean isLocal)
	 */
	public void translateY(float y, boolean isLocal){
		super.translateY(0.01f * y, isLocal);
		updateTransform();
	}

	/**
	 * Manipulates the position of texture image.
	 * 
	 * @param z
	 * 	change of position on Z-axis
	 * @param isLocal
	 * 	if true transformed in local coordinate system, otherwise global
	 * 
	 * @see j3deditor.bin.hierarchy.J3DeObject#translateZ(float z, boolean isLocal)
	 */
	public void translateZ(float z, boolean isLocal){
		super.translateZ(0.01f * z, isLocal);
		updateTransform();
	}

	/**
	 * Manipulates the position of texture image.
	 * 
	 * @param x
	 * 	change of position on X-axis
	 * @param y
	 * 	change of position on Y-axis
	 * @param z
	 * 	change of position on Z-axis
	 * 
	 * @see j3deditor.bin.hierarchy.J3DeObject#translate(float x, float y, float z)
	 */
	public void translate(float x, float y, float z){
		super.translate(x, y, z);
		updateTransform();
	}

	/**
	 * Manipulates the scale of texture image.
	 * 
	 * @param x
	 * 	change of scale on X-axis
	 * @param isLocal
	 * 	if true transformed in local coordinate system, otherwise global
	 * 
	 * @see j3deditor.bin.hierarchy.J3DeObject#scaleX(float x, boolean isLocal)
	 */
	public void scaleX(float x, boolean isLocal){
		super.scaleX(x, isLocal);
		updateTransform();
	}

	/**
	 * Manipulates the scale of texture image.
	 * 
	 * @param y
	 * 	change of scale on Y-axis
	 * @param isLocal
	 * 	if true transformed in local coordinate system, otherwise global
	 * 
	 * @see j3deditor.bin.hierarchy.J3DeObject#scaleY(float y, boolean isLocal)
	 */
	public void scaleY(float y, boolean isLocal){
		super.scaleY(y, isLocal);
		updateTransform();
	}

	/**
	 * Manipulates the scale of texture image.
	 * 
	 * @param z
	 * 	change of scale on Z-axis
	 * @param isLocal
	 * 	if true transformed in local coordinate system, otherwise global
	 * 
	 * @see j3deditor.bin.hierarchy.J3DeObject#scaleZ(float z, boolean isLocal)
	 */
	public void scaleZ(float z, boolean isLocal){
		super.scaleZ(z, isLocal);
		updateTransform();
	}

	/**
	 * Manipulates the scale of texture image.
	 * 
	 * @param x
	 * 	change of scale on X-axis
	 * @param y
	 * 	change of scale on Y-axis
	 * @param z
	 * 	change of scale on Z-axis
	 * 
	 * @see j3deditor.bin.hierarchy.J3DeObject#scale(float x, float y, float z)
	 */
	public void scale(float x, float y, float z){
		super.scale(x, y, z);
		updateTransform();
	}

	/**
	 * Manipulates the rotation of texture image.
	 * 
	 * @param angle
	 * 	angle of rotation around X-axis
	 * @param isLocal
	 * 	if true transformed in local coordinate system, otherwise global
	 * 
	 * @see j3deditor.bin.hierarchy.J3DeObject#rotateX(float angle, boolean isLocal)
	 */
	public void rotateX(float angle, boolean isLocal){
		super.rotateX(0.1f * angle, isLocal);
		updateTransform();
	}

	/**
	 * Manipulates the rotation of texture image.
	 * 
	 * @param angle
	 * 	angle of rotation around Y-axis
	 * @param isLocal
	 * 	if true transformed in local coordinate system, otherwise global
	 * 
	 * @see j3deditor.bin.hierarchy.J3DeObject#rotateY(float angle, boolean isLocal)
	 */
	public void rotateY(float angle, boolean isLocal){
		super.rotateY(0.1f * angle, isLocal);
		updateTransform();
	}

	/**
	 * Manipulates the rotation of texture image.
	 * 
	 * @param angle
	 * 	angle of rotation around Z-axis
	 * @param isLocal
	 * 	if true transformed in local coordinate system, otherwise global
	 * 
	 * @see j3deditor.bin.hierarchy.J3DeObject#rotateZ(float angle, boolean isLocal)
	 */
	public void rotateZ(float angle, boolean isLocal){
		super.rotateZ(0.1f * angle, isLocal);
		updateTransform();
	}

	/**
	 * Manipulates the rotation of texture image.
	 * 
	 * @param x
	 * 	angle of rotation around X-axis
	 * @param y
	 * 	angle of rotation around Y-axis
	 * @param z
	 * 	angle of rotation around Z-axis
	 * 
	 * @see j3deditor.bin.hierarchy.J3DeObject#rotate(float x, float y, float z)
	 */
	public void rotate(float x, float y, float z){
		super.rotate(x, y, z);
		updateTransform();
	}


	/**
	 * Applies the transformation to the texture attributes.
	 */
	private void updateTransform(){
		Transform3D t = new Transform3D();
		getObject().getTransform(t);
		ta.setTextureTransform(t);
	}


	/**
	 * Returns an array of perspective correction mode names.
	 *
	 * @return an array of perspective correction mode names
	 */
	public String[] getPerspectiveCorrectionItems(){
		String[] items = new String[2];
		items[0] = "NICEST";
		items[1] = "FASTEST";
		return items;
	}


	/**
	 * @see javax.media.j3d.TextureAttributes#getPerspectiveCorrectionMode()
	 */
	public int getPerspectiveCorrection(){
		return ta.getPerspectiveCorrectionMode();
	}


	/**
	 * @see javax.media.j3d.TextureAttributes#setPerspectiveCorrectionMode(int m)
	 */
	public void setPerspectiveCorrection(int mode){
		ta.setPerspectiveCorrectionMode(mode);
	}

}
