/*
 * CubeMovement.cs
 * 
 * This class controls the movement of character cubes 
 * in the game world
 *  
 * Created for 2011 Global Game Jam
 */

using UnityEngine;
using System.Collections;

public class CubeMovement : MonoBehaviour 
{
	// Inspector Variables
	public int charNumber;									// what type of character the object is
	public GameObject[] generations = new GameObject[7];	// array of prefabs for the characters in the world	
    public const float physicsImpactThreshold = 100.0f;		// threshold for how hard you have to throw the characters against the wall in Gen 5
    public Transform ps2Explosion;							// particle effect for nice explosion
	
	// Private variables
	int startDir = 0;	// the starting direction used in gen 2
	
	float accumulation;
	float speed = 50;						// the speed for which the item moves
	float spinRotation = 0.0f;
	float elapsedTimeSinceChange = 0.0f;
	const float SwitchInterval = .4f;
	
	Vector3 velocity;	// velocity for the object
	Vector3 moveRight;	// vector for moving the object right
	Vector3 moveDown;	// vector for moving the object down
	Vector3 moveLeft;	// vector for moving the object left
	Vector3 moveUp;		// vector for moving the object up
	Vector3 targetPosition;		// 
	Vector3[] pikaBlinkLocs = new Vector3[6];	// array that holds the locations that eRat can blink too
	
	Plane plane;	// used to get the mouse location so the object can avoid it
	
	// Use this for initialization
	void Start () 
	{	
		plane = new Plane(Vector3.back, 0);	// initialize the plane for mouse tracking
		
		//
		targetPosition = new Vector3(Random.value * 230 - 115, Random.value * 170 - 84);
		
		// set the directional vectors
		moveRight = new Vector3(speed, 0, 0);
		moveDown = new Vector3(0, -speed, 0);
		moveLeft = new Vector3(-speed, 0, 0);
		moveUp = new Vector3(0, speed, 0);
		
		// load the blink locations for Electir Rat
        pikaBlinkLocs[0] = new Vector3(-60.0f, 40.0f, 20.0f);
        pikaBlinkLocs[1] = new Vector3(0.0f, 40.0f, 20.0f);
        pikaBlinkLocs[2] = new Vector3(60.0f, 40.0f, 20.0f);
        pikaBlinkLocs[3] = new Vector3(-60.0f, -40.0f, 20.0f);
        pikaBlinkLocs[4] = new Vector3(0.0f, -40.0f, 20.0f);
        pikaBlinkLocs[5] = new Vector3(60.0f, -40.0f, 20.0f);	

        switch (Global.generation)
        {
            case 1:
                velocity = moveRight;
                break;
            case 2:
                switch (startDir)
                {
                    case 0:
                        velocity = moveRight;
                        startDir++;
                        break;
                    case 1:
                        velocity = moveUp;
                        startDir++;
                        break;
                    case 3:
                        velocity = moveDown;
                        startDir++;
                        break;
                    case 4:
                        velocity = moveLeft;
                        startDir++;
                        break;
                }

                if (startDir > 4)
                    startDir = 0;
                break;
            case 3:
                Vector2 newDir = Random.insideUnitCircle * speed;
                rigidbody.AddForce(newDir, ForceMode.Impulse);
                break;
        }
	}
	
	// Update is called once per frame
	void Update () {
		
		transform.localScale = new Vector3(Global.characterScale, Global.characterScale, Global.characterScale);
		
        switch (Global.generation)
        {
            case 1:
                Gen1Movement();
                rigidbody.velocity = velocity;
                break;
            case 2:
                Gen2Movement();
                rigidbody.velocity = velocity;
                break;
            case 3:
                Gen3Movement();
                break;
			
        }
		
		if(Global.isTransitioning){
			
			// For the quick player that is making transitions happen too fast
			for(int i = 0; i < (Global.generation - 2); i++){
				generations[i].renderer.enabled = false;
			}
			
			if(Global.generation <= 6) {
				Color existing = generations[Global.generation - 2].renderer.material.color;
				float FadeOutAlpha = Mathf.Lerp(1, 0, Global.transitionLerpT);
				Color FadeOutColor = new Color(existing.r, existing.g, existing.b, FadeOutAlpha);
				
				generations[Global.generation - 2].renderer.material.color = FadeOutColor;
				
				if(FadeOutAlpha == 0)
					generations[Global.generation - 2].renderer.enabled = false;
				
				if(!generations[Global.generation - 1].renderer.enabled)
					generations[Global.generation - 1].renderer.enabled = true;
				
				Color NextGen = generations[Global.generation - 1].renderer.material.color;
				float FadeInAlpha = Mathf.Lerp(0, 1, Global.transitionLerpT);
				Color FadeInColor = new Color(NextGen.r, NextGen.g, NextGen.b, FadeInAlpha);
				
				generations[Global.generation - 1].renderer.material.color = FadeInColor;
			}

		}
	}

