/****************************************************************************
Copyright (c) 2010-2012 cocos2d-x.org
Copyright (c) 2009      On-Core
 
http://www.cocos2d-x.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
package org.cocos2d.grid;

import javax.microedition.khronos.opengles.GL10;

import org.cocos2d.CCDirector;
import org.cocos2d.CCDirector.ccDirectorProjection;
import org.cocos2d.base_nodes.CCNode;
import org.cocos2d.cocoa.CCGeometry.CCPoint;
import org.cocos2d.cocoa.CCGeometry.CCSize;
import org.cocos2d.include.ccMacros;
import org.cocos2d.kazmath.kmMat4;
import org.cocos2d.kazmath.GL.Matrix;
import org.cocos2d.opengl.GLResourceHelper;
import org.cocos2d.opengl.GLResourceHelper.Resource;
import org.cocos2d.shaders.ccGLStateCache;
import org.cocos2d.textures.CCTexture2D;
import org.cocos2d.utils.CCFormatter;

import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.opengl.GLES20;

/**
 * @addtogroup effects
 * @{
 */

/** Base class for other
*/
public class CCGridBase {

	public CCGridBase() {
	}

	/** whether or not the grid is active */

	public boolean isActive() {
		return m_bActive;
	}

	public void setActive(boolean bActive) {
		m_bActive = bActive;
		if(! bActive) {
			CCDirector pDirector = CCDirector.sharedDirector();
			ccDirectorProjection proj = pDirector.getProjection();
			pDirector.setProjection(proj);
		}
	}

	/** number of times that the grid will be reused */

	public int getReuseGrid() {
		return m_nReuseGrid ;
	}

	public void setReuseGrid(int nReuseGrid) {
		m_nReuseGrid = nReuseGrid;
	}

	/** size of the grid */
	public CCSize getGridSize() {
		return m_sGridSize;
	}

	public void setGridSize(final CCSize gridSize) {
		m_sGridSize.setSize(gridSize);
	}

	/** pixels between the grids */

	public CCPoint getStep() {
		return m_obStep;
	}

	public void setStep(final CCPoint step) {
		m_obStep.setPoint(step);
	}

	public boolean isTextureFlipped() {
		return m_bIsTextureFlipped;
	}

	public void setTextureFlipped(boolean bFlipped){
		if( m_bIsTextureFlipped != bFlipped ) {
			m_bIsTextureFlipped = bFlipped;
			calculateVertexPoints();
		}
	}

	public boolean initWithSize(final CCSize gridSize, CCTexture2D pTexture, boolean bFlipped) {
		boolean bRet = true;

		m_bActive = false;
		m_nReuseGrid = 0;
		m_sGridSize.setSize(gridSize);

		m_pTexture = pTexture;
		m_bIsTextureFlipped = bFlipped;

		CCSize texSize = m_pTexture.getContentSize();
		m_obStep.x = texSize.width / m_sGridSize.width;
		m_obStep.y = texSize.height / m_sGridSize.height;

		m_pGrabber = new CCGrabber();
		if(m_pGrabber != null) {
			m_pGrabber.grab(m_pTexture);
		} else {
			bRet = false;
		}

// TODO		m_pShaderProgram = CCShaderCache.sharedShaderCache().programForKey(kCCShader_PositionTexture);
		calculateVertexPoints();

		return bRet;
	}

	public boolean initWithSize(final CCSize gridSize) {

		// TODO legacy -->
		CCTexture2D texture = new CCTexture2D();

		texture.setLoader(new GLResourceHelper.GLResourceLoader() {

			@Override
			public void load(Resource res) {
				CCSize s = CCDirector.sharedDirector().getWinSizeInPixels();

				int textureSize = 8;
				while (textureSize < s.width || textureSize < s.height)
					textureSize *= 2;

				if (textureSize > 1024) {
					textureSize = 1024;
				}
				Bitmap bitmap = Bitmap.createBitmap(textureSize, textureSize, Config.ARGB_8888);
				Canvas canvas = new Canvas(bitmap);
				canvas.drawBitmap(bitmap, 0, 0, new Paint());

				((CCTexture2D)res).initWithImage(bitmap, CCSize.Make(textureSize, textureSize));

				init(gridSize, ((CCTexture2D)res), false);
			}
		});

		return true;
	}

	public void beforeDraw() {
		// save projection
		CCDirector director = CCDirector.sharedDirector();
		m_directorProjection = director.getProjection();

		// 2d projection
		//    [director setProjection:kCCDirectorProjection2D];
		set2DProjection();
		m_pGrabber.beforeRender(m_pTexture);
	}

	public void afterDraw(CCNode target) {
		m_pGrabber.afterRender(m_pTexture);

		// restore projection
		CCDirector director = CCDirector.sharedDirector();
		director.setProjection(m_directorProjection);

		if (target.getCamera().isDirty()) {
			CCPoint offset = target.getAnchorPointInPoints();

			//
			// XXX: Camera should be applied in the AnchorPoint
			//
			Matrix.kmGLTranslatef(offset.x, offset.y, 0);
			target.getCamera().locate();
			Matrix.kmGLTranslatef(-offset.x, -offset.y, 0);
		}

		ccGLStateCache.ccGLBindTexture2D(m_pTexture.getName());

		// restore projection for default FBO .fixed bug #543 #544
//TODO:		CCDirector::sharedDirector()->setProjection(CCDirector::sharedDirector()->getProjection());
//TODO:		CCDirector::sharedDirector()->applyOrientation();
		blit();
	}

