﻿using UnityEngine;
using System.Collections;

public class TransformManager : MonoBehaviour
{
    public GameObject transformPrefab;

    /// <summary>
    /// All vertex game objects will be scaled by this amount.
    /// </summary>
    public float scale = 15.0f;

    public Camera transformCamera;

    /// <summary>
    /// Collection of GameObjects that represent the verticies to
    /// be transformed.
    /// </summary>
    public GameObject[] vertices = new GameObject[4];

    public bool viewTransform = false;
    public bool plusProjectionTransform = false;
    public bool plusViewportTransform = true;

    protected GameObject[] viewVertexTransforms;
    protected GameObject[] projectionVertexTransforms;
    protected GameObject[] viewportVertexTransforms;

    protected Vector2 lastScreenSize;

    void Awake()
    {
        viewVertexTransforms = new GameObject[vertices.Length];
        projectionVertexTransforms = new GameObject[vertices.Length];
        viewportVertexTransforms = new GameObject[vertices.Length];

	    for(int i = 0; i < vertices.Length; i++)
        {
            GameObject thisVertex = vertices[i];

            viewVertexTransforms[i] = instantiateVertexTransform(thisVertex, delegate(Vector4 vertex, out bool clipped)
            {
                clipped = false;
                Vector4 result = Transformer.performViewTransform(vertex, transformCamera);
                return result;
            });

            projectionVertexTransforms[i] = instantiateVertexTransform(thisVertex, delegate(Vector4 vertex, out bool clipped)
            {
                Vector4 result = Transformer.performViewTransform(vertex, transformCamera);
                result = Transformer.performProjectionTransform(result, transformCamera);
                clipped = Transformer.clip(result);
                return result;
            });

            viewportVertexTransforms[i] = instantiateVertexTransform(thisVertex, delegate(Vector4 vertex, out bool clipped)
            {
                Vector4 result = Transformer.performViewTransform(vertex, transformCamera);
                result = Transformer.performProjectionTransform(result, transformCamera);
                clipped = Transformer.clip(result);
                Vector2 result2D = Transformer.performViewportTransform(result);
                result = new Vector4(result2D.x, result2D.y, 0, 1);
                return result;
            });
        }
	}

    /// <summary>
    /// Instanciates and returns a GameObject based on the transformPrefab.
    /// </summary>
    GameObject instantiateVertexTransform(GameObject vertex, VertexTransform.TransformDelegate del)
    {
        GameObject newObj = Instantiate(transformPrefab) as GameObject;
        if (newObj)
        {
            VertexTransform vertexTransform = newObj.GetComponent<VertexTransform>();
            vertexTransform.sourceVertex = vertex.transform;
            vertexTransform.transformDel = del;
        }
        return newObj;
    }

    public void Update()
    {
        for (int i = 0; i < vertices.Length; i++)
        {
            Vector3 scaleVector = new Vector3(scale, scale, scale);

            viewVertexTransforms[i].transform.localScale = scaleVector;
            projectionVertexTransforms[i].transform.localScale = scaleVector;
            viewportVertexTransforms[i].transform.localScale = scaleVector;

            viewVertexTransforms[i].renderer.enabled = viewTransform;
            projectionVertexTransforms[i].renderer.enabled = plusProjectionTransform;
            viewportVertexTransforms[i].renderer.enabled = plusViewportTransform;
        }
    }

    public void LateUpdate()
    {
        lastScreenSize.x = Screen.width;
        lastScreenSize.y = Screen.height;
    }

    public void OnDrawGizmos()
    {
        if (plusProjectionTransform)
        {
            Gizmos.color = Color.yellow;
            Gizmos.DrawWireCube(Vector3.zero, new Vector3(2f, 2f, 2f));
        }
        if (plusViewportTransform)
        {
            Gizmos.color = Color.yellow;
            Gizmos.DrawWireCube(new Vector3(lastScreenSize.x / 2f, lastScreenSize.y / 2f, 0f), new Vector3(lastScreenSize.x, lastScreenSize.y, 0f));
        }
    }
}
