/*
 * Copyright [yyyy] [name of copyright owner]
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


// Anonymous function start
//
(function( window, undefined )
{

// reference
var Config			= window.h5glib.Config;
var Debug			= window.h5glib.Debug;
var Command			= window.h5glib.Command;
var Task			= window.h5glib.Task;
var SoundTask		= window.h5glib.SoundTask;
var ReadyTask		= window.h5glib.ReadyTask;
var ImageAnimator	= window.h5glib.ImageAnimator;
var Message			= window.h5glib.Message;
var MessageHandler	= window.h5glib.MessageHandler;
var MessageManager	= window.h5glib.MessageManager;
var SceneStatus		= window.h5glib.SceneStatus;
var Scene			= window.h5glib.Scene;

/**
 * Res
 */
var Res =
{
	String :
	{
		HTML_USAGE	: "<p>" +
					  "右側のキャラクターを操作します。<br>" +
					  "[←][→]: 移動 [Z]: 攻撃 [ESC]: メニューに戻る<br>" +
					  "</p>"
	},
	Color :
	{
		BACKGROUND	: "rgb(0, 0, 0)"
	},
	Font :
	{
		LARGE		: "bold 18px 'ＭＳ Ｐゴシック'",
		SMALL		: "bold 14px 'ＭＳ Ｐゴシック'"
	}
};

/**
 * MessageType
 */
var MessageType =
{
	NONE			: 0,
	RET_PREV_SCENE	: 1
};

/**
 * StageTask
 */
var StageTask = function( scene )
{
	this.command	= scene.command;	// input
};
StageTask.prototype = new Task();

(function( pt )
{
	/**
	 * 
	 */
	pt.update = function( scene )
	{
		var upd			= false;
		var msgManager	= scene.msgManager;

		// command
		if ( this.command.tbl.escape )
		{
			var message	= new Message( MessageType.RET_PREV_SCENE );
			msgManager.postBreakMessage( message );
		}
		return upd;
	};
	/**
	 * 
	 */
	pt.draw = function( scene )
	{
		var canvas		= scene.canvas;
		var context		= scene.context;
		var resource	= scene.data.resource;

		context.save();

		var image = resource.image.back.data;
		context.drawImage(
			image,
			0,				// sx
			0,				// sy
			image.width,	// sw
			image.height,	// sh
			( canvas.width  - image.width  ) / 2,	// dx
			( canvas.height - image.height ) / 2,	// dy
			image.width,	// dw
			image.height	// dh
		);

		context.restore();
	};
})( StageTask.prototype );

/**
 * ActorListTask
 */
var ActorListTask = function( scene )
{
	this.command	= scene.command;
	this.actorL		= null;
	this.actorR		= null;
	this.actors		= [];
};
ActorListTask.prototype = new Task();

(function( pt )
{
	/**
	 * 
	 */
	pt.setData = function( scene )
	{
		this.child	= null;

		// crreate actor

		this.actorL	= new ActorTask();
		this.actorR	= new ActorTask();
		this.actorL.init( scene, new AICommand(), ActorType.LEFT,  this.actorR );
		this.actorR.init( scene, scene.command,   ActorType.RIGHT, this.actorL );

		// create list
		this.child = this.actorL;
		this.actorL.append( this.actorR );

		this.actors.push( this.actorL );
		this.actors.push( this.actorR );
	};

	/**
	 * 
	 */
	pt.update = function( scene )
	{
		var upd = this.updateChildren( scene );

		if ( this.actorL.status == ActorStatus.PUNCH )
		{
			this.actors.length = 0;
			this.actors.push( this.actorR );
			this.actors.push( this.actorL );
		}
		if ( this.actorR.status == ActorStatus.PUNCH )
		{
			this.actors.length = 0;
			this.actors.push( this.actorL );
			this.actors.push( this.actorR );
		}
		return upd;
	};
	/**
	 * 
	 */
	pt.draw = function( scene )
	{
		for ( var i = 0; i < this.actors.length; i++ )
		{
			this.actors[i].draw( scene );
		}
	};
})( ActorListTask.prototype );

