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

public class WaveGenerator : MonoBehaviour {
    public GameObject topPrefab; // For speed and convenience.
    public Color simultaneousColor; // For speed and convenience.
    public Color topColor; // For speed and convenience.
    public Color bottomColor; // For speed and convenience.
    public UnityEngine.UI.Image topWaveLineImage; // For speed and convenience.
    public UnityEngine.UI.Image bottomWaveLineImage; // For speed and convenience.
    public GameObject bottomPrefab; // For speed and convenience.
    public GameObject simultaneousPrefab; // For speed and convenience.
    public GameObject waveBlockWrapper; // For speed and convenience.
    public Transform generatedBlockWrapper; // For speed and convenience.
    public RectTransform waveFormBackgroundRectTransform; // For speed and convenience.
    public RectTransform waveFormTopRectTransform; // For speed and convenience.
    public RectTransform waveFormBottomRectTransform; // For speed and convenience.

    private UnityEngine.UI.Image waveFormBackgroundImage; // For speed and convenience.
    private Transform waveWrapper; // For speed and convenience.
    private WaveBlock currentWaveBlock; // Manage currently this block.
    private bool currentInputActive; // To spawn just the current block.

    private class WaveBlock {
        private GameObject wrapper; // For convenience.
        private GameObject block; // Wave block.
        [HideInInspector]
        public Transform wrapperTransform; // For speed and convenience.
        private Transform blockTransform; // For speed and convenience.
        private RectTransform blockRectTransform; // For speed and convenience.
        private UnityEngine.UI.Image blockImage; // For speed and convenience.
        private RectTransform waveWrapperRectTransform; // For speed and convenience.
        private StaticConstants.WaveBlockType waveBlockType; // For speed and convenience.
        private RectTransform waveFormTopRectTransform; // For speed and convenience.
        private RectTransform waveFormBottomRectTransform; // For speed and convenience.

        public WaveBlock (ref GameObject prefab, ref Transform waveWrapper, ref GameObject waveBlockWrapper, ref float scaleToMovementSlowDown, ref RectTransform waveFormTopRectTransform, ref RectTransform waveFormBottomRectTransform, ref StaticConstants.WaveBlockType waveBlockType) {
            this.waveBlockType = waveBlockType;
            this.waveFormTopRectTransform = waveFormTopRectTransform;
            this.waveFormBottomRectTransform = waveFormBottomRectTransform;
            wrapper = Instantiate (waveBlockWrapper);
            wrapperTransform = wrapper.transform;
            waveWrapperRectTransform = wrapper.transform.GetComponent <RectTransform> ();
            wrapperTransform.SetParent (waveWrapper, true);
            waveWrapperRectTransform.sizeDelta = new Vector2 (0f, 0f);
            waveWrapperRectTransform.anchoredPosition = new Vector3 (0f, 0f, 0f);
            block = Instantiate (prefab);
            blockTransform = block.transform;
            blockTransform.SetParent (wrapperTransform, true);
            blockRectTransform = blockTransform.GetComponent <RectTransform> ();
            blockRectTransform.anchoredPosition = new Vector2 (0f, 0f);
            blockImage = blockTransform.GetComponent <UnityEngine.UI.Image> ();
            blockRectTransform.sizeDelta = new Vector2 (0f, 0f);
        }

        public void PlaceWaveBlock (ref float blockHeightDelta) {
            blockRectTransform.anchorMin = new Vector2 (.5f, .5f);
            blockRectTransform.anchorMax = new Vector2 (.5f, .5f);
            if (waveBlockType == StaticConstants.WaveBlockType.top) {
                blockRectTransform.pivot = new Vector2 (1f, 0f);
                blockRectTransform.sizeDelta = new Vector2 (0f, (waveFormTopRectTransform.transform.position.y - waveFormBottomRectTransform.transform.position.y) + blockHeightDelta);
            } else {
                if (waveBlockType == StaticConstants.WaveBlockType.bottom) {
                    blockRectTransform.pivot = new Vector2 (1f, 1f);
                    blockRectTransform.sizeDelta = new Vector2 (0f, (waveFormTopRectTransform.transform.position.y - waveFormBottomRectTransform.transform.position.y) + blockHeightDelta);
                } else {
                    blockRectTransform.pivot = new Vector2 (1f, .5f);
                    blockRectTransform.sizeDelta = new Vector2 (0f, blockHeightDelta * 2f + (waveFormTopRectTransform.transform.position.y - waveFormBottomRectTransform.transform.position.y) * 2f);
                }
            }
        }


