package org.cocos2d.grid;

import javax.microedition.khronos.opengles.GL10;

import org.cocos2d.CCDirector;
import org.cocos2d.nodes.CCNode;
import org.cocos2d.opengl.CCTexture2D;
import org.cocos2d.opengl.GLResourceHelper;
import org.cocos2d.opengl.GLResourceHelper.Resource;
import org.cocos2d.types.CGPoint;
import org.cocos2d.types.CGSize;
import org.cocos2d.utils.CCFormatter;

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

/**
 * @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 director = CCDirector.sharedDirector();
			int proj = director.getProjection();
			director.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 CGSize getGridSize() {
		return m_sGridSize;
	}

	public void setGridSize(final CGSize gridSize) {
		m_sGridSize.set(gridSize);
	}

	/** pixels between the grids */

	public CGPoint getStep() {
		return m_obStep;
	}

	public void setStep(final CGPoint step) {
		m_obStep.set(step);
	}

	public boolean isTextureFlipped() {
		return m_bIsTextureFlipped;
	}

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

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

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

		m_pTexture = pTexture;
		m_bIsTextureFlipped = bFlipped;

		CGSize 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 CGSize gridSize) {

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

		texture.setLoader(new GLResourceHelper.GLResourceLoader() {

			@Override
			public void load(Resource res) {
				CGSize 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, CGSize.make(textureSize, textureSize));

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

		return true;
	}

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

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

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

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

		/* TODO legacy -->
		set3DProjection(gl);
		applyLandscape(gl);
		*/

		if (target.getCamera().getDirty()) {
			CGPoint offset = target.getAnchorPointInPoints();

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

		gl.glBindTexture(GL10.GL_TEXTURE_2D, m_pTexture.name());

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

	public void blit(GL10 gl) {
		assert false : "";
	}

	public void reuse(GL10 gl) {
		assert false : "";
	}

	public void calculateVertexPoints() {
		assert false : "";
	}

	/** create one Grid */
	public static CCGridBase create(final CGSize 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 CGSize gridSize) {
		CCGridBase pGridBase = new CCGridBase();

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

		return pGridBase;
	}

	public void set2DProjection(GL10 gl) {
		CGSize winSize = CCDirector.sharedDirector().getWinSizeInPixels();

		gl.glLoadIdentity();
		gl.glViewport(0, 0, (int) winSize.width, (int) winSize.height);
		gl.glMatrixMode(GL10.GL_PROJECTION);
		gl.glLoadIdentity();
		gl.glOrthof(0, winSize.width, 0, winSize.height, -100, 100);
		gl.glMatrixMode(GL10.GL_MODELVIEW);
	}

	protected boolean m_bActive;
	protected int m_nReuseGrid;
	protected CGSize m_sGridSize = new CGSize();
	protected CCTexture2D m_pTexture;
	protected CGPoint m_obStep = new CGPoint();
	protected CCGrabber m_pGrabber;
	protected boolean m_bIsTextureFlipped;
// TODO	protected CCGLProgram* m_pShaderProgram;
	protected int 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, CGSize gridSize, CCTexture2D texture, boolean flipped) {
    	init(gridSize, texture, flipped);
    }
    
    private void init(CGSize gridSize, CCTexture2D texture, boolean flipped) {
    	initWithSize(gridSize, texture, flipped);
    }
    
    public CCGridBase(final CGSize 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
/// @}