/**
 * ActorStatus
 */
var ActorStatus =
{
	NEUTRAL	: 0,
	STEP	: 1,
	PUNCH	: 2,
	DAMAGE	: 3
};

/**
 * ActorType
 */
var ActorType =
{
	LEFT	: 0,
	RIGHT	: 1
};

/**
 * ActorTask
 */
var ActorTask = function( scene )
{
	this.statusObjs		= null;
	this.animator		= null;
	this.type			= ActorType.LEFT;
	this.enemy			= null;

	this.trans			= null;	// center position
	this.step			= 0;
};
ActorTask.prototype = new Task();

(function( pt )
{
	pt.STEP_VAL		= 30;
	pt.HIT_DIST		= 128;
	pt.HIT_RANGE	= 30;

	/**
	 * 
	 */
	pt.init = function( scene, command, type, enemy )
	{
		var arr =	// center position
		[
			{ x : 128, y : 224 },
			{ x : 384, y : 224 }
		];

		this.command	= command;
		this.type		= type;
		this.enemy		= enemy;
		this.trans		= arr[ this.type ];

		var image		= scene.data.resource.image;
		var animation	= scene.data.animation;
		this.statusObjs	=
		[
			{ update : this.updateNeutral,	animator : new ImageAnimator( image.actorNeutral.data,	animation.actorNeutral ) },
			{ update : this.updateAction,	animator : new ImageAnimator( image.actorStep.data,		animation.actorAction ) },
			{ update : this.updateAction,	animator : new ImageAnimator( image.actorPunch.data,	animation.actorAction ) },
			{ update : this.updateAction,	animator : new ImageAnimator( image.actorDamage.data,	animation.actorAction ) }
		];
		this.setStatus( ActorStatus.NEUTRAL );
	};
	/**
	 * 
	 */
	pt.setStatus = function( status )
	{
		this.status		= status;

		var sobj		= this.statusObjs[ this.status ];
		this.update		= sobj.update;
		this.animator	= sobj.animator;
	};
	/**
	 * 
	 */
	pt.updateNeutral = function( scene )
	{
		var upd		= false;
		var sound	= scene.soundTask;

		this.command.update();

		if ( this.command.tbl.right )
		{
			this.setStatus( ActorStatus.STEP );
			this.animator.start();
			this.step = this.STEP_VAL;
		}
		else if ( this.command.tbl.left )
		{
			this.setStatus( ActorStatus.STEP );
			this.animator.start();
			this.step = this.STEP_VAL * -1;
		}
		else if ( this.command.tbl.punch )
		{
			var dist = Math.abs( this.trans.x - this.enemy.trans.x );

			if ( this.HIT_DIST - this.HIT_RANGE < dist )
			{
				this.setStatus( ActorStatus.PUNCH );
				this.animator.start();
				// judge hitting
				if ( dist < this.HIT_DIST + this.HIT_RANGE && this.enemy.status == ActorStatus.NEUTRAL )
				{
					// sound
					sound.prepare("damage");
					// damage
					this.enemy.setStatus( ActorStatus.DAMAGE );
					this.enemy.animator.start();
					// effect
					var pm		= ( this.type == ActorType.RIGHT ) ? -1 : 1;
					var ex		= this.trans.x + ( this.animator.fw / 2 * pm );
					var ey		= this.trans.y;
					var task	= new EffectTask( scene, ex, ey );
					task.link( scene.actorListTask );
				}
			}
		}

		if ( this.status != ActorStatus.NEUTRAL )
		{
			return true;
		}

		// neutral animation
		if ( this.animator.isActive() )
		{
			upd = this.animator.proceed();
		}
		else
		{
			var r = Math.floor( Math.random() * 15 );
			if ( r == 1 )
			{
				this.animator.start();
				upd = true;
			}
		}
		return upd;
	};
	/**
	 * 
	 */
	pt.updateAction = function( scene )
	{
		var canvas		= scene.canvas;

		var upd = false;

		if ( this.animator.isActive() )
		{
			upd = this.animator.proceed();
			// move
			if ( this.step != 0 )
			{
				var x = this.trans.x + this.step;
				if ( ( this.animator.fw / 4 ) <= x && x <= canvas.width - ( this.animator.fw / 4 ) &&
					 Math.abs( x - this.enemy.trans.x ) >= ( this.animator.fw / 4 ) )
				{
					this.trans.x = x;
					upd = true;
				}

				this.step /= 2;
				if ( this.step <= this.STEP_VAL / 8 )
				{
					this.step = 0;
				}
			}
		}
		else
		{
			this.setStatus( ActorStatus.NEUTRAL );
			this.step = 0;
			upd = true;
		}
		return upd;
	};

	/**
	 * 
	 */
	pt.draw = function( scene )
	{
		var canvas		= scene.canvas;
		var context		= scene.context;

		context.save();

		// 画像を反転する。
		if ( this.type == ActorType.LEFT )
		{
			 context.setTransform( -1, 0, 0, 1, this.trans.x * 2, 0 );
		}
		context.drawImage(
			this.animator.image,
			this.animator.fx,							// sx
			this.animator.fy,							// sy
			this.animator.fw,							// sw
			this.animator.fh,							// sh
			this.trans.x - ( this.animator.fw / 2 ),	// dx
			this.trans.y - ( this.animator.fh / 2 ),	// dy
			this.animator.fw,							// dw
			this.animator.fh							// dh
		);

		context.restore();
	};
})( ActorTask.prototype );

