using UnityEngine;
using System.Collections.Generic;

public class PlayerMovement : MonoBehaviour {
    
    // Attributes.
	private Rigidbody body;
	private BoxCollider boxFloor;
	private GameObject floor;
    private AnimationPlayer animator;
    private Player p;
    private EnemyLoader enemyLoader;

    public bool falling;
	public bool transition;
    public bool attacking;
    public bool teleporting;
	public Vector3 obj;
    public int auxExit = 0;
    private float speed;
    private float drag;

	// Scripts
	private CameraMovement cameraScript;


	// Model data
	//private List<Nexus> nexus;
    //private string currentPlane;


	void Awake() {
        this.attacking = false;
		this.transition = false;
        this.falling = false;
        this.teleporting = false;
		this.speed = 2.0f;
		this.drag = 10.0f;
	}

    private void getAttacking() {
        this.attacking = this.animator.getAttacking();
    }

	void Start() {
        this.p = (Player)(GameObject.Find("PlayerBody").GetComponent<Player>());   
        this.body = (Rigidbody)GameObject.Find("PlayerBody").GetComponent<Rigidbody>();
        this.cameraScript = GameObject.FindGameObjectWithTag("MainCamera").GetComponent<CameraMovement>();


        if (LoadSavePlayerStats.tmp != null) {
            
            if (LoadSavePlayerStats.isLoaded) {
                this.floor = GameObject.Find(p.playerStats.floor);
                this.boxFloor = (BoxCollider)this.floor.GetComponent<BoxCollider>();
            } else {
                string s = ChangingPlane.getPlane(Application.loadedLevelName, p.playerStats.auxExit);
                this.floor = GameObject.Find(s);
                this.boxFloor = (BoxCollider)this.floor.GetComponent<BoxCollider>();                
            }

        } else {
           this.floor = GameObject.Find(ChangingPlane.getInitPlane());
        }

        this.cameraScript.setPlane(this.floor.name);
        this.enemyLoader = (EnemyLoader)(GameObject.Find("EnemyLoader").GetComponent<EnemyLoader>());
        this.updatePS(this.transform.position);
    }

    // 
    //public void push(Vector3 dir) { Debug.Log("PUSH!");  this.body.AddForce(dir*1000.0f); }

	void FixedUpdate() {
        // If the player is in the middle of a transition (changing of room), the movement
        // is automatic and the user cannot do anything.
		if (this.transition) {
           
			this.transform.position = Vector3.MoveTowards (this.transform.position,
			                                               obj,
			                                               Time.deltaTime * 5.0f);

            if (this.transform.position == this.obj) this.transition = false;
			return;
		}

        // If the player is falling, not input is allowed. Is just as going to a point... but
        // vertically.
        if (this.falling) {
            this.transform.position = Vector3.MoveTowards(this.transform.position,
                obj,                                               
                Time.deltaTime * 15.0f);
            return;
        
        }

        // Upload the attack flag.
        this.getAttacking();

        // Player cannot move if is attacking.
        if (!attacking) {

            if (Input.GetKeyDown(KeyCode.Space)) {

            // Action Input
                this.action();    
                
            }

            // Movement Input
            float moveHorizontal = Input.GetAxis("Horizontal");
            float moveVertical = Input.GetAxis("Vertical");
            Vector3 movement = new Vector3(moveHorizontal, 0.0f, moveVertical);

            // If the is some movement...
            if (movement != Vector3.zero) {
            //if (this.body != null && movement != Vector3.zero) {
                this.animator.beginWalking();

                this.body.AddForce(movement * this.speed, ForceMode.Impulse);

                float rotationX = transform.localEulerAngles.x;
                float rotationZ = transform.localEulerAngles.z;
                this.body.transform.localEulerAngles = 
                    new Vector3(rotationX, 
                                getRotationFromMovement(moveHorizontal, moveVertical), 
                                rotationZ);

            } else if (this.animator.isWalking) {
                this.animator.beginIdle();
            }
            return;
        } 
	}
	