        public void ColorWaveBlock (Color blockColor) {
            blockImage.color = blockColor;
        }

        private float xSize; // How large does the block grow.

        public void GrowWaveBlock (float growSpeed) {
            blockRectTransform.sizeDelta = new Vector2 (xSize, blockRectTransform.sizeDelta.y);
            xSize += growSpeed;
        }
    }

    public void Initialize () {
        waveWrapper = transform;
        topWaveLineImage.color = topColor;
        bottomWaveLineImage.color = bottomColor;
    }

    void Start () {
        waveFormBackgroundImage = waveFormBackgroundRectTransform.GetComponent <UnityEngine.UI.Image> ();
        waveFormBackgroundImage.color = DGA.control.waveFormTransparancyColor;
    }

    private void ManageBlockGeneration (ref GameObject prefab, ref float blockHeightDelta, StaticConstants.WaveBlockType waveBlockType) {
        if (currentInputActive) {
            if (previousWaveBlockType != StaticConstants.WaveBlockType.simultaneous && DGA.control.inputManager.simultaneousInputActive) {
                SetCurrentBlockForHistory ();
                StartANewBlock (ref prefab, ref blockHeightDelta, ref waveBlockType);
            } else
                if ((previousWaveBlockType == StaticConstants.WaveBlockType.simultaneous && DGA.control.inputManager.simultaneousInputActive) || (previousWaveBlockType == StaticConstants.WaveBlockType.top && DGA.control.inputManager.topInputActive) || (previousWaveBlockType == StaticConstants.WaveBlockType.bottom && DGA.control.inputManager.bottomInputActive))
                    currentWaveBlock.GrowWaveBlock (DGA.control.tempo * DGA.control.clampedDeltaTime * DGA.control.scaleToMovementSlowDown);
                else {
                    SetCurrentBlockForHistory ();
                    StartANewBlock (ref prefab, ref blockHeightDelta, ref waveBlockType);
                }
        } else
            StartANewBlock (ref prefab, ref blockHeightDelta, ref waveBlockType);
    }

    private void StartANewBlock (ref GameObject prefab, ref float blockHeightDelta, ref StaticConstants.WaveBlockType waveBlockType) {
        currentWaveBlock = new WaveBlock (ref prefab, ref waveWrapper, ref waveBlockWrapper, ref DGA.control.scaleToMovementSlowDown, ref waveFormTopRectTransform, ref waveFormBottomRectTransform, ref waveBlockType);
        currentWaveBlock.PlaceWaveBlock (ref blockHeightDelta);
        currentInputActive = true;
        if (DGA.control.inputManager.simultaneousInputActive) {
            previousWaveBlockType = StaticConstants.WaveBlockType.simultaneous;
            currentWaveBlock.ColorWaveBlock (simultaneousColor);
        } else {
            if (DGA.control.inputManager.topInputActive) {
                previousWaveBlockType = StaticConstants.WaveBlockType.top;
                currentWaveBlock.ColorWaveBlock (topColor);
            } else
                if (DGA.control.inputManager.bottomInputActive) {
                    previousWaveBlockType = StaticConstants.WaveBlockType.bottom;
                    currentWaveBlock.ColorWaveBlock (bottomColor);
                }
        }
    }

    private void SetCurrentBlockForHistory () {
        previousWaveBlockType = StaticConstants.WaveBlockType.none;
        if (currentWaveBlock != null && currentWaveBlock.wrapperTransform != null)
            currentWaveBlock.wrapperTransform.SetParent (generatedBlockWrapper, true);
    }

    [HideInInspector]
    public StaticConstants.WaveBlockType previousWaveBlockType; // To determine input state changes during hold.

    public WaveFormMover waveFormMover; // For speed and convenience.

    void Update () {
        if (DGA.control.inputManager.simultaneousInputActive)
            ManageBlockGeneration (ref simultaneousPrefab, ref waveFormMover.simultaneousHeightDelta, StaticConstants.WaveBlockType.simultaneous);
        else {
            if (DGA.control.inputManager.topInputActive)
                ManageBlockGeneration (ref topPrefab, ref waveFormMover.singleHeightDelta, StaticConstants.WaveBlockType.top);
            else {
                if (DGA.control.inputManager.bottomInputActive)
                    ManageBlockGeneration (ref bottomPrefab, ref waveFormMover.singleHeightDelta, StaticConstants.WaveBlockType.bottom);
                else {
                    currentInputActive = false;
                    SetCurrentBlockForHistory ();
                }
            }
        }
    }
}