/**
 * EffectTask
 */
var EffectTask = function( scene, cx, cy )
{
	this.animator	= new ImageAnimator( scene.data.resource.image.fire.data, scene.data.animation.fire );
	this.animator.start();
	this.trans	= { x : cx, y : cy };	// center position
};
EffectTask.prototype = new Task();

(function( pt )
{
	/**
	 * 
	 */
	pt.update = function( scene )
	{
		var upd = false;

		if ( this.animator.isActive() )
		{
			upd = this.animator.proceed();
		}
		else
		{
			this.unlink();
			upd = true;
		}
		return upd;
	};

	/**
	 * 
	 */
	pt.draw = function( scene )
	{
		var canvas		= scene.canvas;
		var context		= scene.context;

		context.save();

		context.drawImage(
			this.animator.image,
			this.animator.fx,							// sx
			this.animator.fy,							// sy
			this.animator.fw,							// sw
			this.animator.fh,							// sh
			this.trans.x - ( this.animator.fw / 2 ),	// dx
			this.trans.y - ( this.animator.fh / 2 ),	// dy
			this.animator.fw,							// dw
			this.animator.fh							// dh
		);

		context.restore();
	};
})( EffectTask.prototype );

/**
 * DebugTask
 */
var DebugTask = function( scene )
{
	this.command	= scene.command;	// input
	this.info		= null;
	this.lag		= 0;
};
DebugTask.prototype = new Task();

(function( pt )
{
	pt.LAG_VAL	= 10;

	/**
	 * 
	 */
	pt.update = function( scene )
	{
		var upd = false;
		// lag
		if ( this.lag )
		{
			this.lag--;
		}
		else
		{
			if ( this.command.tbl.debug )
			{
				this.info	= "x=" + scene.actorListTask.child.trans.x;
				this.lag	= this.LAG_VAL;
				upd = true;
			}
		}
		return upd;
	};

	/**
	 * 
	 */
	pt.draw = function( scene )
	{
		// output debug info
		if ( this.info )
		{
			Debug.print( this.info );
			this.info = null;
		}
	};
})( DebugTask.prototype );

/**
 * AICommand
 */
var AICommand = function()
{
	this.tbl.left	= 0;
	this.tbl.right	= 0;
	this.tbl.punch	= 0;
};
AICommand.prototype = new Command();