    // Returns a rotation angle depending of the input.
    private float getRotationFromMovement(float moveHorizontal, float moveVertical) {
        // Up-Right
        float rot = 0;

        if (moveHorizontal > 0 && moveVertical > 0)
        {
            rot = 45;
        }

        // Up-Left
        else if (moveHorizontal < 0 && moveVertical > 0)
        {
            rot = 315;
        }

        // Down-Left 
        else if (moveHorizontal < 0 && moveVertical < 0)
        {
            rot = 225;
        }

        // Down-Right
        else if (moveHorizontal > 0 && moveVertical < 0)
        {
            rot = 135;
        }

        // Right
        else if (moveHorizontal > 0 && moveVertical == 0)
        {
            rot = 90;
        }

        // Left
        else if (moveHorizontal < 0 && moveVertical == 0)
        {
            rot = 270;
        }

        // Up
        else if (moveHorizontal == 0 && moveVertical > 0)
        {
            rot = 0;
        }

        // Down
        else if (moveHorizontal == 0 && moveVertical < 0)
        {
            rot = 180;
        }

        // Model is looking to a negative axis, little fix.
        // Modular calc also.
        return (rot+90) % 360;
    
    }

    // Update player stats for the load/save methods.
    private void updatePS(Vector3 pos) {
        this.p.playerStats.floor = floor.name;
        this.p.playerStats.scene = Application.loadedLevelName;
        this.p.playerStats.posx = pos.x;
        this.p.playerStats.posy = pos.y+1;
        this.p.playerStats.posz = pos.z;
    }
    
    // Check all the Actionable objects and action the one that has not be
    // actioned and must to.
    private void action() {
        foreach (GameObject c in GameObject.FindGameObjectsWithTag("Actionable")) {
            if (c.name.Contains("Palanca")) {
                bool hover = c.GetComponent<AnimationPalanco>().hover;
                if (hover) c.GetComponent<AnimationPalanco>().setAction();
            } else if (c.name.Contains("Chest")) {
                bool hover = c.GetComponent<AnimationChest>().hover;
                if (hover) c.GetComponent<AnimationChest>().setAction();
            } else if (c.name.Contains("Portal")) {
                bool hover = c.GetComponent<Portal>().hover;
                if (hover) c.GetComponent<Portal>().setAction();
            } else if (c.name.Contains("ChangeWorld")) {
                bool hover = c.GetComponent<ChangeScene>().hover;
                if (hover) c.GetComponent<ChangeScene>().setAction();
            }
        }
    }

    // Changing room is like falling room... horizontally.
    public void changingRoom(string plane, Vector3 obj) {
        Debug.Log("Go to plane: " + plane + " Destiny2: " + obj);
        this.transition = true;
       
        // Refresh time!
        this.cameraScript.setPlane(plane);
        this.floor = GameObject.Find(plane);
 
        // Establishing the new position and updating the stats
        this.obj = new Vector3(obj.x, this.transform.position.y, obj.z);
        this.updatePS(this.obj);

        // Loading the enemies from the new plane.
        this.enemyLoader.Load(plane);
        
    }

    // Falling room is like changing room... vertically.
    public void fallingRoom(float dist, string plane) {
        // Refresh time!
        this.cameraScript.setPlane(plane);
        this.floor = GameObject.Find(plane);
        this.falling = true;

        // Establishing the new position and updating the stats
        this.obj = new Vector3(this.transform.position.x, this.transform.position.y + dist, this.transform.position.z);
        this.updatePS(this.obj);

        // Loading the enemies from the new plane.
        this.enemyLoader.Load(plane);

    }

    // Setter.
    public void setAnimationPlayer (AnimationPlayer anim) {
        this.animator = anim;    
    }

    // Make the teleport from a portal to other one.
    public void teleport(string plane, Vector3 pos) {
        //Debug.Log("Teleporting position: " + pos);
        
        // Refresh time!
        this.cameraScript.setPlane(plane);
        this.floor = GameObject.Find(plane);
        
        // Stop the body movement.
        this.body.velocity = Vector3.zero;
        this.body.angularVelocity = Vector3.zero;
        
        // Establishing the new position and updating the stats.
        this.transform.position = new Vector3(pos.x, pos.y +1.0f, pos.z);
        this.updatePS(this.transform.position);

        // Loading the enemies from the plane.
        this.enemyLoader.Load(plane);
    }
}
