package org.cocos2d.nodes;

import javax.microedition.khronos.opengles.GL10;

import org.cocos2d.config.ccConfig;
import org.cocos2d.opengl.CCTexture2D;
import org.cocos2d.include.CCProtocols.CCLabelProtocol;
import org.cocos2d.types.CGSize;
import org.cocos2d.types.ccQuad2;
import org.cocos2d.types.ccQuad3;
import org.cocos2d.types.util.PoolHolder;

/**
 * @addtogroup GUI
 * @{
 * @addtogroup label
 * @{
 */

/** @brief CCLabelAtlas is a subclass of CCAtlasNode.
 * 
 * It can be as a replacement of CCLabel since it is MUCH faster.
 * 
 * CCLabelAtlas versus CCLabel:
 * - CCLabelAtlas is MUCH faster than CCLabel
 * - CCLabelAtlas "characters" have a fixed height and width
 * - CCLabelAtlas "characters" can be anything you want since they are taken from an image file
 * 
 * A more flexible class is CCLabelBMFont. It supports variable width characters and it also has a nice editor.
 */
public class CCLabelAtlas extends CCAtlasNode implements CCLabelProtocol {

	public CCLabelAtlas() {
		m_sString = "";
	}

	/** creates the CCLabelAtlas with a string, a char map file(the atlas), the width and height of each element and the starting char of the atlas */
	public static CCLabelAtlas create(String string, String charMapFile, int itemWidth, int itemHeight, int startCharMap) {
		CCLabelAtlas pRet = new CCLabelAtlas();
		if((pRet != null) && pRet.initWithString(string, charMapFile, itemWidth, itemHeight, startCharMap)) {
			return pRet;
		}
		pRet = null;
		return null;
	}

	/** creates the CCLabelAtlas with a string and a configuration file
	 * @since v2.0
	 */
	public static CCLabelAtlas create(String string, String fntFile) {
		CCLabelAtlas ret = new CCLabelAtlas();
		if(ret != null) {
			if(ret.initWithString(string, fntFile)) {
			} else {
				ret = null;
			}
		}

		return ret;
	}

	/** initializes the CCLabelAtlas with a string, a char map file(the atlas), the width and height of each element and the starting char of the atlas */
	public boolean initWithString(String string, String charMapFile, int itemWidth, int itemHeight, int startCharMap) {
		CCTexture2D texture = CCTextureCache.sharedTextureCache().addImage(charMapFile);
		return initWithString(string, texture, itemWidth, itemHeight, startCharMap);
	}

	/** initializes the CCLabelAtlas with a string and a configuration file
	 * @since v2.0
	 */
	public boolean initWithString(String string, String fntFile) {
/* TODO
		String pathStr = CCFileUtils.sharedFileUtils().fullPathForFilename(fntFile);
		String relPathStr = pathStr.substr(0, pathStr.find_last_of("/"))+"/";
		CCDictionary dict = CCDictionary.createWithContentsOfFile(pathStr.c_str());

		assert (((CCString*)dict->objectForKey("version"))->intValue() == 1 : "Unsupported version. Upgrade cocos2d version";

		String texturePathStr = relPathStr + ((CCString*)dict->objectForKey("textureFilename"))->getCString();
		String textureFilename = String.create(texturePathStr);
		int width = ((CCString*)dict->objectForKey("itemWidth"))->intValue() / CC_CONTENT_SCALE_FACTOR();
		int height = ((CCString*)dict->objectForKey("itemHeight"))->intValue() / CC_CONTENT_SCALE_FACTOR();
		int startChar = ((CCString*)dict->objectForKey("firstChar"))->intValue();

		this.initWithString(theString, textureFilename->getCString(), width, height, startChar);

		return true;
*/
		return false;
	}