	public void blit() {
		ccMacros.CCAssert(false, "");
	}

	public void reuse() {
		ccMacros.CCAssert(false, "");
	}

	public void calculateVertexPoints() {
		ccMacros.CCAssert(false, "");
	}

	/** create one Grid */
	public static CCGridBase create(final CCSize gridSize, CCTexture2D texture, boolean flipped) {
		CCGridBase pGridBase = new CCGridBase();

		if (pGridBase != null) {
			if (pGridBase.initWithSize(gridSize, texture, flipped)) {
			} else {
				pGridBase = null;
			}
		}

		return pGridBase;
	}

	/** create one Grid */
	public static CCGridBase create(final CCSize gridSize) {
		CCGridBase pGridBase = new CCGridBase();

		if (pGridBase != null) {
			if (pGridBase.initWithSize(gridSize)) {
			} else {
				pGridBase = null;
			}
		}

		return pGridBase;
	}

	public void set2DProjection() {
		CCDirector director = CCDirector.sharedDirector();

		CCSize size = director.getWinSizeInPixels();

		GLES20.glViewport(0, 0, (int)(size.width * ccMacros.CC_CONTENT_SCALE_FACTOR()), (int)(size.height * ccMacros.CC_CONTENT_SCALE_FACTOR()));
		Matrix.kmGLMatrixMode(Matrix.KM_GL_PROJECTION);
		Matrix.kmGLLoadIdentity();

		kmMat4 orthoMatrix = new kmMat4();
		kmMat4.kmMat4OrthographicProjection(orthoMatrix, 0, size.width * ccMacros.CC_CONTENT_SCALE_FACTOR(), 0, size.height * ccMacros.CC_CONTENT_SCALE_FACTOR(), -1, 1);
		Matrix.kmGLMultMatrix(orthoMatrix);

		Matrix.kmGLMatrixMode(Matrix.KM_GL_MODELVIEW);
		Matrix.kmGLLoadIdentity();

		ccGLStateCache.ccSetProjectionMatrixDirty();
	}

	protected boolean m_bActive;
	protected int m_nReuseGrid;
	protected CCSize m_sGridSize = new CCSize();
	protected CCTexture2D m_pTexture;
	protected CCPoint m_obStep = new CCPoint();
	protected CCGrabber m_pGrabber;
	protected boolean m_bIsTextureFlipped;
// TODO	protected CCGLProgram* m_pShaderProgram;
	protected ccDirectorProjection m_directorProjection;


	// TODO legacy -->

	protected GL10 gl;

    public static final int kTextureSize = 512;


    public int getGridWidth() {
        return (int) m_sGridSize.width;
    }

    public int getGridHeight() {
        return (int) m_sGridSize.height;
    }

    public CCGridBase(GL10 gl, CCSize gridSize, CCTexture2D texture, boolean flipped) {
    	init(gridSize, texture, flipped);
    }
    
    private void init(CCSize gridSize, CCTexture2D texture, boolean flipped) {
    	initWithSize(gridSize, texture, flipped);
    }
    
    public CCGridBase(final CCSize gSize) {
    	initWithSize(gSize);
    }

    public String toString() {
        return CCFormatter.format("<%s : Dimensions = %dx%d>",
        			CCGridBase.class, m_sGridSize.width, m_sGridSize.height);
    }
/*
    // This routine can be merged with Director
    public void applyLandscape(GL10 gl) {
    	CCDirector director = CCDirector.sharedDirector();
        boolean landscape = director.getLandscape();
        CGSize winSize = director.getWinSizeInPixels();
        float w = winSize.width / 2;
     	float h = winSize.height / 2;
     	
        if (landscape) {
        	gl.glTranslatef(w,h,0);
 			gl.glRotatef(-90,0,0,1);
 			gl.glTranslatef(-h,-w,0);
        }
    }

    // This routine can be merged with Director
    public void set3DProjection(GL10 gl) {
        CGSize winSize = CCDirector.sharedDirector().displaySize();

        gl.glViewport(0, 0, (int) winSize.width, (int) winSize.height);
        gl.glMatrixMode(GL10.GL_PROJECTION);
        gl.glLoadIdentity();
        GLU.gluPerspective(gl, 60, winSize.width / winSize.height, 0.5f, 1500.0f);

        gl.glMatrixMode(GL10.GL_MODELVIEW);
        gl.glLoadIdentity();
        GLU.gluLookAt(gl, winSize.width / 2, winSize.height / 2, CCDirector.sharedDirector().getZEye(),
                winSize.width / 2, winSize.height / 2, 0,
                0.0f, 1.0f, 0.0f
        );
    }


    @Override
    public void finalize()  throws Throwable {
    	ccMacros.CCLOGINFO("cocos2d: deallocing %s", this.toString());

    	setActive(false);

        super.finalize();
    }
*/
}

// end of effects group
/// @}