    void Gen1Movement()
    {
    }

    void Gen2Movement()
    {
        elapsedTimeSinceChange += Time.deltaTime;

        if (elapsedTimeSinceChange > 1.0f)
        {
            if (velocity == moveRight)
            {
                velocity = moveDown;
            }
            else if (velocity == moveDown)
            {
                velocity = moveLeft;
            }
            else if (velocity == moveLeft)
            {
                velocity = moveUp;
            }
            else if (velocity == moveUp)
            {
                velocity = moveRight;
            }

            elapsedTimeSinceChange = 0.0f;
        }
    }

    void Gen3Movement()
    {
        elapsedTimeSinceChange += Time.deltaTime;

        if (elapsedTimeSinceChange > 1.0f)
        {
            Vector2 newDir = Random.insideUnitCircle * speed;
            rigidbody.AddForce(newDir, ForceMode.Impulse);

            elapsedTimeSinceChange = 0.0f;
        }
    }
	
	void OnCollisionEnter(Collision collision){
		
        if (collision.gameObject.name == "Right Wall")
        {		
			if(Global.generation < 3)
            	velocity = moveDown;
            else if (Global.generation == 5 && Mathf.Abs(transform.rigidbody.velocity.x) > physicsImpactThreshold)
            {
                //print(Mathf.Abs(transform.rigidbody.velocity.x));
                Global.numCharsLeft[charNumber - 1]--;

                Camera.main.transform.GetComponent<HUD>().fireSoundEffect(this.GetComponent<SoundEffect>().soundEffects[Global.generation - 1]);

                if (ps2Explosion)
                    Instantiate(ps2Explosion, transform.position, transform.rotation);

                if (Global.numCharsLeft[charNumber - 1] == 0)
                {
                    Global.generation++;
                    Global.startTransition(charNumber - 1);
                }
                Destroy(gameObject);

            }
        }
        else if (collision.gameObject.name == "Bottom Wall")
        {
			if(Global.generation < 3)
            	velocity = moveLeft;
            if (Global.generation == 5 && Mathf.Abs(transform.rigidbody.velocity.y) > physicsImpactThreshold)
            {
                //print(Mathf.Abs(transform.rigidbody.velocity.y));
                //print(Mathf.Abs(transform.rigidbody.velocity.y) > physicsImpactThreshold);
                //print(physicsImpactThreshold);
                Global.numCharsLeft[charNumber - 1]--;

                Camera.main.transform.GetComponent<HUD>().fireSoundEffect(this.GetComponent<SoundEffect>().soundEffects[Global.generation - 1]);
                
                if (ps2Explosion)
                    Instantiate(ps2Explosion, transform.position, transform.rotation);

                if (Global.numCharsLeft[charNumber - 1] == 0)
                {
                    Global.generation++;
                    Global.startTransition(charNumber - 1);
                }
                Destroy(gameObject);
            }
        }
        else if (collision.gameObject.name == "Left Wall")
        {
            
			if(Global.generation < 3)
            	velocity = moveUp;

            if (Global.generation == 5 && Mathf.Abs(transform.rigidbody.velocity.x) > physicsImpactThreshold)
            {
                //print(Mathf.Abs(transform.rigidbody.velocity.x));
                Global.numCharsLeft[charNumber - 1]--;

                Camera.main.transform.GetComponent<HUD>().fireSoundEffect(this.GetComponent<SoundEffect>().soundEffects[Global.generation - 1]);

                if (ps2Explosion)
                    Instantiate(ps2Explosion, transform.position, transform.rotation);

                if (Global.numCharsLeft[charNumber - 1] == 0)
                {
                    Global.generation++;
                    Global.startTransition(charNumber - 1);
                }
                Destroy(gameObject);

            }
        }
        else if (collision.gameObject.name == "Top Wall")
        {
			if(Global.generation < 3)
            	velocity = moveRight;

            if (Global.generation == 5 && Mathf.Abs(transform.rigidbody.velocity.y) > physicsImpactThreshold)
            {
                //print(Mathf.Abs(transform.rigidbody.velocity.y));
                //print(Mathf.Abs(transform.rigidbody.velocity.y) > physicsImpactThreshold);
                //print(physicsImpactThreshold);
                Global.numCharsLeft[charNumber - 1]--;

                Camera.main.transform.GetComponent<HUD>().fireSoundEffect(this.GetComponent<SoundEffect>().soundEffects[Global.generation - 1]);

                if (ps2Explosion)
                    Instantiate(ps2Explosion, transform.position, transform.rotation);

                if (Global.numCharsLeft[charNumber - 1] == 0)
                {
                    Global.generation++;
                    Global.startTransition(charNumber - 1);
                }
                Destroy(gameObject);

            }
        }
        else if(collision.gameObject.name != "FrontPlane" && collision.gameObject.name != "RearPlane" && collision.gameObject.name.Substring(0,13) == "Gen1Character")
			velocity = -velocity;
		
	}
	