	/** initializes the CCLabelAtlas with a string, a texture, the width and height in points of each element and the starting char of the atlas */
	public boolean initWithString(String string, CCTexture2D texture, int itemWidth, int itemHeight, int startCharMap) {
		assert string != null : "";
		if(super.initWithTexture(texture, itemWidth, itemHeight, string.length())) {
			m_uMapStartChar = startCharMap;
			this.setString(string);
			return true;
		}
		return false;
	}

	// super methods

	@Override
	public void updateAtlasValues() {
/* TODO
		int n = m_sString.length();

		ccV3F_C4B_T2F_Quad quad = new ccV3F_C4B_T2F_Quad();

		String s = m_sString;

		CCTexture2D texture = m_pTextureAtlas.getTexture();
		float textureWide = (float) texture.getPixelsWide();
		float textureHigh = (float) texture.getPixelsHigh();
		float itemWidthInPixels = m_uItemWidth * ccMacros.CC_CONTENT_SCALE_FACTOR();
		float itemHeightInPixels = m_uItemHeight * ccMacros.CC_CONTENT_SCALE_FACTOR();

		for(int i = 0; i < n; i++) {
			int a = s.charAt(i) - m_uMapStartChar;
			float row = (float) (a % m_uItemsPerRow);
			float col = (float) (a / m_uItemsPerRow);

			if(ccConfig.CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL != 0) {
				// Issue #938. Don't use texStepX & texStepY
				float left		= (2 * row * itemWidthInPixels + 1) / (2 * textureWide);
				float right		= left + (itemWidthInPixels * 2 - 2) / (2 * textureWide);
				float top		= (2 * col * itemHeightInPixels + 1) / (2 * textureHigh);
				float bottom	= top + (itemHeightInPixels * 2 - 2) / (2 * textureHigh);
			} else {
				float left		= row * itemWidthInPixels / textureWide;
				float right		= left + itemWidthInPixels / textureWide;
				float top		= col * itemHeightInPixels / textureHigh;
				float bottom	= top + itemHeightInPixels / textureHigh;
			} // ! CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL

			quad.tl.texCoords.u = left;
			quad.tl.texCoords.v = top;
			quad.tr.texCoords.u = right;
			quad.tr.texCoords.v = top;
			quad.bl.texCoords.u = left;
			quad.bl.texCoords.v = bottom;
			quad.br.texCoords.u = right;
			quad.br.texCoords.v = bottom;

			quad.bl.vertices.x = (float) (i * m_uItemWidth);
			quad.bl.vertices.y = 0;
			quad.bl.vertices.z = 0.0f;
			quad.br.vertices.x = (float)(i * m_uItemWidth + m_uItemWidth);
			quad.br.vertices.y = 0;
			quad.br.vertices.z = 0.0f;
			quad.tl.vertices.x = (float)(i * m_uItemWidth);
			quad.tl.vertices.y = (float)(m_uItemHeight);
			quad.tl.vertices.z = 0.0f;
			quad.tr.vertices.x = (float)(i * m_uItemWidth + m_uItemWidth);
			quad.tr.vertices.y = (float)(m_uItemHeight);
			quad.tr.vertices.z = 0.0f;

			ccColor4B c = new ccColor4B(_displayedColor.r, _displayedColor.g, _displayedColor.b, _displayedOpacity);
			quad.tl.colors = c;
			quad.tr.colors = c;
			quad.bl.colors = c;
			quad.br.colors = c;
			m_pTextureAtlas->updateQuad(&quad, i);
		}
*/
		// TODO legacy -->
		int n = m_sString.length();
		
		PoolHolder holder = PoolHolder.getInstance();
		ccQuad2 texCoord = holder.getccQuad2Pool().get(); 
		ccQuad3 vertex   = holder.getccQuad3Pool().get(); 
		
//        String s = string_;
		for (int i = 0; i < n; i++) {
			int a = m_sString.charAt(i) - m_uMapStartChar;
			float row = (a % m_uItemsPerRow) * texStepX;
			float col = (a / m_uItemsPerRow) * texStepY;
			
			texCoord.bl_x = row;                        // A - x
			texCoord.bl_y = col;                        // A - y
			texCoord.br_x = row + texStepX;                // B - x
			texCoord.br_y = col;                        // B - y
			texCoord.tl_x = row;                        // C - x
			texCoord.tl_y = col + texStepY;                // C - y
			texCoord.tr_x = row + texStepX;                // D - x
			texCoord.tr_y = col + texStepY;                // D - y
			
			vertex.bl_x = i * m_uItemWidth;                // A - x
			vertex.bl_y = 0;                            // A - y
			vertex.bl_z = 0;                            // A - z
			vertex.br_x = i * m_uItemWidth + m_uItemWidth;    // B - x
			vertex.br_y = 0;                            // B - y
			vertex.br_z = 0;                            // B - z
			vertex.tl_x = i * m_uItemWidth;                // C - x
			vertex.tl_y = m_uItemHeight;                    // C - y
			vertex.tl_z = 0;                            // C - z
			vertex.tr_x = i * m_uItemWidth + m_uItemWidth;    // D - x
			vertex.tr_y = m_uItemHeight;                    // D - y
			vertex.tr_z = 0;                            // D - z
			
			m_pTextureAtlas.updateQuad(texCoord, vertex, i);
		}
		
		holder.getccQuad2Pool().free(texCoord);
		holder.getccQuad3Pool().free(vertex);
		// TODO <-- legacy
	}

