/* <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> */

///////////////////////////////////////////////////////////////////////
// Class ElementPlanes
//      This class represents the 5 planes generated by an element
//      in the world - the face itself, and one plane going back in Z
//      for each side of the element.  Lines drawn will clip against
//      those 5 planes.
///////////////////////////////////////////////////////////////////////
var viewUtils = require("js/helper-classes/3D/view-utils").ViewUtils,
    vecUtils = require("js/helper-classes/3D/vec-utils").VecUtils,
    Rectangle = require("js/helper-classes/3D/rectangle").Rectangle;

var ElementPlanes = exports.ElementPlanes = Object.create(Object.prototype, {
    ///////////////////////////////////////////////////////////////////////
    // Instance variables
    ///////////////////////////////////////////////////////////////////////

    // maintain a back pointer to the original element
    _elt: { value: null, writable: true },

    // the 4 3D boundary points in world space
    _boundaryPts: { value: null, writable: true },

    // the 2D boundary rectangle.  Used for quick rejection tests.
    _rect: { value: null, writable: true },
    _zMin: { value: 0, writable: true },
    _zMax: { value: 0, writable: true },

    // keep a flag indicating that the element is back facing
    _backFacing: { value: false, writable: true },

    // cache the normal
    _planeEq: { value: null, writable: true },

    ///////////////////////////////////////////////////////////////////////
    // Property accessors
    ///////////////////////////////////////////////////////////////////////
    setElement: { value: function( elt )       {  this._elt = elt;             } },
    getElement: { value: function()            {  return this._elt;            } },

    getPlaneEq: { value: function()            {  return this._planeEq.slice(0);  } },
    setPlaneEq: { value: function(p)           {  this._planeEq = p;           } },

    getRectangle: { value: function()            {  return this._rect;           } },
    getBoundaryPoints: { value: function()            {  return this._boundaryPts;    } },
    isBackFacing: { value: function()            {  return this._backFacing;     } },

    getZMin: { value: function()            {  return this._zMin;           } },
    getZMax: { value: function()            {  return this._zMax;           } },

    ///////////////////////////////////////////////////////////////////////
    // Methods
    ///////////////////////////////////////////////////////////////////////
    init: {
        value: function()
        {
            if (this._elt)
            {
                // get the 3D boundary points
                var elt = this._elt;
                this._boundaryPts = viewUtils.getElementViewBounds3D( elt );
                //var mat = viewUtils.getMatrixFromElement( elt );

                var tmpMat = viewUtils.getLocalToGlobalMatrix( elt );
                for (var i=0;  i<4;  i++)
                {
//                this._boundaryPts[i] = viewUtils.localToGlobal(this._boundaryPts[i], elt );
                    this._boundaryPts[i] = viewUtils.localToGlobal2(this._boundaryPts[i], tmpMat);
                }

                // set the backfacing flag based on the direction of the normal
                // for the purposes of stage drawing, we use a left-handed coordinate system
                // (as opposed to the left-handed system used in the browser).  With that
                // assumption, the points are specified counterclockwise on the stage, producing
                // a negative Z for the normal, hence a positive Z implies back facing.
                var nrm = this.computeNormal();
                this._backFacing = false;
                if (nrm[2] > 0)
                    this._backFacing = true;
                else
                    MathUtils.negate( nrm );

                // create the plane equation
                //var d = -( nrm.dot( this._boundaryPts[0]) );
                var d = -vecUtils.vecDot(3, nrm, this._boundaryPts[0]);
                var planeEq = [nrm[0], nrm[1], nrm[2], d] ;
                this.setPlaneEq( planeEq );

                // get the 2D rectangle
                var rect = Object.create(Rectangle, {});
                rect.setLeft( this._boundaryPts[0][0] );
                rect.setTop( this._boundaryPts[0][1] );
                rect.setRight( this._boundaryPts[0][0] );
                rect.setBottom( this._boundaryPts[0][1] );
                this._zMin = this._boundaryPts[0][2];
                this._zMax = this._boundaryPts[0][2];
                for (var i=1;  i<4;  i++)
                {
                    rect.unionPoint( this._boundaryPts[i] );
                    var z = this._boundaryPts[i][2];
                    if (z < this._zMin)  this._zMin = z;
                    if (z > this._zMax)  this._zMax = z;
                }
                this._rect = rect;
            }
        }
    },

    computeNormal: {
        value: function()
        {
            var xPts = new Array(),  yPts = new Array(),  zPts = new Array();
            var n = this._boundaryPts.length;
            for (var i=0;  i<n;  i++)
            {
                var pt = this._boundaryPts[i];
                xPts.push( pt[0] );
                yPts.push( pt[1] );
                zPts.push( pt[2] );
            }
            var nrm = MathUtils.getPolygonNormal( n, xPts, yPts, zPts );

            return nrm;
        }
    }

});