package org.cocos2d.layers_scenes_transitions_nodes;

import org.cocos2d.include.ccTypes.ccColor3B;
import org.cocos2d.include.ccTypes.ccColor4B;
import org.cocos2d.include.ccTypes.ccColor4F;
import org.cocos2d.types.CGPoint;

/**
 * @addtogroup layer
 * @{
 */

//
//CCLayerGradient
//
/** @brief CCLayerGradient is a subclass of CCLayerColor that draws gradients across the background.
 * 
 * All features from CCLayerColor are valid, plus the following new features:
 * - direction
 * - final color
 * - interpolation mode
 * 
 * Color is interpolated between the startColor and endColor along the given
 * vector (starting at the origin, ending at the terminus).  If no vector is
 * supplied, it defaults to (0, -1) -- a fade from top to bottom.
 * 
 * If 'compressedInterpolation' is disabled, you will not see either the start or end color for
 * non-cardinal vectors; a smooth gradient implying both end points will be still
 * be drawn, however.
 * 
 * If ' compressedInterpolation' is enabled (default mode) you will see both the start and end colors of the gradient.
 * 
 * @since v0.99.5
 */
public class CCLayerGradient extends CCLayerColor {

	/** Creates a full-screen CCLayer with a gradient between start and end. */
	public static CCLayerGradient create(final ccColor4B start, final ccColor4B end) {
		CCLayerGradient pLayer = new CCLayerGradient();
		if((pLayer != null) && pLayer.initWithColor(start, end)) {
			return pLayer;
		}
		pLayer = null;
		return null;
	}

	/** Creates a full-screen CCLayer with a gradient between start and end in the direction of v. */
	public static CCLayerGradient create(final ccColor4B start, final ccColor4B end, final CGPoint v) {
		CCLayerGradient pLayer = new CCLayerGradient();
		if((pLayer != null) && pLayer.initWithColor(start, end, v)) {
			return pLayer;
		}
		pLayer = null;
		return null;
	}

	public boolean init() {
		return initWithColor(ccColor4B.ccc4(0, 0, 0, 255), ccColor4B.ccc4(0, 0, 0, 255));
	}

	/** Initializes the CCLayer with a gradient between start and end. */
	public boolean initWithColor(final ccColor4B start, final ccColor4B end) {
		return initWithColor(start, end, CGPoint.ccp(0, -1));
	}

	/** Initializes the CCLayer with a gradient between start and end in the direction of v. */
	public boolean initWithColor(final ccColor4B start, final ccColor4B end, final CGPoint v) {
		m_endColor.r = end.r;
		m_endColor.g = end.g;
		m_endColor.b = end.b;

		m_cEndOpacity = end.a;
		m_cStartOpacity = start.a;
		m_AlongVector.set(v);

		m_bCompressedInterpolation = true;

		return super.initWithColor(ccColor4B.ccc4(start.r, start.g, start.b, 255));
	}

	protected ccColor3B m_startColor = new ccColor3B(); 

	public ccColor3B getStartColor() {
		return _realColor;
	}

	public void setStartColor(ccColor3B color) {
		setColor(color);
	}

	protected ccColor3B m_endColor = new ccColor3B();

	public ccColor3B getEndColor() {
		return m_endColor;
	}

	public void setEndColor(ccColor3B var) {
		m_endColor.set(var);
		updateColor();
	}

	protected int m_cStartOpacity;

	public int getStartOpacity() {
		return m_cStartOpacity;
	}

	public void setStartOpacity(int o) {
		m_cStartOpacity = o;
		updateColor();
	}

	protected int m_cEndOpacity;

	public int getEndOpacity() {
		return m_cEndOpacity;
	}

	public void setEndOpacity(int o) {
		m_cEndOpacity = o;
		updateColor();
	}

	protected CGPoint m_AlongVector = new CGPoint();

	public CGPoint getVector() {
		return m_AlongVector;
	}