	public void setString(String label) {
		int len = label.length();
		if(len > m_pTextureAtlas.getTotalQuads()) {
			m_pTextureAtlas.resizeCapacity(len);
		}
		m_sString = label;
		this.updateAtlasValues();

		CGSize s = CGSize.make(len * m_uItemWidth, m_uItemHeight);

		this.setContentSize(s);

		m_uQuadsToDraw = len;
	}

	public String getString() {
		return m_sString;
	}

	@Override
	public void draw(GL10 gl) {
/* TODO
		if(ccConfig.CC_LABELATLAS_DEBUG_DRAW) {
			super.draw(gl);

			CGSize s = this.getContentSize();
			CGPoint vertices[4]={
					CGPoint.ccp(0,0),
					CGPoint.ccp(s.width,0),
					CGPoint.ccp(s.width,s.height),
					CGPoint.ccp(0,s.height),
			};
			ccDrawPoly(vertices, 4, true);
		} // CC_LABELATLAS_DEBUG_DRAW
*/
		// TODO legacy -->

		// Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
		// Needed states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_TEXTURE_COORD_ARRAY
		// Unneeded states: GL_COLOR_ARRAY
		gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
		gl.glColor4f(_displayedColor.r/255.f, _displayedColor.g/255.f, _displayedColor.b/255.f, _displayedOpacity/255.f);

		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 );
		}

		m_pTextureAtlas.draw(gl, m_sString.length());
	
		if( newBlend )
			gl.glBlendFunc(ccConfig.CC_BLEND_SRC, ccConfig.CC_BLEND_DST);
	
		// Restore Default GL state. Enable GL_COLOR_ARRAY
		gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
	}

	// string to render
	protected String m_sString;
	// the first char in the charmap
	protected int m_uMapStartChar;




    // TODO legacy -->


    /** creates the CCLabelAtlas with a string,
     * a char map file(the atlas), the width and height of each element
     * and the starting char of the atlas */
/*    public static CCLabelAtlas label(CharSequence theString, String charmapfile, int w, int h, char c) {
        return new CCLabelAtlas(theString, charmapfile, w, h, c);
    }
*/
    /** initializes the CCLabelAtlas with a string, a char map file(the atlas), the width and height of each element and the starting char of the atlas */
/*    protected CCLabelAtlas(CharSequence theString, String charmapfile, int w, int h, char c) {
        super(charmapfile, w, h, theString.length());

//        string_ = new TextBuilder(theString.length());
//        string_.append(theString);
        m_sString = theString.toString();
        m_uMapStartChar = c;

        updateAtlasValues();
    }
*/
}

// end of GUI group
/// @}
/// @}
