using UnityEngine;
using System.Collections;
using System.Collections.Generic;

[RequireComponent(typeof(Rigidbody))]
[RequireComponent(typeof(WallController))]
public class TracerControllerV2 : TracerControllerBase {

    private struct Turn {
        public Vector3 turnStartPositionBack;
        public Vector3 turnStartPositionFront;
        public float distanceForTurn;
        public float rotation;
    }

    private Rigidbody snakeHead;

    private Queue<Turn> turns = new Queue<Turn>();

    void Awake() {
        InitComponents();

        snakeHead = (Rigidbody)Instantiate(snakeHeadPrefab,
            pointFront.position, pointFront.rotation);
        snakeHead.transform.parent = this.transform.parent;
        snakeHead.name = string.Format("{0}-SnakeHead", this.name);
        snakeHead.transform.SetAsFirstSibling();
    }

    void Start() {
        StartMoving();

        snakeHead.transform.position = pointFront.position;
        snakeHead.transform.rotation = pointFront.rotation;
        snakeHead.velocity = transform.forward * baseVelocity;
    }

    void Update() {
        CheckForTurn();
        if (turns.Count > 0) {
            HandleTurn();
        }
    }

    private void HandleTurn() {
        Turn currentTurn = turns.Peek();
        float distanceCovered = Vector3.Distance(
              currentTurn.turnStartPositionBack,
              pointBack.transform.position);

        rotateBody.LookAt(snakeHead.transform);

        if (distanceCovered >= currentTurn.distanceForTurn) {
            rotateBody.localRotation = Quaternion.identity;

            transform.Rotate(0F, currentTurn.rotation, 0F);
            transform.position = currentTurn.turnStartPositionFront;
            myRigidbody.velocity = transform.forward * baseVelocity;

            wallController.TracerTurned();

            turns.Dequeue();

            if (turns.Count == 0) {
                snakeHead.transform.position = pointFront.position;
            } else {
                rotateBody.LookAt(snakeHead.transform);
            }

        }
    }


    private void CheckForTurn() {
        float? testRotation = null;
        base.CheckForTurn(ref testRotation);

        if (testRotation != null) {
            Turn nextTurn = new Turn();
            nextTurn.rotation = testRotation.Value;
            nextTurn.turnStartPositionFront
              = snakeHead.transform.position;

            if (turns.Count == 0) {
                nextTurn.turnStartPositionBack = pointBack.transform.position;
            } else {
                Turn[] turnsArray = turns.ToArray();
                Turn previousTurn = turnsArray[turns.Count - 1];
                nextTurn.turnStartPositionBack
                  = previousTurn.turnStartPositionFront;
            }

            nextTurn.distanceForTurn = Vector3.Distance(
                nextTurn.turnStartPositionBack,
                nextTurn.turnStartPositionFront);

            turns.Enqueue(nextTurn);

            snakeHead.transform.Rotate(0F, nextTurn.rotation, 0F);
            snakeHead.velocity
              = snakeHead.transform.forward * baseVelocity;
        }
    }

}
