//
//	SuperAnimNodeV2.js
//
//  Created by Raymond Lu(Raymondlu1105@qq.com)
//  Created by Natural Style Co. Ltd.(window@na-s.jp)
//  
//  All rights reserved.
//
//  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.
//
var SuperAnim = SuperAnim = SuperAnim || {};

SuperAnim.AnimState = {};

SuperAnim.AnimState.kAnimStateInvalid = -1;
SuperAnim.AnimState.kAnimStateInitialized = 0;
SuperAnim.AnimState.kAnimStatePlaying = 1;
SuperAnim.AnimState.kAnimStatePause = 2;



SuperAnim.SuperAnimNode = cc.Node.extend({
	mId: -1,
	mListener: null,
	mAnimHandler: null,
	mIsLoop: false,
	mAnimState: SuperAnim.AnimState.kAnimStateInvalid,
	// support sprite sheet
	mSpriteSheetFileFullPath: '',
	mUseSpriteSheet: false,
	mSpriteSheet: null,
	mIsFlipX: false,
	mIsFlipY: false,
	mSpeedFactor: 0.0,
	
	
	mReplacedSpriteMap: null,
	
	// for time event
	mLabelNameToTimeEventInfoArrayMap: {},
	mCurTimeEventInfoArray: [],

	ctor: function(){
		this._super();
		this.mAnimHandler = new SuperAnim.SuperAnimHandler();
		this.mReplacedSpriteMap = {};
	},
	dtor: function(){
		this.tryUnloadSpirteSheet();
		this.mReplacedSpriteMap = {};
	},

	init: function(theAbsAnimFile, theId, theListener){
		if (this._super() == false) {
			return false;
		}
		
		// try to load the sprite sheet file
		this.mSpriteSheetFileFullPath = theAbsAnimFile.substring(0, theAbsAnimFile.lastIndexOf('.') + 1) + "plist";
		this.tryLoadSpriteSheet();
		
		this.mAnimHandler = SuperAnim.GetSuperAnimHandler(theAbsAnimFile);
		if (!this.mAnimHandler.IsValid())
		{
			return false;
		}
	
		this.setContentSize(cc.SIZE_PIXELS_TO_POINTS(cc.SizeMake(this.mAnimHandler.mWidth, this.mAnimHandler.mHeight)));
	
		this.mId = theId;
		this.mListener = theListener;
		this.mAnimState = SuperAnim.AnimState.kAnimStateInitialized;
		this.mIsFlipX = this.mIsFlipY = false;
		this.mSpeedFactor = 1.0;
		this.mIsLoop = false;
	
		// shader program
		//### this.setShaderProgram(cc.ShaderCache.sharedShaderCache().programForKey(kCCShader_PositionTextureColor));
		this.scheduleUpdate();
		
		this.setAnchorPoint(cc.p(0.5, 0.5));
	
		return true;
	},
	draw: function(ctx){
		if (this.mAnimState == SuperAnim.AnimState.kAnimStateInvalid ||
			this.mAnimState == SuperAnim.AnimState.kAnimStateInitialized)
		{
			return;
		}
		
		if (!this.mAnimHandler.IsValid()) {
			return;
		}
		
		var anIndex = 0;
		
		var anAnimContentHeightInPixel = this.getContentSize().height * cc.CONTENT_SCALE_FACTOR();
		SuperAnim.BeginIterateAnimObjDrawInfo();
		while (SuperAnim.IterateAnimObjDrawInfo(this.mAnimHandler, SuperAnim.SuperAnimNode.sAnimObjDrawnInfo)) {
			if (SuperAnim.SuperAnimNode.sAnimObjDrawnInfo.mSpriteId == SuperAnim.InvalidSuperAnimSpriteId) {
				cc.Assert(false, "Missing a sprite.");
				continue;
			}
			
			// check whether this sprite has been replaced
			var aCurSpriteId = SuperAnim.SuperAnimNode.sAnimObjDrawnInfo.mSpriteId;
			var anIter = this.mReplacedSpriteMap[aCurSpriteId];
			if (anIter) {
				aCurSpriteId = anIter;
			}
				
			var aSprite = SuperAnim.SuperAnimSpriteMgr.GetInstance().GetSpriteById(aCurSpriteId);
			if (!aSprite){
				cc.Assert(false, "Missing a sprite.");
				continue;
			}
			
			// safe check!!
			if (this.mUseSpriteSheet) {
				cc.Assert(mSpriteSheet === aSprite.mTexture, "must in the same texture!!");
			}
			
			// cocos2d the origin is located at left bottom, but is in left top in flash
			SuperAnim.SuperAnimNode.sAnimObjDrawnInfo.mTransform.mMatrix.m[1][2] = anAnimContentHeightInPixel - SuperAnim.SuperAnimNode.sAnimObjDrawnInfo.mTransform.mMatrix.m[1][2];
			
			//### cc.NODE_DRAW_SETUP();
			
			var aOriginQuad = SuperAnim.cloneObject(aSprite.mQuad);
			aSprite.mQuad = SuperAnim.SuperAnimNode.sAnimObjDrawnInfo.mTransform.mMatrix.op_astQ(aSprite.mQuad);
			var aColor = cc.c4(SuperAnim.SuperAnimNode.sAnimObjDrawnInfo.mColor.mRed, SuperAnim.SuperAnimNode.sAnimObjDrawnInfo.mColor.mGreen, SuperAnim.SuperAnimNode.sAnimObjDrawnInfo.mColor.mBlue, SuperAnim.SuperAnimNode.sAnimObjDrawnInfo.mColor.mAlpha);		
			aSprite.mQuad.bl.colors = SuperAnim.cloneObject(aColor);
			aSprite.mQuad.br.colors = SuperAnim.cloneObject(aColor);
			aSprite.mQuad.tl.colors = SuperAnim.cloneObject(aColor);
			aSprite.mQuad.tr.colors = SuperAnim.cloneObject(aColor);
			
			if (this.mIsFlipX) {
				var aWidthinPixel = this.getContentSize().width * cc.CONTENT_SCALE_FACTOR();
				aSprite.mQuad.bl.vertices.x = aWidthinPixel - aSprite.mQuad.bl.vertices.x;
				aSprite.mQuad.br.vertices.x = aWidthinPixel - aSprite.mQuad.br.vertices.x;
				aSprite.mQuad.tl.vertices.x = aWidthinPixel - aSprite.mQuad.tl.vertices.x;
				aSprite.mQuad.tr.vertices.x = aWidthinPixel - aSprite.mQuad.tr.vertices.x;
			}
			
			if (this.mIsFlipY) {
				var aHeightinPixel = this.getContentSize().height * cc.CONTENT_SCALE_FACTOR();
				aSprite.mQuad.bl.vertices.y = aHeightinPixel - aSprite.mQuad.bl.vertices.y;
				aSprite.mQuad.br.vertices.y = aHeightinPixel - aSprite.mQuad.br.vertices.y;
				aSprite.mQuad.tl.vertices.y = aHeightinPixel - aSprite.mQuad.tl.vertices.y;
				aSprite.mQuad.tr.vertices.y = aHeightinPixel - aSprite.mQuad.tr.vertices.y;
			}
			
			// draw
			if (!this.mUseSpriteSheet)
			{
				/*###
				ccGLBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
				ccGLBindTexture2D(aSprite->mTexture->getName());
				//
				// Attributes
				ccGLEnableVertexAttribs( kCCVertexAttribFlag_PosColorTex );
				
				#define kQuadSize sizeof(aSprite->mQuad.bl)
				long offset = (long)&aSprite->mQuad;
				
				// vertex
				int diff = offsetof( ccV3F_C4B_T2F, vertices);
				glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (void*) (offset + diff));
				
				// texCoods
				diff = offsetof( ccV3F_C4B_T2F, texCoords);
				glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff));
				
				// color
				diff = offsetof( ccV3F_C4B_T2F, colors);
				glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (void*)(offset + diff));
				
				glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
				*/
				
				ctx.save();
				
				// Flip
				var flipX = 1.0;
				var flipY = 1.0;
				if (this.mIsFlipX) {
					flipX *= -1.0;
				}
				if (this.mIsFlipY) {
					flipY *= -1.0;
				}
				ctx.scale(flipX, flipY);
				
				// Matrix
				ctx.transform(
					SuperAnim.SuperAnimNode.sAnimObjDrawnInfo.mTransform.mMatrix.m[0][0],
					SuperAnim.SuperAnimNode.sAnimObjDrawnInfo.mTransform.mMatrix.m[1][0] * -1.0,	//###
					SuperAnim.SuperAnimNode.sAnimObjDrawnInfo.mTransform.mMatrix.m[0][1] * -1.0,	//###
					SuperAnim.SuperAnimNode.sAnimObjDrawnInfo.mTransform.mMatrix.m[1][1],
					SuperAnim.SuperAnimNode.sAnimObjDrawnInfo.mTransform.mMatrix.m[0][2],
					SuperAnim.SuperAnimNode.sAnimObjDrawnInfo.mTransform.mMatrix.m[1][2] * -1.0	//###
				);
				
				// AnchorPoint
				ctx.translate(aSprite.mTexture.width * -0.5, aSprite.mTexture.height * -0.5);
				
				// Color
        		ctx.globalAlpha = SuperAnim.SuperAnimNode.sAnimObjDrawnInfo.mColor.mAlpha / 255;
				
				ctx.drawImage(aSprite.mTexture, 0, 0);
				
				ctx.restore();
			} else {
				// 0
				SuperAnim.SuperAnimNode.sVertexBuffer[anIndex] = aSprite.mQuad.bl.vertices;
				SuperAnim.SuperAnimNode.sTexCoorBuffer[anIndex] = aSprite.mQuad.bl.texCoords;
				SuperAnim.SuperAnimNode.sColorBuffer[anIndex++] = aSprite.mQuad.bl.colors;
				// 1
				SuperAnim.SuperAnimNode.sVertexBuffer[anIndex] = aSprite.mQuad.tl.vertices;
				SuperAnim.SuperAnimNode.sTexCoorBuffer[anIndex] = aSprite.mQuad.tl.texCoords;
				SuperAnim.SuperAnimNode.sColorBuffer[anIndex++] = aSprite.mQuad.tl.colors;
				// 2
				SuperAnim.SuperAnimNode.sVertexBuffer[anIndex] = aSprite.mQuad.br.vertices;
				SuperAnim.SuperAnimNode.sTexCoorBuffer[anIndex] = aSprite.mQuad.br.texCoords;
				SuperAnim.SuperAnimNode.sColorBuffer[anIndex++] = aSprite.mQuad.br.colors;
				// 3
				SuperAnim.SuperAnimNode.sVertexBuffer[anIndex] = aSprite.mQuad.tl.vertices;
				SuperAnim.SuperAnimNode.sTexCoorBuffer[anIndex] = aSprite.mQuad.tl.texCoords;
				SuperAnim.SuperAnimNode.sColorBuffer[anIndex++] = aSprite.mQuad.tl.colors;
				// 4
				SuperAnim.SuperAnimNode.sVertexBuffer[anIndex] = aSprite.mQuad.tr.vertices;
				SuperAnim.SuperAnimNode.sTexCoorBuffer[anIndex] = aSprite.mQuad.tr.texCoords;
				SuperAnim.SuperAnimNode.sColorBuffer[anIndex++] = aSprite.mQuad.tr.colors;
				// 5
				SuperAnim.SuperAnimNode.sVertexBuffer[anIndex] = aSprite.mQuad.br.vertices;
				SuperAnim.SuperAnimNode.sTexCoorBuffer[anIndex] = aSprite.mQuad.br.texCoords;
				SuperAnim.SuperAnimNode.sColorBuffer[anIndex++] = aSprite.mQuad.br.colors;
				
				cc.Assert(anIndex < SuperAnim.SuperAnimNode.MAX_VERTEX_CNT, "buffer is not enough");
			}
			
			aSprite.mQuad = aOriginQuad;
		}
		
		if (this.mUseSpriteSheet) {
			/*###
			// Be sure that you call this macro every draw
			CC_NODE_DRAW_SETUP();
			
			ccGLBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
			ccGLBindTexture2D(mSpriteSheet->getName());
			//
			// Attributes
			ccGLEnableVertexAttribs( kCCVertexAttribFlag_PosColorTex );
			
			// vertex
			glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, 0, (void*) (sVertexBuffer));
			
			// texCoods
			glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, 0, (void*)(sTexCoorBuffer));
			
			// color
			glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, (void*)(sColorBuffer));
			
			glDrawArrays(GL_TRIANGLES, 0, anIndex);
			*/
		}
	},
	update: function(dt){
		if (this.mAnimState != SuperAnim.AnimState.kAnimStatePlaying)
		{
			return;
		}
		
		var isNewLabel = [false];
		var anOriginFrameRate = this.mAnimHandler.mAnimRate;
		this.mAnimHandler.mAnimRate *= this.mSpeedFactor;
		SuperAnim.IncAnimFrameNum(this.mAnimHandler, dt, isNewLabel);
		this.mAnimHandler.mAnimRate = anOriginFrameRate;
		
		var aTimeFactor = (this.mAnimHandler.mCurFrameNum - this.mAnimHandler.mFirstFrameNumOfCurLabel) / (this.mAnimHandler.mLastFrameNumOfCurLabel - this.mAnimHandler.mFirstFrameNumOfCurLabel);
		//cc.log("aTimeFactor: " + aTimeFactor);
		
		for (var anIter=0; anIter<this.mCurTimeEventInfoArray.length; ++anIter) {
			if (aTimeFactor >= this.mCurTimeEventInfoArray[anIter].mTimeFactor) {
				// trigger time event
				cc.log("Trigger anim time event: " + this.mId + ", " + anIter.mLabelName + ", " + anIter.mEventId + "");
				if (this.mListener) {
					this.mListener.OnTimeEvent(this.mId, this.mCurTimeEventInfoArray[anIter].mLabelName, this.mCurTimeEventInfoArray[anIter].mEventId);
				}
				break;
			}
		}
		
		// remove obsolete time event
		for (var anIter=0; anIter<this.mCurTimeEventInfoArray.length;) {
			if (aTimeFactor >= this.mCurTimeEventInfoArray[anIter].mTimeFactor) {
				this.mCurTimeEventInfoArray.splice(anIter, 1);
			} else {
				anIter++;
			}
		}
		
		if (isNewLabel[0] && this.mIsLoop) {
			this.PlaySection(this.mAnimHandler.mCurLabel, this.mIsLoop);
		}
		
		if (isNewLabel[0] && this.mListener)
		{
			this.mListener.OnAnimSectionEnd(this.mId, this.mAnimHandler.mCurLabel);
		}
	},
	setFlipX: function(isFlip){
		this.mIsFlipX = isFlip;
	},
	setFlipY: function(isFlip){
		this.mIsFlipY = isFlip;
	},

	PlaySection: function(theLabel, isLoop){
		if (this.mAnimState == SuperAnim.AnimState.kAnimStateInvalid)
		{
			cc.Assert(false, "The animation isn't ready.");
			return false;
		}
	
		if (theLabel == '')
		{
			cc.Assert(false, "Please specify an animation section label to play.");
			return false;
		}
		
		if (SuperAnim.PlayBySection(this.mAnimHandler, theLabel)){
			this.mAnimState = SuperAnim.AnimState.kAnimStatePlaying;
			this.mIsLoop = isLoop;
			
			// set time event info for this run
			this.mCurTimeEventInfoArray = [];
			var anIter = this.mLabelNameToTimeEventInfoArrayMap[theLabel];
			if (anIter) {
				//ORG: mCurTimeEventInfoArray.insert(mCurTimeEventInfoArray.begin(), anIter->second.begin(), anIter->second.end());
				this.mCurTimeEventInfoArray = anIter.concat(this.mCurTimeEventInfoArray);
			}
			
			return true;
		}
	
		// we should not go here.
		// if we do that means you specify a wrong label
		cc.Assert(false, "I cannot find the specified section label in animation.");
		return false;
	},
	Pause: function(){
		this.mAnimState = SuperAnim.AnimState.kAnimStatePause;
	},
	Resume: function(){
		this.mAnimState = SuperAnim.AnimState.kAnimStatePlaying;
	},
	IsPause: function(){
		return this.mAnimState == SuperAnim.AnimState.kAnimStatePause;
	},
	IsPlaying: function(){
		return this.mAnimState == SuperAnim.AnimState.kAnimStatePlaying;
	},
	GetCurFrame: function(){
		return Math.floor(this.mAnimHandler.mCurFrameNum);
	},
	GetId: function(){
		return this.mId;
	},
	GetCurSectionName: function(){
		return this.mAnimHandler.mCurLabel;
	},
	HasSection: function(theLabelName){
		return  SuperAnim.HasSection(this.mAnimHandler, theLabelName);
	},
	setSpeedFactor: function(theNewSpeedFactor){
		this.mSpeedFactor = theNewSpeedFactor;
	},
	
	// for replaceable sprite
	replaceSprite: function(theOriginSpriteName, theNewSpriteName){
		var anOriginSpriteId = SuperAnim.InvalidSuperAnimSpriteId;
		var aCurSpriteId = [SuperAnim.InvalidSuperAnimSpriteId];
		SuperAnim.SuperAnimSpriteMgr.GetInstance().BeginIterateSpriteId();
		while (SuperAnim.SuperAnimSpriteMgr.GetInstance().IterateSpriteId(aCurSpriteId)) {
			var aSuperAnimSprite = SuperAnim.SuperAnimSpriteMgr.GetInstance().GetSpriteById(aCurSpriteId[0]);
			var aSpriteFullPath = aSuperAnimSprite.mStringId;
			if (aSpriteFullPath.substr(aSpriteFullPath.length - theOriginSpriteName.length) == theOriginSpriteName) {
				anOriginSpriteId = aCurSpriteId[0];
				break;
			}
		}
		
		if (anOriginSpriteId != SuperAnim.InvalidSuperAnimSpriteId) {
			//var aNewSpriteId = SuperAnim.SuperAnimSpriteMgr.GetInstance().LoadSuperAnimSprite(cc.FileUtils.sharedFileUtils().fullPathFromRelativePath(theNewSpriteName));
			var aNewSpriteId = SuperAnim.SuperAnimSpriteMgr.GetInstance().LoadSuperAnimSprite(theNewSpriteName);
			cc.Assert(aNewSpriteId != SuperAnim.InvalidSuperAnimSpriteId, "failed to create super anim sprite");
			this.mReplacedSpriteMap[anOriginSpriteId] = aNewSpriteId;
		} else{
			cc.Assert(false, "Original sprite should exist.");
		}
	},
	resumeSprite: function(theOriginSpriteName){
		var anOriginSpriteId = SuperAnim.InvalidSuperAnimSpriteId;
		var aCurSpriteId = [SuperAnim.InvalidSuperAnimSpriteId];
		SuperAnim.SuperAnimSpriteMgr.GetInstance().BeginIterateSpriteId();
		while (SuperAnim.SuperAnimSpriteMgr.GetInstance().IterateSpriteId(aCurSpriteId)) {
			var aSuperAnimSprite = SuperAnim.SuperAnimSpriteMgr.GetInstance().GetSpriteById(aCurSpriteId[0]);
			var aSpriteFullPath = aSuperAnimSprite.mStringId;
			if (aSpriteFullPath.substr(aSpriteFullPath.length - theOriginSpriteName.length) == theOriginSpriteName) {
				anOriginSpriteId = aCurSpriteId[0];
				break;
			}
		}
		if (anOriginSpriteId != SuperAnim.InvalidSuperAnimSpriteId) {
			var anIter = this.mReplacedSpriteMap[anOriginSpriteId];
			if (anIter) {
				// unload the replaced sprite
				SuperAnim.SuperAnimSpriteMgr.GetInstance().UnloadSuperSprite(anIter);
				delete this.mReplacedSpriteMap[anOriginSpriteId];
			}
		}
	},
	
	// for time event
	registerTimeEvent: function(theLabel, theTimeFactor, theEventId){
		if (this.HasSection(theLabel) == false) {
			cc.Assert(false, "Label not existed.");
			return;
		}
		
		theTimeFactor = SuperAnim.Clamp(theTimeFactor, 0.0, 1.0);
		var aTimeEventInfo = new SuperAnim.SuperAnimNode.TimeEventInfo();
		{
			aTimeEventInfo.mLabelName = theLabel;
			aTimeEventInfo.mTimeFactor = theTimeFactor;
			aTimeEventInfo.mEventId = theEventId;
		};
		if(!this.mLabelNameToTimeEventInfoArrayMap[theLabel]){
			this.mLabelNameToTimeEventInfoArrayMap[theLabel] = new Array();
		}
		var aTimeEventInfoArray = this.mLabelNameToTimeEventInfoArrayMap[theLabel];
		aTimeEventInfoArray.push(aTimeEventInfo);
	},
	removeTimeEvent: function(theLabel, theEventId){
		if (this.HasSection(theLabel) == false) {
			cc.Assert(false, "Label not existed.");
			return;
		}
		var anIter = this.mLabelNameToTimeEventInfoArrayMap[theLabel];
		if (anIter) {
			var aTimeEventInfoArray = anIter;
			for (var i=0; i<aTimeEventInfoArray.length; i++) {
				if (aTimeEventInfoArray[i].mEventId == theEventId) {
					aTimeEventInfoArray.splice(i, 1);
					break;
				}
			}
		}
		
		// also remove in the current time event info array
		for (var i=0; i<this.mCurTimeEventInfoArray.length; i++) {
			if (this.mCurTimeEventInfoArray[i].mLabelName == theLabel &&	this.mCurTimeEventInfoArray[i].mEventId == theEventId) {
				this.mCurTimeEventInfoArray.splice(i, 1);
				break;
			}
		}
	},
	// support sprite sheet
	tryLoadSpriteSheet: function(){
		if (SuperAnim.hasFile(this.mSpriteSheetFileFullPath)) {
			cc.SpriteFrameCache.sharedSpriteFrameCache().addSpriteFramesWithFile(this.mSpriteSheetFileFullPath);
			var aTexturePath = this.mSpriteSheetFileFullPath.substring(0, this.mSpriteSheetFileFullPath.lastIndexOf('.') + 1) + 'png';
			this.mSpriteSheet = cc.TextureCache.sharedTextureCache().addImage(aTexturePath);
			this.mUseSpriteSheet = true;
		}
	},
	tryUnloadSpirteSheet: function(){
		if (SuperAnim.hasFile(this.mSpriteSheetFileFullPath)) {
			cc.SpriteFrameCache.sharedSpriteFrameCache().removeSpriteFramesFromFile(this.mSpriteSheetFileFullPath);
		}
	},
});


