package org.cocos2d.layers_scenes_transitions_nodes;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.opengles.GL10;

import org.cocos2d.CCDirector;
import org.cocos2d.config.ccConfig;
import org.cocos2d.include.CCProtocols.CCBlendProtocol;
import org.cocos2d.shaders.CCShaderCache;
import org.cocos2d.types.CGSize;
import org.cocos2d.include.ccTypes.ccBlendFunc;
import org.cocos2d.include.ccTypes.ccColor3B;
import org.cocos2d.include.ccTypes.ccColor4F;
import org.cocos2d.include.ccTypes.ccVertex2F;
import org.cocos2d.include.ccTypes.ccColor4B;

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

//
//CCLayerColor
//
/** @brief CCLayerColor is a subclass of CCLayer that implements the CCRGBAProtocol protocol.
 * 
 * All features from CCLayer are valid, plus the following new features:
 * - opacity
 * - RGB colors
 */
public class CCLayerColor extends CCLayerRGBA
	implements CCBlendProtocol {

	protected ccVertex2F [] m_pSquareVertices = new ccVertex2F[4];
	protected ccColor4F [] m_pSquareColors = new ccColor4F[4];

	protected FloatBuffer squareVertices_;
	protected FloatBuffer squareColors_;

	public CCLayerColor() {
		// default blend function
		m_tBlendFunc.src = ccConfig.CC_BLEND_SRC;
		m_tBlendFunc.dst = ccConfig.CC_BLEND_DST;
	}

	@Override
	public void draw(GL10 gl) {

		// TODO legacy -->

		// Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
		// Needed states: GL_VERTEX_ARRAY, GL_COLOR_ARRAY
		// Unneeded states: GL_TEXTURE_2D, GL_TEXTURE_COORD_ARRAY
		gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
		gl.glDisable(GL10.GL_TEXTURE_2D);

		gl.glVertexPointer(2, GL10.GL_FLOAT, 0, squareVertices_);
		gl.glColorPointer(4, GL10.GL_FLOAT, 0, squareColors_);

		boolean newBlend = false;
		if (m_tBlendFunc.src != ccConfig.CC_BLEND_SRC || m_tBlendFunc.dst != ccConfig.CC_BLEND_DST) {
			newBlend = true;
			gl.glBlendFunc(m_tBlendFunc.src, m_tBlendFunc.dst);
		} else if (_displayedOpacity != 255) {
			newBlend = true;
			gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
		}

		gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);

		if (newBlend)
			gl.glBlendFunc(ccConfig.CC_BLEND_SRC, ccConfig.CC_BLEND_DST);

		// restore default GL state
		gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
		gl.glEnable(GL10.GL_TEXTURE_2D);
	}

	/// override contentSize
	@Override
	public void setContentSize(final CGSize size) {
		/* TODO
		m_pSquareVertices[1].x = size.width;
		m_pSquareVertices[2].y = size.height;
		m_pSquareVertices[3].x = size.width;
		m_pSquareVertices[3].y = size.height;
		*/

		// TODO legacy -->

		// Layer default ctor calls setContentSize priot to nio alloc
		if (squareVertices_ != null) {
			squareVertices_.put(2, size.width);
			squareVertices_.put(5, size.height);
			squareVertices_.put(6, size.width);
			squareVertices_.put(7, size.height);
		}

		// TODO legacy <->

		super.setContentSize(size);
	}

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

	/** creates a CCLayer with color, width and height in Points */
	public static CCLayerColor create(final ccColor4B color, float width, float height) {
		CCLayerColor pLayer = new CCLayerColor();
		if((pLayer != null) && pLayer.initWithColor(color,width,height)) {
			return pLayer;
		}
		pLayer = null;
		return null;
	}

	/** creates a CCLayer with color. Width and height are the window size. */
	public static CCLayerColor create(final ccColor4B color) {
		CCLayerColor pLayer = new CCLayerColor();
		if((pLayer != null) && pLayer.initWithColor(color)) {
			return pLayer;
		}
		pLayer = null;
		return null;
	}

	public boolean init() {
		CGSize s = CCDirector.sharedDirector().getWinSize();
		return initWithColor(ccColor4B.ccc4(0,0,0,0), s.width, s.height);
	}

	/** initializes a CCLayer with color, width and height in Points */
	public boolean initWithColor(final ccColor4B color, float width, float height) {
		if(super.init()) {
			// TODO legacy -->
			ByteBuffer vbb = ByteBuffer.allocateDirect(4 * 2 * 4);
			vbb.order(ByteOrder.nativeOrder());
			squareVertices_ = vbb.asFloatBuffer();

			ByteBuffer sbb = ByteBuffer.allocateDirect(4 * 4 * 4);
			sbb.order(ByteOrder.nativeOrder());
			squareColors_ = sbb.asFloatBuffer();
			// TODO legacy <--

			// default blend function
			m_tBlendFunc.src = GL10.GL_SRC_ALPHA;
			m_tBlendFunc.dst = GL10.GL_ONE_MINUS_SRC_ALPHA;

			_displayedColor.r = _realColor.r = color.r;
			_displayedColor.g = _realColor.g = color.g;
			_displayedColor.b = _realColor.b = color.b;
			_displayedOpacity = color.a;

			/* TODO
			for(size_t i = 0;i < sizeof(m_pSquareVertices) / sizeof( m_pSquareVertices[0]);i++) {
				m_pSquareVertices[i].x = 0.0f;
				m_pSquareVertices[i].y = 0.0f;
			}
			*/

			// TODO legacy -->
			for (int i = 0; i < (4 * 2); i++) {
				squareVertices_.put(i, 0);
			}
			squareVertices_.position(0);
			// TODO legacy <--

			updateColor();
			setContentSize(CGSize.make(width, height));

// TODO			setShaderProgram(CCShaderCache.sharedShaderCache().programForKey(kCCShader_PositionColor));
		}
		return true;
	}

	/** initializes a CCLayer with color. Width and height are the window size. */
	public boolean initWithColor(final ccColor4B color) {
		CGSize s = CCDirector.sharedDirector().getWinSize();
		this.initWithColor(color, s.width, s.height);
		return true;
	}

	/** change width in Points*/
	public void changeWidth(float w) {
		setContentSize(CGSize.make(w, m_obContentSize.height));
	}

	/** change height in Points*/
	public void changeHeight(float h) {
		setContentSize(CGSize.make(m_obContentSize.width, h));
	}

	/** change width and height in Points
	 * @since v0.8
	 */
	public void changeWidthAndHeight(float w, float h) {
		this.setContentSize(CGSize.make(w, h));
	}

	/** BlendFunction. Conforms to CCBlendProtocol protocol */
	protected ccBlendFunc m_tBlendFunc = new ccBlendFunc();

	/// blendFunc getter
	public ccBlendFunc getBlendFunc() {
		return m_tBlendFunc;
	}

	/// blendFunc setter
	public void setBlendFunc(ccBlendFunc var) {
		m_tBlendFunc.src = var.src;
		m_tBlendFunc.dst = var.dst;
	}

	@Override
	public void setOpacityModifyRGB(boolean bValue) {
	}

	@Override
	public boolean isOpacityModifyRGB() {
		return false;
	}

	public void setColor(final ccColor3B color) {
		super.setColor(color);
		updateColor();
	}

	public void setOpacity(int opacity) {
		super.setOpacity(opacity);
		updateColor();
	}

	protected void updateColor() {

		/* TODO
		for(int i=0;i < 4;i++) {
			m_pSquareColors[i].r = _displayedColor.r / 255.0f;
			m_pSquareColors[i].g = _displayedColor.g / 255.0f;
			m_pSquareColors[i].b = _displayedColor.b / 255.0f;
			m_pSquareColors[i].a = _displayedOpacity / 255.0f;
		}
		*/

		// TODO legacy -->

		for (int i = 0; i < squareColors_.limit(); i++) {
			switch (i % 4) {
			case 0:
				squareColors_.put(i, _displayedColor.r / 255f);
				break;
			case 1:
				squareColors_.put(i, _displayedColor.g / 255f);
				break;
			case 2:
				squareColors_.put(i, _displayedColor.b / 255f);
				break;
			default:
				squareColors_.put(i, _displayedOpacity / 255f);
			}
			squareColors_.position(0);
		}
	}



	// TODO legacy -->

    /** creates a CCLayer with color. Width and height are the window size. */
    public static CCLayerColor node(ccColor4B color) {
        CGSize size = CCDirector.sharedDirector().getWinSizeInPixels();
        return new CCLayerColor(color, size.width, size.height);
    }

    /** creates a CCLayer with color, width and height */
    public static CCLayerColor node(ccColor4B color, float w, float h) {
        return new CCLayerColor(color, w, h);
    }

    /** initializes a CCLayer with color. Width and height are the window size. */
    protected CCLayerColor(ccColor4B color) {
        CGSize s = CCDirector.sharedDirector().getWinSizeInPixels();
        init(color, s.width, s.height);
    }

    /** initializes a CCLayer with color, width and height */
    protected CCLayerColor(ccColor4B color, float w, float h) {
    	init(color, w, h);
    }
    
    protected void init(ccColor4B color, float w, float h) {
        ByteBuffer vbb = ByteBuffer.allocateDirect(4 * 2 * 4);
        vbb.order(ByteOrder.nativeOrder());
        squareVertices_ = vbb.asFloatBuffer();

        ByteBuffer sbb = ByteBuffer.allocateDirect(4 * 4 * 4);
        sbb.order(ByteOrder.nativeOrder());
        squareColors_ = sbb.asFloatBuffer();

		_displayedColor.r = _realColor.r = color.r;
		_displayedColor.g = _realColor.g = color.g;
		_displayedColor.b = _realColor.b = color.b;
		_displayedOpacity = color.a;
		m_tBlendFunc.setSrc(ccConfig.CC_BLEND_SRC);
		m_tBlendFunc.setDst(ccConfig.CC_BLEND_DST);

        for (int i = 0; i < (4 * 2); i++) {
            squareVertices_.put(i, 0);
        }
        squareVertices_.position(0);

        updateColor();
        setContentSize(CGSize.make(w, h));
    }
}

// end of layer group
/// @}