	public void setVector(CGPoint var) {
		m_AlongVector.set(var);
		updateColor();
	}

	/** Whether or not the interpolation will be compressed in order to display all the colors of the gradient both in canonical and non canonical vectors
	 * Default: YES
	 */

	protected boolean m_bCompressedInterpolation;

	public void setCompressedInterpolation(boolean compress) {
		m_bCompressedInterpolation = compress;
		updateColor();
	}

	public boolean isCompressedInterpolation() {
		return m_bCompressedInterpolation;
	}

	public static CCLayerGradient create() {
		CCLayerGradient pRet = new CCLayerGradient();
		if((pRet != null) && pRet.init()) {
		} else {
			pRet = null;
		}
		return pRet;
	}

	protected void updateColor() {
		super.updateColor();

		float h = CGPoint.ccpLength(m_AlongVector);
		if(h == 0) {
			return;
		}

		float c = (float) Math.sqrt(2.0);
		CGPoint u = CGPoint.ccp(m_AlongVector.x / h, m_AlongVector.y / h);

		// Compressed Interpolation mode
		if(m_bCompressedInterpolation) {
			float h2 = 1 / ( Math.abs(u.x) + Math.abs(u.y) );
			u = CGPoint.ccpMult(u, h2 * (float)c);
		}

		float opacityf = (float)_displayedOpacity / 255.0f;

		ccColor4F S = new ccColor4F(
				_displayedColor.r / 255.0f,
				_displayedColor.g / 255.0f,
				_displayedColor.b / 255.0f,
				m_cStartOpacity * opacityf / 255.0f
		);

		ccColor4F E = new ccColor4F(
				m_endColor.r / 255.0f,
				m_endColor.g / 255.0f,
				m_endColor.b / 255.0f,
				m_cEndOpacity * opacityf / 255.0f
		);

		// (-1, -1)
		m_pSquareColors[0].r = E.r + (S.r - E.r) * ((c + u.x + u.y) / (2.0f * c));
		m_pSquareColors[0].g = E.g + (S.g - E.g) * ((c + u.x + u.y) / (2.0f * c));
		m_pSquareColors[0].b = E.b + (S.b - E.b) * ((c + u.x + u.y) / (2.0f * c));
		m_pSquareColors[0].a = E.a + (S.a - E.a) * ((c + u.x + u.y) / (2.0f * c));
		// (1, -1)
		m_pSquareColors[1].r = E.r + (S.r - E.r) * ((c - u.x + u.y) / (2.0f * c));
		m_pSquareColors[1].g = E.g + (S.g - E.g) * ((c - u.x + u.y) / (2.0f * c));
		m_pSquareColors[1].b = E.b + (S.b - E.b) * ((c - u.x + u.y) / (2.0f * c));
		m_pSquareColors[1].a = E.a + (S.a - E.a) * ((c - u.x + u.y) / (2.0f * c));
		// (-1, 1)
		m_pSquareColors[2].r = E.r + (S.r - E.r) * ((c + u.x - u.y) / (2.0f * c));
		m_pSquareColors[2].g = E.g + (S.g - E.g) * ((c + u.x - u.y) / (2.0f * c));
		m_pSquareColors[2].b = E.b + (S.b - E.b) * ((c + u.x - u.y) / (2.0f * c));
		m_pSquareColors[2].a = E.a + (S.a - E.a) * ((c + u.x - u.y) / (2.0f * c));
		// (1, 1)
		m_pSquareColors[3].r = E.r + (S.r - E.r) * ((c - u.x - u.y) / (2.0f * c));
		m_pSquareColors[3].g = E.g + (S.g - E.g) * ((c - u.x - u.y) / (2.0f * c));
		m_pSquareColors[3].b = E.b + (S.b - E.b) * ((c - u.x - u.y) / (2.0f * c));
		m_pSquareColors[3].a = E.a + (S.a - E.a) * ((c - u.x - u.y) / (2.0f * c));
	}
}

// end of layer group
/// @}