SuperAnim.SuperAnimNode.TimeEventInfo = cc.Class.extend({
	mLabelName: '',
	mTimeFactor: 0.0,
	mEventId: 0,
	ctor: function(){
	},
});

SuperAnim.SuperAnimNode.MAX_VERTEX_CNT = 4096;
SuperAnim.SuperAnimNode.sVertexBuffer = new Array(SuperAnim.SuperAnimNode.MAX_VERTEX_CNT);
SuperAnim.SuperAnimNode.sTexCoorBuffer = new Array(SuperAnim.SuperAnimNode.MAX_VERTEX_CNT);
SuperAnim.SuperAnimNode.sColorBuffer = new Array(SuperAnim.SuperAnimNode.MAX_VERTEX_CNT);
SuperAnim.SuperAnimNode.sAnimObjDrawnInfo = new SuperAnim.SuperAnimObjDrawInfo();

SuperAnim.SuperAnimNode.create = function(theAbsAnimFile, theId, theListener){
	var aSuperAnimNode = new SuperAnim.SuperAnimNode();
	if (!aSuperAnimNode)
	{
		return null;
	}
	if (aSuperAnimNode.init(theAbsAnimFile, theId, theListener) == false)
	{
		return null;
	}
	return aSuperAnimNode;
};



SuperAnim.SuperAnimSprite = cc.Class.extend({
	mID: SuperAnim.InvalidSuperAnimSpriteId,
	mTexture: null,
	mQuad: null,
	mStringId: '',

	ctor: function(theTexture, theTextureRect){
		this.mID = ++SuperAnim.SuperAnimSprite.sCount;
		this.mQuad = cc.V3F_C4B_T2F_QuadZero();
		
		this.SetTexture(theTexture, theTextureRect);
	},
	dtor: function(){
		if (mTexture)
		{
			mTexture = null;
		}
	},
	
	SetTexture: function(theTexture, theTextureRect){
		if (!theTextureRect) {
			var aRect = cc.RectZero;
			aRect.size = theTexture.getContentSize();
			this.SetTexture(theTexture, aRect);
		}else{
			if (!theTexture)
			{
				return;
			}
			
			if (this.mTexture)
			{
				this.mTexture = null;
			}
			
			this.mTexture = theTexture;
			
			// Set Texture coordinates
			var theTexturePixelRect = cc.RECT_POINTS_TO_PIXELS(theTextureRect);
			var aTextureWidth = this.mTexture.width;//ORG: this.mTexture.getPixelsWide();
			var aTextureHeight = this.mTexture.height;//ORG: this.mTexture.getPixelsHigh();
			
			var aLeft = theTexturePixelRect.origin.x / aTextureWidth;
			var aRight = (theTexturePixelRect.origin.x + theTexturePixelRect.size.width) / aTextureWidth;
			var aTop = theTexturePixelRect.origin.y / aTextureHeight;
			var aBottom = (theTexturePixelRect.origin.y + theTexturePixelRect.size.height) / aTextureHeight;
			
			this.mQuad.bl.texCoords.u = aLeft;
			this.mQuad.bl.texCoords.v = aBottom;
			this.mQuad.br.texCoords.u = aRight;
			this.mQuad.br.texCoords.v = aBottom;
			this.mQuad.tl.texCoords.u = aLeft;
			this.mQuad.tl.texCoords.v = aTop;
			this.mQuad.tr.texCoords.u = aRight;
			this.mQuad.tr.texCoords.v = aTop;
			
			var x1 = theTexturePixelRect.size.width * -0.5;
			var y1 = theTexturePixelRect.size.height * -0.5;
			var x2 = theTexturePixelRect.size.width * 0.5;
			var y2 = theTexturePixelRect.size.height * 0.5;
			
			this.mQuad.bl.vertices = cc.vertex3(x1, y1, 0);
			this.mQuad.br.vertices = cc.vertex3(x2, y1, 0);
			this.mQuad.tl.vertices = cc.vertex3(x1, y2, 0);
			this.mQuad.tr.vertices = cc.vertex3(x2, y2, 0);
			
			// Set color
			var aDefaultColor = new cc.Color4B(255, 255, 255, 255);
			this.mQuad.bl.colors = aDefaultColor;
			this.mQuad.br.colors = aDefaultColor;
			this.mQuad.tl.colors = aDefaultColor;
			this.mQuad.tr.colors = aDefaultColor;
		}
	},
});

