package gustavo.mundo 
{
	
	
	import Box2D.Collision.*;
	import Box2D.Collision.Shapes.*;
	import Box2D.Collision.Shapes.b2PolygonDef;
	import Box2D.Collision.b2AABB;
	import Box2D.Collision.b2Bound;
	import Box2D.Common.*;
	import Box2D.Common.Math.*;
	import Box2D.Common.Math.b2Vec2;
	import Box2D.Dynamics.*;
	import Box2D.Dynamics.Contacts.*;
	import Box2D.Dynamics.Joints.*;
	import Box2D.Dynamics.b2Body;
	import Box2D.Dynamics.b2BodyDef;
	import Box2D.Dynamics.b2World;
	
	import General.Input;
	
	import caurina.transitions.Tweener;
	
	import classes.com.greensock.TweenLite;
	import classes.com.greensock.TweenMax;
	import classes.com.greensock.easing.Strong;
	
	import fl.motion.easing.Exponential;
	
	import flash.display.*;
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.*;
	import flash.events.Event;
	import flash.geom.*;
	import flash.utils.Timer;
	import flash.utils.setTimeout;
	
	import gustavo.Logo;
	import gustavo.SoundManager;
	import gustavo.Torneira;
	import gustavo.gota.Gota;
	import gustavo.gota.GotaInfo;
	
	import keigo.box2d.events.*;
	import keigo.box2d.utils.*;
	import keigo.box2d.utils.KGB2WorldManagerBeta;
	import keigo.math.*;
	
	import model.*;
	
	import view.pool.*;
	import view.pool.component.Water;
	import view.pool.component.Waving;
	
	
	public class Mundo extends Pool
	{
		
		
		
		private 						var mundo					:b2World;
		private 						var fps						:Number = 1.0 / 30.0;
		private 						var iteracao				:Number = 10;
		
		protected						var _waving					:view.pool.component.Waving;		
		public 	  						var m_water					:view.pool.component.Water;
		
		public 							var m_mouseJoint			:b2MouseJoint;
		
		static public 					var mouseXWorldPhys			:Number;
		static public 					var mouseYWorldPhys			:Number;
		static public 					var mouseXWorld				:Number;
		static public 					var mouseYWorld				:Number;
		
		public 							var m_input					:Input;
		public 							var m_sprite				:Sprite;
		public 							var m_world					:b2World;
		public 							var m_physScale				:Number = 30.0;
		
		private 						var mousePVec				:b2Vec2 = new b2Vec2();
		
		//public 							var m_timeStep				:Number = 1.0/30.0;
		public 							var m_timeStep				:Number = 1.0/20.0;
		
		
		private 						var timer					:Timer;
		private 						var dados					:Array;
		private 						var torneira				:Torneira;
		private 						var logo					:Logo;
		private 						var total					:int;
		
		private 						var index					:int	= 0;
		
		private 						var bodys					:Array;
		private 						var gotas					:Array;
		
		private 						var containerGotas			:Sprite;
		
		private 						var estaPigando				:Boolean = false;
		
		public function Mundo()
		{
			
		}
	
		public function init(_dados:Array,_torneira:Torneira,_logo:Logo):void
		{
		
			torneira	= 	 _torneira;
			logo		=    _logo;
			dados 		=	 _dados;
			total       =   dados.length-1;	
		
			startBox2D();
			criarParedes();
			criarObjetosGotaTorneira();
			
		}
		
		private function startBox2D():void
		{
		
			m_input 								= new Input(this);
			
			bodys									= new Array();
			gotas									= new Array();
			containerGotas							= new Sprite();
			addChild(containerGotas);
			
			var limite:b2AABB 						= new b2AABB();
			limite.lowerBound.Set(-100.0, -100.00)
			limite.upperBound.Set(100.0,100.0);
			
			var gravidade:b2Vec2 					= new b2Vec2(0.0,9.5);
			var bSleep:Boolean 						= true;
			
			mundo 									= new b2World(limite, gravidade, bSleep);
			
			addEventListener(Event.ENTER_FRAME, _enterFrame);
			
			
		}
		
		
		//================================================PAREDES========================================================//

		
				
		private function criarParedes():void
		{
			
			criaParedeStage();
			criaParedeLogo();
			//criaParedeTorneira();
			
		}
		
		private function criaParedeStage():void 
		{
			
			var paredeDef				:b2PolygonDef 	= new b2PolygonDef();
			var paredeBodyDef			:b2BodyDef 		= new b2BodyDef();
			var paredeBody				:b2Body;
			
			var altura  								= stage.stageHeight;
			var largura 								= stage.stageWidth;
			
			paredeDef.SetAsBox(100 / 30, (altura + 40) / 30 / 2);
			
			//Esquerda
			paredeBodyDef.position.Set(-100 / 30, altura / 30 / 2);
			
			paredeBody=mundo.CreateBody(paredeBodyDef);
			paredeBody.CreateShape(paredeDef);
			
			//Direita
			paredeBodyDef.position.Set((largura + 100) / 30, altura / 30 / 2);
			paredeBody=mundo.CreateBody(paredeBodyDef);
			paredeBody.CreateShape(paredeDef);
			//
			
			paredeDef.SetAsBox((largura + 40) / 30 / 2, 100 / 30);
			// Topo
			paredeBodyDef.position.Set(largura/30/2, -100/30);
			paredeBody=mundo.CreateBody(paredeBodyDef);
			paredeBody.CreateShape(paredeDef);
			
			// Bottom
			paredeBodyDef.position.Set(largura / 30 /2, (altura+80) / 30);
			paredeBody=mundo.CreateBody(paredeBodyDef);
			paredeBody.CreateShape(paredeDef);
			
			paredeBody.SetMassFromShapes();
		}
		
		
		
		private function criaParedeLogo():void 
		{
			
			var paredeDef				:b2PolygonDef 	= new b2PolygonDef();
			var paredeBodyDef			:b2BodyDef 		= new b2BodyDef();
			var paredeBody				:b2Body;
			
			paredeDef.SetAsBox(logo.width / 30, logo.height/30);
			paredeBodyDef.position.Set(logo.x/30, logo.y/30);
			
			paredeBody					=	mundo.CreateBody(paredeBodyDef);
			
			paredeBody.CreateShape(paredeDef);
			paredeBody.SetMassFromShapes();
			
		}
		
		
		
		
		private function criaParedeTorneira():void 
		{
			
			var paredeDef				:b2PolygonDef 	= new b2PolygonDef();
			var paredeBodyDef			:b2BodyDef 		= new b2BodyDef();
			var paredeBody				:b2Body;
		
			paredeDef.SetAsBox(torneira.width / 30, torneira.height/30);
			paredeBodyDef.position.Set(torneira.x/30, torneira.y/30);
			
			paredeBody					=	mundo.CreateBody(paredeBodyDef);
			
			paredeBody.CreateShape(paredeDef);
			paredeBody.SetMassFromShapes();
			
		}
		
		
		
		//========================================================================================================//
		
		
		
		
		
		
		
		//================================================== CRIA OBJETOS ============================================//
		
		
		
		
		
		private function criarObjetosGotaTorneira():void
		{
			
			timer  = new Timer(820,dados.length);
			timer.addEventListener(TimerEvent.TIMER,criaItemGotaTorneira);
			timer.addEventListener(TimerEvent.TIMER_COMPLETE,terminouPingar);
			timer.start();
			
			estaPigando = true;
		}
		
		private function terminouPingar(e:TimerEvent):void
		{
			timer.stop();
			timer.removeEventListener(TimerEvent.TIMER,criaItemGotaTorneira);
			timer = null;
			estaPigando = false;
		}

		private function criaItemGotaTorneira(e:TimerEvent):void
		{
			
			var tSprite			:	Gota  		 = new Gota();
			containerGotas.addChild(tSprite);
			
			tSprite.x 			= (torneira.x+106);
			tSprite.y 			= (torneira.y+190);
			
			tSprite.init(dados[index]);
			
			gotas.push(tSprite);
			
			tSprite.onCloseTorneira = function():void
			{	
				createObjectMundo(tSprite);	
			};
			
			index++;
		}
		
	
		private function criaItemEsquerda():void
		{
		
			
			if(estaPigando)
			{
				timer.stop();
				timer.removeEventListener(TimerEvent.TIMER,criaItemGotaTorneira);
				timer.removeEventListener(TimerEvent.TIMER_COMPLETE,terminouPingar);
				estaPigando = false;
			}
			
			var novaGota		:		Gota;
			
			
			for each(var gotaInfo:GotaInfo in dados)
			{
				
				
				novaGota = new Gota();
				
				containerGotas.addChild(novaGota);
				novaGota.init(gotaInfo,Gota.ESQUERDA);
				gotas.push(novaGota);
					
			}
			
			setTimeout(SoundManager.play,400,"vento")
			
			setTimeout(createObjectsMundo,1000);
				
		}
		
		
		private function createObjectsMundo():void
		{
			
			
			mundo.m_bodyList = null;

			
			for each(var gota:Gota in gotas)
			createObjectMundo(gota);
		
			setTimeout(addEventListener,100,Event.ENTER_FRAME, _enterFrame);		

			
		}
		
		
		
		
		
		private function createObjectMundo(tSprite:Gota):void
		{
			
			var bd				:	b2BodyDef;
			
			var sq				:	b2PolygonDef = new b2PolygonDef();
			
			sq.SetAsBox(tSprite.width /2 /30, tSprite.height / 2 / 30);
			
			sq.density 			= 105;
			sq.friction	 		= 0;
			sq.restitution 		= 0.2;
			
			bd 					= new b2BodyDef();
			bd.userData 		= tSprite;
			
			bd.position.Set(tSprite.x / 30, tSprite.y / 30);
			
			var sqb:b2Body 		= mundo.CreateBody(bd);
			
			(sqb.m_userData as Gota).isInCenter = true;
			
			sqb.CreateShape(sq);
			sqb.SetMassFromShapes();
			
			bodys.push(sqb);
			
			m_world 			= mundo;
			
		}
		
		
		
		//========================================================================================================//
		
		
		

		
		//====================================================RENDER======================================================================

		
		
				
		public function _enterFrame(e:Event):void
		{
			
			mundo.Step(fps, iteracao);
			
			for (var bb:b2Body = mundo.m_bodyList; bb; bb = bb.m_next)
			{
				
				if (bb.m_userData is Gota)
				{
					bb.m_userData.x = bb.GetPosition().x * 30;
					bb.m_userData.y = bb.GetPosition().y * 30;
					bb.m_userData.rotation = bb.GetAngle() * (180 / Math.PI);	
					bb.m_userData.testeAgua();
					
				}
				
				
			}

			
			
			//start drag
			UpdateMouseWorld();
			MouseDrag();
			Input.update();
			
		}
		
		

		
		//==========================================================================================================================

		
		//=============================================UPDATE============================================================
		
		
		
		public function updateSeta(_dados:Array):void
		{
			
			dados  =  _dados;
			
			
			removeEventListener(Event.ENTER_FRAME, _enterFrame);
			
			saiAgua();
			setTimeout(disposeContainerGota,1200);

			setTimeout(criaItemEsquerda,1210);
				
				
			index 	= 0;
			bodys	= [];
			gotas   = [];	

			
		}
		
		public function updateTorneira(_dados:Array):void
		{
			
			dados  =  _dados;
			
			if(estaPigando)
			{
				timer.stop();
				timer.removeEventListener(TimerEvent.TIMER,criaItemGotaTorneira);
				timer = null;
				estaPigando = false;
			}
			
			removeEventListener(Event.ENTER_FRAME, _enterFrame);
			
			saiAgua();
			setTimeout(disposeContainerGota,1200);
			
			setTimeout(function():void{
			
				criarObjetosGotaTorneira();
				addEventListener(Event.ENTER_FRAME, _enterFrame);

			},1210);
						
			index 	= 0;
			bodys	= [];
			gotas   = [];	
			
		}
		
		public function pauseMundo():void
		{
			removeEventListener(Event.ENTER_FRAME, _enterFrame);
		}
		
		public function resumeMundo():void
		{
			addEventListener(Event.ENTER_FRAME, _enterFrame);
		}
		
		
		private function saiAgua():void
		{
			
		
			for (var i:int=0; i<bodys.length; i++)
			{
				
				mundo.DestroyBody(bodys[i])
				
				TweenMax.to(gotas[i],1.2,{x:-100,rotation:0,y:Docol.ref.stage.stageHeight-(100),blurFilter:{blurX:50},delay:i/20,ease:Strong.easeInOut,onComplete:function()
				{
					disposeGotas(gotas[i]);
				}});
				
			}
			
			
			
		}
		
		
		private function disposeContainerGota():void
		{
			while(containerGotas.numChildren)
			{
				containerGotas.removeChildAt(0);
			}
		}
		
		
		private function disposeGotas(gota:Gota):void
		{
			TweenMax.killTweensOf(gota,false,{onComplete:true});
		}
		
		
		
		
		//==========================================================================================================================================//
		
		
		
		
		
		
		//==================================================================================================================================================
									     					//  MOVIMENTA ITENS  //
		//==================================================================================================================================================
		
		
		
		//======================
		// Update mouseWorld
		//======================
		
		public function UpdateMouseWorld():void
		{
			
			mouseXWorldPhys = (Input.mouseX)/m_physScale; 
			mouseYWorldPhys = (Input.mouseY)/m_physScale; 
			
			mouseXWorld 	= (Input.mouseX); 
			mouseYWorld 	= (Input.mouseY); 
			
		}
		
		//======================
		// Mouse Drag 
		//======================
		
		public function MouseDrag():void
		{
			
			// mouse press
			if (Input.mouseDown && !m_mouseJoint){
				
				var body:b2Body = GetBodyAtMouse();
				
				if (body)
				{
					
					var md:b2MouseJointDef = new b2MouseJointDef();
					md.body1 = m_world.GetGroundBody();
					md.body2 = body;
					md.target.Set(mouseXWorldPhys, mouseYWorldPhys);
					md.maxForce = 500.0 * body.GetMass();
					md.timeStep = m_timeStep;
					m_mouseJoint = m_world.CreateJoint(md) as b2MouseJoint;
					body.WakeUp();
					
					
				}
			}
			
			// mouse release
			if (!Input.mouseDown){
				if (m_mouseJoint)
				{
					m_world.DestroyJoint(m_mouseJoint);
					m_mouseJoint = null;
				}
			}
			
			// mouse move
			if (m_mouseJoint)
			{
				var p2:b2Vec2 = new b2Vec2(mouseXWorldPhys, mouseYWorldPhys);
				m_mouseJoint.SetTarget(p2);
			}
		}
		
		//======================
		// GetBodyAtMouse
		//======================
		
		public function GetBodyAtMouse(includeStatic:Boolean=false):b2Body{
			// Make a small box.
			mousePVec.Set(mouseXWorldPhys, mouseYWorldPhys);
			var aabb:b2AABB = new b2AABB();
			aabb.lowerBound.Set(mouseXWorldPhys - 0.001, mouseYWorldPhys - 0.001);
			aabb.upperBound.Set(mouseXWorldPhys + 0.001, mouseYWorldPhys + 0.001);
			
			// Query the world for overlapping shapes.
			var k_maxCount:int = 10;
			var shapes:Array = new Array();
			var count:int = m_world.Query(aabb, shapes, k_maxCount);
			var body:b2Body = null;
			for (var i:int = 0; i < count; ++i)
			{
				if (shapes[i].GetBody().IsStatic() == false || includeStatic)
				{
					var tShape:b2Shape = shapes[i] as b2Shape;
					var inside:Boolean = tShape.TestPoint(tShape.GetBody().GetXForm(), mousePVec);
					if (inside)
					{
						body = tShape.GetBody();
						break;
					}
				}
			}
			return body;
		}
		
		//======================
		// Draw Joint 
		//======================
		public function DrawJoint(joint:b2Joint):void
		{
			var b1:b2Body = joint.m_body1;
			var b2:b2Body = joint.m_body2;
			
			var x1:b2Vec2 = b1.m_linearVelocity;
			var x2:b2Vec2 = b2.m_linearVelocity;
			var p1:b2Vec2 = joint.GetAnchor1();
			var p2:b2Vec2 = joint.GetAnchor2();
			
			m_sprite.graphics.lineStyle(1,0x44aaff,1/1);
			
			switch (joint.m_type)
			{
				case b2Joint.e_distanceJoint:
				case b2Joint.e_mouseJoint:
					m_sprite.graphics.moveTo(p1.x * m_physScale, p1.y * m_physScale);
					m_sprite.graphics.lineTo(p2.x * m_physScale, p2.y * m_physScale);
					break;
				
				case b2Joint.e_pulleyJoint:
					var pulley:b2PulleyJoint = joint as b2PulleyJoint;
					var s1:b2Vec2 = pulley.m_groundAnchor1;
					var s2:b2Vec2 = pulley.m_groundAnchor2;
					m_sprite.graphics.moveTo(s1.x * m_physScale, s1.y * m_physScale);
					m_sprite.graphics.lineTo(p1.x * m_physScale, p1.y * m_physScale);
					m_sprite.graphics.moveTo(s2.x * m_physScale, s2.y * m_physScale);
					m_sprite.graphics.lineTo(p2.x * m_physScale, p2.y * m_physScale);
					break;
				
				default:
					if (b1 == m_world.m_groundBody){
						m_sprite.graphics.moveTo(p1.x * m_physScale, p1.y * m_physScale);
						m_sprite.graphics.lineTo(x2.x * m_physScale, x2.y * m_physScale);
					}
					else if (b2 == m_world.m_groundBody){
						m_sprite.graphics.moveTo(p1.x * m_physScale, p1.y * m_physScale);
						m_sprite.graphics.lineTo(x1.x * m_physScale, x1.y * m_physScale);
					}
					else{
						m_sprite.graphics.moveTo(x1.x * m_physScale, x1.y * m_physScale);
						m_sprite.graphics.lineTo(p1.x * m_physScale, p1.y * m_physScale);
						m_sprite.graphics.lineTo(x2.x * m_physScale, x2.y * m_physScale);
						m_sprite.graphics.lineTo(p2.x * m_physScale, p2.y * m_physScale);
					}
			}
		}
		

		
		//==================================================================================================================================================
	

		
	}//end class
}