(function( pt )
{
	/**
	 * 
	 */
	pt.update = function()
	{
		this.clear();

		var r = Math.floor( Math.random() * 54 );
		if      ( 0 <= r && r <= 2 )	{ this.tbl.left		= 1; }
		else if ( 3 <= r && r <= 4 )	{ this.tbl.right	= 1; }
		else if ( 5 <= r && r <= 6 )	{ this.tbl.punch	= 1; }
	};
})( AICommand.prototype );

/**
 * InputCommand
 */
var InputCommand = function()
{
	this.tbl.left	= 0;
	this.tbl.right	= 0;
	this.tbl.punch	= 0;
	this.tbl.escape	= 0;
	this.tbl.debug	= 0;
};
InputCommand.prototype = new Command();

(function( pt )
{
	/**
	 * 
	 */
	pt.update = function() {};
	/**
	 * 
	 */
	pt.handleSysEvent = function( event )
	{
		var type = event.type.toLowerCase();
		if ( type.substring( 0, 3 ) == "key" )
		{
			var value = 0;
			if      ( type == "keydown" ) { value = 1; }
			else if ( type == "keyup"   ) { value = 0; }

			switch ( event.keyCode )
			{
				case 37: this.tbl.left	= value; break;	// ←
				case 39: this.tbl.right	= value; break;	// →
				case 90: this.tbl.punch	= value; break;	// Z
				case 27: this.tbl.escape= value; break;	// ESC
				case 81: this.tbl.debug	= value; break;	// Q
			}
		}
	};
})( InputCommand.prototype );

/**
 * GBoxScene
 */
var GBoxScene = function( app, name )
{
	this.app			= app;
	this.name			= name;
	this.data			= null;
	this.command		= new InputCommand();

	// create task
	this.readyTask		= new ReadyTask( this );
	this.stageTask		= new StageTask( this );
	this.actorListTask	= new ActorListTask( this );
	this.soundTask		= new SoundTask( this );
	this.debugTask		= new DebugTask( this );
	// create list
	this.stageTask.append( this.actorListTask );
	this.stageTask.append( this.soundTask );
	this.stageTask.append( this.debugTask );

	this.headTasks		=
	[
		this.readyTask,
		this.stageTask,
		this.readyTask
	];
	this.setStatus( SceneStatus.READY );

	// message handler
	this.msgManager		= new MessageManager();
	this.msgManager.addHandler( new MessageHandler( MessageType.RET_PREV_SCENE,	this, this.handleRetPrevScene ) );
};
GBoxScene.prototype = new Scene();

(function( pt )
{
	/**
	 * 
	 */
	pt.handleRetPrevScene = function( scene, message )
	{
		this.app.sceneManager.pop();
		var prevScene = this.app.sceneManager.current;
		prevScene.show();
	};
	/**
	 * 
	 */
	pt.setStatus = function( status )
	{
		this.status	= status;
		this.child	= this.headTasks[ this.status ];
	};

	/**
	 * 
	 */
	pt.init = function()
	{
		// window.onload のタイミング
	};
	/**
	 * 
	 */
	pt.show = function()
	{
		this.setUsage( Res.String.HTML_USAGE );

		this.command.clear();
		this.holdCanvas();
		this.drawChildren( this );
	};

	/**
	 * 
	 */
	pt.setData = function( data )
	{
		this.data		= data;
		// create actorList
		this.actorListTask.setData( this );
	};
	/**
	 * 
	 */
	pt.getData = function()
	{
		return this.data;
	};
	/**
	 * 
	 */
	pt.loadData = function( data )
	{
		try
		{
			// load resource
			this.app.loadResource( this.name, data.resource );
			// set data
			this.setData( data );
			// set status
			var self = this;
			window.setTimeout( function() { self.setStatus( SceneStatus.RUNNING ); self.show(); }, Config.loadInterval );
		}
		catch ( e )
		{
			this.app.kill();
			Debug.alertError( e );
		}
	};
})( GBoxScene.prototype );


// Expose
if ( !window.h5glib ) { window.h5glib = {}; }
window.h5glib.GBoxScene	= GBoxScene;

// Anonymous function end
//
})( window );
