/* <copyright>
This file contains proprietary software owned by Motorola Mobility, Inc.<br/>
No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.<br/>
(c) Copyright 2011 Motorola Mobility, Inc.  All Rights Reserved.
</copyright> */

var Material = require("js/lib/rdge/materials/material").Material;

///////////////////////////////////////////////////////////////////////
// Class GLTexture
//      GL representation of a texture.
///////////////////////////////////////////////////////////////////////
function Texture( dstWorld, texMapName,  wrap, mips )
{
    ///////////////////////////////////////////////////////////////////////
    // Instance variables
    ///////////////////////////////////////////////////////////////////////
    this._texture;

    // texture attributes
    this._texMapName = texMapName.slice();

    // set default values for wrap and mips
    if (wrap === undefined)
        wrap = "REPEAT";
    if (mips === undefined)
        mips = true;
    this._wrap = wrap;
    this._mips = mips;

   // the canvas generating the texture map (if there is one)
    this._srcCanvas;	
    this._srcWorld;

    // cache whether or not the source is animated
    this._isAnimated = false;
    
    // the destination world that will use the texture map
    this._dstWorld = dstWorld;

    ///////////////////////////////////////////////////////////////////////
    // Property Accessors
    ///////////////////////////////////////////////////////////////////////
    this.getTexture		= function()	{  return this._texture;	}

    this.setSrcWorld	= function(w)	{  this._srcWorld = w;		}
    this.getSrcWorld	= function()	{  return this._srcWorld;	}

    this.setDstWorld	= function(w)	{  this._dstWorld = w;		}
    this.getDstWorld	= function()	{  return this._dstWorld;	}

    this.isAnimated     = function()    {  return this._isAnimated; }

    ///////////////////////////////////////////////////////////////////////
    // Methods
    ///////////////////////////////////////////////////////////////////////

    this.init = function()
    {
        // determine if the source is a canvas or an image file
        var viewUtils = require("js/helper-classes/3D/view-utils").ViewUtils;
        var root = viewUtils.application.ninja.currentDocument.documentRoot;
        var srcCanvas = this.findCanvas( this._texMapName, root );
        if (srcCanvas)
        {
            this._srcCanvas = srcCanvas;
            if (srcCanvas.elementModel && srcCanvas.elementModel.shapeModel && srcCanvas.elementModel.shapeModel.GLWorld)
            {
                this._srcWorld = srcCanvas.elementModel.shapeModel.GLWorld;

                // check if the source is animated
                if (srcCanvas.elementModel && srcCanvas.elementModel.shapeModel  && srcCanvas.elementModel.shapeModel.GLWorld)
                    this._isAnimated = this._srcWorld._hasAnimatedMaterials;
            }

            this.loadFromCanvas();
        }
        else
        {
            this.loadFromFile();  
        }


    }

    this.loadFromFile = function()
    {
        var tex = this._texture;
        this._srcCanvas = null;

        // only load if something has changed
        if (this._texMapName !== texMapName)	// does RDGE allow us to change wrap or mips?
        {
            var texMapName = this._texMapName;
            var wrap = this._wrap;
            var mips = this._mips;

            var dstWorld = this.getDstWorld();
            if (dstWorld)
            {
                var renderer = dstWorld.getRenderer();
                tex = renderer.getTextureByName(texMapName, wrap, mips );
                this._texture = tex;
                dstWorld.textureToLoad( tex );
            }
        }

        return tex;
    }

    var __texCounter = 0;
    this.loadFromCanvas = function()
    {
        var srcCanvas = this._srcCanvas;
        var wrap = this._wrap;
        var mips = this._mips;

        this._texMapName = "GLTexture_" + __texCounter;
        __texCounter++;

        // create the texture
        var world = this.getDstWorld();
        tex = world.getGLContext().createTexture();
        this._texture = tex;
        tex.texparams = new _texparams(wrap, mips);	// defined in renderer.js
        tex.image = new Image;

        // create the canvas and context to render into
        var doc = srcCanvas.ownerDocument;
        this._renderCanvas = doc.createElement("canvas");

        // cache whether this is a 2D canvas or 3D canvas
        var srcCtx = srcCanvas.getContext("2d");
        this._is3D = false;
        if (!srcCtx)  this._is3D = true;

        this.rerender();

        return tex;
    }

    this.rerender = function()
    {
        if (!this._srcCanvas)
        {
            console.log( " no source canvas in GLTexture.rerender" );
            return;
        }
        var srcCanvas = this._srcCanvas;

        var world = this.getDstWorld();
        if (!world)
        {
            console.log( "no world in GLTexture.rerender" );
            return;
        }
        var renderer = world.getRenderer();

        var imageData;
        var width = srcCanvas.width,  height = srcCanvas.height;
        if (!this.isPowerOfTwo(width) || !this.isPowerOfTwo(height))
        {
            width = this.nextLowerPowerOfTwo( width );
            height = this.nextLowerPowerOfTwo( height );
        }

        // create a canvas to be used as the image for the texture map
        var renderCanvas = this._renderCanvas;
        if (!renderCanvas)
        {
            console.log( "no render canvas in GLTexture.rerender" );
            return;
        }
        renderCanvas.width = width;
        renderCanvas.height = height;
        var renderCtx = renderCanvas.getContext("2d");

        // create the texture
        var tex = this._texture;
        if (!tex)
        {
            console.log( "no texture in GLTexture.rerender" );
            return;
        }

        var srcCtx;
        if (!this._is3D)
        {
            srcCtx = srcCanvas.getContext("2d");
            imageData = srcCtx.getImageData( 0, 0, width, height );
            renderCtx.putImageData( imageData, 0, 0 );
        }
        else
        {
            srcCtx = srcCanvas.getContext("experimental-webgl");
            if (srcCtx)
            {
                renderCtx.drawImage(srcCanvas, 0, 0);
//				var data = new Uint8Array(width * height * 4);
//				srcCtx.readPixels(0, 0, width, height, srcCtx.RGBA, srcCtx.UNSIGNED_BYTE, data);
//				imageData = renderCtx.createImageData(width, height);
//				var nBytes = width*height*4;
//				for (var i=0;  i<nBytes;  i++)
//					imageData.data[i] = data[i];
//		        renderCtx.putImageData( imageData, 0, 0 );

            }
        }

        /////////////////
        tex.image = renderCanvas;
        renderer.commitTexture( tex );

        return tex;
}
 
    this.isPowerOfTwo = function(x)
    {
        return (x & (x - 1)) == 0;
    }
 
    this.nextHighestPowerOfTwo = function(x)
    {
        --x;
        for (var i = 1; i < 32; i <<= 1) {
            x = x | x >> i;
        }
        return x + 1;
    }
 
    this.nextLowerPowerOfTwo = function(x)
    {
        return this.nextHighestPowerOfTwo(x) >> 1;
    }

    this.findCanvas = function( id,  elt )
    {
        if (elt.id && elt.id === id)
            return elt;
 
		if (elt.children)
		{
			var nKids = elt.children.length;
			for (var i=0;  i<nKids;  i++)
			{
				var child = elt.children[i];
				var canvas = this.findCanvas( id, child );
                if (canvas)  return canvas;
			}
		}
   }

    /*
    this.findWorld = function( id,  elt )
    {
        if (elt.id && elt.id === id)
        {
            if (elt.elementModel && elt.elementModel.shapeModel && elt.elementModel.shapeModel.GLWorld)
            {
                var world = elt.elementModel.shapeModel.GLWorld;
                return world;
            }
        }
 
		if (elt.children)
		{
			var nKids = elt.children.length;
			for (var i=0;  i<nKids;  i++)
			{
				var child = elt.children[i];
				var world = this.findWorld( id, child );
                if (world)  return world;
			}
		}
   }
   */

   // initialize the object
   this.init();
}

if (typeof exports === "object") {
    exports.Texture = Texture;
}