	void OnTriggerEnter(Collider collider){
		
		if(collider.name == "Thwomp"){
			Global.numCharsLeft[charNumber - 1]--;

            Camera.main.transform.GetComponent<HUD>().fireSoundEffect(this.GetComponent<SoundEffect>().soundEffects[Global.generation - 1]);
			
			if (Global.numCharsLeft[charNumber - 1] == 0)
            {
                Global.generation++;

                if (Global.generation == 3)
                {
                    GameObject thwomp = GameObject.Find("Thwomp");

                    thwomp.GetComponent<PlayerControls>().killThwomp();
                }

                Global.startTransition(charNumber - 1);
            }
			Destroy(gameObject);
		}
	}

    public void MouseOverKill()
    {
        Global.numCharsLeft[charNumber - 1]--;        

        Camera.main.transform.GetComponent<HUD>().fireSoundEffect(this.GetComponent<SoundEffect>().soundEffects[Global.generation - 1]);

        if (Global.numCharsLeft[charNumber - 1] == 0)
        {
            Global.generation++;
            Global.startTransition(charNumber - 1);
        }
        Destroy(gameObject);
    }

    public void MouseClickKill()
    {
        Global.numCharsLeft[charNumber - 1]--;

        Camera.main.transform.GetComponent<HUD>().fireSoundEffect(this.GetComponent<SoundEffect>().soundEffects[Global.generation - 1]);

        if (Global.numCharsLeft[charNumber - 1] == 0)
        {
            Global.generation++;
            Global.startTransition(charNumber - 1);
        }
        Destroy(gameObject);

    }

    public void firePS2Particle()
    {
        if (ps2Explosion)
            Instantiate(ps2Explosion, transform.position, transform.rotation);
    }
	