SuperAnim.SuperAnimSprite.sCount = 0;



SuperAnim.SuperAnimSpriteMgr = cc.Class.extend({
	mSuperAnimSpriteMap: null,
	mSuperAnimSpriteIterator: SuperAnim.InvalidSuperAnimSpriteId,

	ctor: function(){
		this.mSuperAnimSpriteMap = {};
	},
	dtor: function(){
		this.mSuperAnimSpriteMap = {};
	},

	LoadSuperAnimSprite: function(theSpriteName){
		// already load the sprite ?
		for (var anItr in this.mSuperAnimSpriteMap)
		{
			if (this.mSuperAnimSpriteMap[anItr].mStringId == theSpriteName) {
				return anItr;
			}
		}
		
		var anImageFileName;
		var anImageFile;
		var aLastSlashIndex = Math.max(theSpriteName.lastIndexOf('/'), theSpriteName.lastIndexOf('\\'));
		if (-1 < aLastSlashIndex) {
			anImageFileName = theSpriteName.substr(aLastSlashIndex + 1);
		} else {
			anImageFileName = theSpriteName;
		}
		
		var hasFileExt = -1 < anImageFileName.indexOf('.');
		if (!hasFileExt) {
			// PNG by default if not specified format
			anImageFile = theSpriteName + '.png';
		} else {
			anImageFile = theSpriteName;
		}
		// load the physical sprite
		var aTextureRect = cc.RectZero;
		var aTexture = this.getTexture(anImageFile, aTextureRect);
		if (!aTexture) {
			return SuperAnim.InvalidSuperAnimSpriteId;
		}
		
		// create new super animation sprite
		var aSuperAnimSprite = new SuperAnim.SuperAnimSprite(aTexture, aTextureRect);
		// use the sprite name as the key
		aSuperAnimSprite.mStringId = theSpriteName;
		var anId = aSuperAnimSprite.mID;
		this.mSuperAnimSpriteMap[anId] = aSuperAnimSprite;
		
		return anId;
	},
	UnloadSuperSprite: function(theSpriteId){
		var anItr = this.mSuperAnimSpriteMap[theSpriteId];
		if (anItr)
		{
			delete this.mSuperAnimSpriteMap[theSpriteId];
		}
	},
	GetSpriteById: function(theSpriteId){
		var anItr = this.mSuperAnimSpriteMap[theSpriteId];
		if (anItr)
		{
			return anItr;
		}
		
		return null;
	},
	BeginIterateSpriteId: function(){
		this.mSuperAnimSpriteIterator = SuperAnim.InvalidSuperAnimSpriteId;
		
		for (var i in this.mSuperAnimSpriteMap) {
			this.mSuperAnimSpriteIterator = i;
			break;
		}
	},
	IterateSpriteId: function(theCurSpriteId){
		if (this.mSuperAnimSpriteIterator == SuperAnim.InvalidSuperAnimSpriteId) {
			theCurSpriteId[0] = SuperAnim.InvalidSuperAnimSpriteId;
			return false;
		}
		
		theCurSpriteId[0] = this.mSuperAnimSpriteIterator;
		
		var bBreak = false;
		for (var i in this.mSuperAnimSpriteMap) {
			if (bBreak) {
				this.mSuperAnimSpriteIterator = i;
				break;
			}
			
			if (i == this.mSuperAnimSpriteIterator) {
				this.mSuperAnimSpriteIterator = SuperAnim.InvalidSuperAnimSpriteId;
				bBreak = true;
			}
		}
		
		return true;
	},
	
	getTexture: function(theImageFullPath, theTextureRect){
		// try to load from sprite sheet
		var anImageFileName;
		var aLastSlashIndex = Math.max(theImageFullPath.lastIndexOf('/'), theImageFullPath.lastIndexOf('\\'));
		if (-1 < aLastSlashIndex) {
			anImageFileName = theImageFullPath.substr(aLastSlashIndex + 1);
		} else {
			anImageFileName = theImageFullPath;
		}
		var aSpriteFrame = cc.SpriteFrameCache.getInstance().getSpriteFrame(anImageFileName);
		if (aSpriteFrame) {
			theTextureRect = aSpriteFrame.getRect();
			return aSpriteFrame.getTexture();
		}
		
		var aTexture = cc.TextureCache.getInstance().addImage(theImageFullPath);
		theTextureRect.origin = cc.PointZero;
		theTextureRect.size = cc.SizeMake(aTexture.width, aTexture.height);//ORG: aTexture.getContentSize();
		return aTexture;
	},
});