	void FixedUpdate()
	{
        if (Global.generation == 6)
        {
            string cubeType = name.Substring(10, 1);

            if (cubeType == "3")
            {
                elapsedTimeSinceChange += Time.deltaTime;

                if (elapsedTimeSinceChange > 1.0f)
                {
					int iWhatToDo = Random.Range(0,5);
					
					switch(iWhatToDo) {
					case 0:
						rigidbody.velocity = moveRight;
						break;
					case 1:
						rigidbody.velocity = moveLeft;
						break;
					case 3:
						rigidbody.velocity = moveUp;
						break;
					case 4:
						rigidbody.velocity = moveDown;
						break;
					}

                    elapsedTimeSinceChange = 0.0f;
                }
            } else if (cubeType == "4") {
				elapsedTimeSinceChange += Time.deltaTime;
				
				if(elapsedTimeSinceChange > 1.5f) {
					int iLocIndex = Random.Range(0,5);
					rigidbody.transform.position = pikaBlinkLocs[iLocIndex];
		            Vector2 newDir = Random.insideUnitCircle * speed;
		            rigidbody.AddForce(newDir, ForceMode.Impulse);
					elapsedTimeSinceChange = 0.0f;
				}
			} else if (cubeType == "1" || cubeType == "5")
            {
                rigidbody.useGravity = true;
				elapsedTimeSinceChange += Time.deltaTime;
				
				if(elapsedTimeSinceChange > 1.5f) {
					int iWhatToDo = Random.Range(0,4);
					
					switch(iWhatToDo) {
					case 0:
						rigidbody.AddForce(moveRight*1.5f, ForceMode.Acceleration);
						break;
					case 1:
						rigidbody.AddForce(moveLeft*1.5f, ForceMode.Acceleration);
						break;
					case 3:
						rigidbody.AddForce(moveUp*speed, ForceMode.Acceleration);
						break;
					}
					
					elapsedTimeSinceChange = 0.0f;
				}
            }
            else if (cubeType == "2" || cubeType == "6")
            {
                rigidbody.useGravity = true;
				elapsedTimeSinceChange += Time.deltaTime;
				
				if(elapsedTimeSinceChange > 1.5f) {
					int iWhatToDo = Random.Range(0,4);
					
					switch(iWhatToDo) {
					case 0:
						rigidbody.AddForce(moveRight*2.5f, ForceMode.Acceleration);
						break;
					case 1:
						rigidbody.AddForce(moveLeft*2.5f, ForceMode.Acceleration);
						break;
					case 3:
						rigidbody.AddForce(moveUp*speed*1.5f, ForceMode.Acceleration);
						break;
					}
					
					elapsedTimeSinceChange = 0.0f;
				}
            }
            else if (cubeType == "5")
            {
                accumulation += Time.deltaTime;
                if (accumulation >= SwitchInterval)
                {
                    accumulation -= SwitchInterval;
                    targetPosition = new Vector3(Random.value * 230 - 115, Random.value * 170 - 84);
                }

                var target = targetPosition - transform.position;
                var mag = target.magnitude;
                target /= mag;
                target *= Mathf.Min(mag * 2, 100);

                rigidbody.AddForce(target, ForceMode.Force);
            }
        }
		else if(Global.generation == 5){
			
			accumulation += Time.deltaTime;
			if (accumulation >= SwitchInterval)
			{
				accumulation -= SwitchInterval;
				targetPosition = new Vector3(Random.value * 230 - 115, Random.value * 170 - 84);
			}
	
			var target = targetPosition - transform.position;
			var mag = target.magnitude;
			target /= mag;
			target *= Mathf.Min(mag * 2, 100);
	
	
			rigidbody.AddForce(target, ForceMode.Force);
		}
		else if(Global.generation == 4){
			
			accumulation += Time.deltaTime;
			if (accumulation >= SwitchInterval)
			{
				accumulation -= SwitchInterval;
				targetPosition = new Vector3(Random.value * 230 - 115, Random.value * 170 - 84);
			}
	
			var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
			float dist;
			plane.Raycast(ray, out dist);
	
			var target1 = targetPosition - transform.position;
			var target2 = transform.position - (ray.origin + ray.direction * dist);
	
			var mag1 = target1.magnitude;
			target1 /= mag1;
			target1 *= Mathf.Min(mag1 * 2, 50);
	
	
			var mag2 = target2.magnitude;
			target2 /= mag2;
			mag2 = 400 - mag2 * 5;
			if (mag2 < 0)
				mag2 = 0.01f;
			target2 *= Mathf.Min(mag2, 400);
	
	
			var target = target1 + target2;
			var mag = target.magnitude;
			target /= mag;
			target *= Mathf.Min(mag * 2, 200);
			rigidbody.AddForce(target, ForceMode.Force);
		}

	}
}