SuperAnim.SuperAnimSpriteMgr.sInstance = null;

SuperAnim.SuperAnimSpriteMgr.GetInstance = function(){
	if (!SuperAnim.SuperAnimSpriteMgr.sInstance)
	{
		SuperAnim.SuperAnimSpriteMgr.sInstance = new SuperAnim.SuperAnimSpriteMgr();
	}
	
	return SuperAnim.SuperAnimSpriteMgr.sInstance;
};

SuperAnim.SuperAnimSpriteMgr.DestroyInstance = function(){
	if (SuperAnim.SuperAnimSpriteMgr.sInstance)
	{
		SuperAnim.SuperAnimSpriteMgr.sInstance = null;
	}
};



SuperAnim.LoadSuperAnimSprite = function(theSpriteName){
	return SuperAnim.SuperAnimSpriteMgr.GetInstance().LoadSuperAnimSprite(theSpriteName);
};

SuperAnim.UnloadSuperSprite = function(theSpriteId){
	SuperAnim.SuperAnimSpriteMgr.GetInstance().UnloadSuperSprite(theSpriteId);
};



SuperAnim.hasFile = function(theFileFullPath){
	var has = false;
	/*###
	var shouldPopupNoitify = cc.FileUtils.sharedFileUtils().isPopupNotify();
	cc.FileUtils.sharedFileUtils().setPopupNotify(false);
	var aSize;
	var aDataBuffer = cc.FileUtils.sharedFileUtils().getFileData(theFileFullPath, 'rb', aSize);
	if (aDataBuffer) {
	    cc.SAFE_DELETE_ARRAY(aDataBuffer);
	    has = true;
	}
	cc.FileUtils.sharedFileUtils().setPopupNotify(shouldPopupNoitify);
	*/
	return has;
};

SuperAnim.LoadAnimFileExt = function(theAbsAnimFile){
	// try to load the sprite sheet file
	var aSpriteSheetFileFullPath = theAbsAnimFile.substring(0, theAbsAnimFile.lastIndexOf('.') + 1) + "plist";
	if (SuperAnim.hasFile(aSpriteSheetFileFullPath)) {
		cc.SpriteFrameCache.sharedSpriteFrameCache().addSpriteFramesWithFile(aSpriteSheetFileFullPath);
	}
	return SuperAnim.LoadAnimFile(theAbsAnimFile);
};

SuperAnim.UnloadAnimFileExt = function(theAbsAnimFile){
	// try to unload the sprite sheet file
	var aSpriteSheetFileFullPath = theAbsAnimFile.substring(0, theAbsAnimFile.lastIndexOf('.') + 1) + "plist";
	if (SuperAnim.hasFile(aSpriteSheetFileFullPath)) {
		cc.SpriteFrameCache.sharedSpriteFrameCache().removeSpriteFramesFromFile(aSpriteSheetFileFullPath);
	}
	return SuperAnim.UnloadAnimFile(theAbsAnimFile);
};

SuperAnim.Clamp = function(val, min, max) {
	return Math.max(min, Math.min(max, val))
};









