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

[System.Serializable]
public class StepElementInfo
{
    public int BeginStep;
    public int EndStep;
    public Element Element;
    public bool OneTime;
};

[System.Serializable]
public class ElementInfo
{
    public int BeginStep;
    public int EndStep;
    public Element Element;
};

public class Story : MonoBehaviour
{
    public List<StepElementInfo> StepElements;
    private Dictionary<int, List<StepElementInfo>> m_StoryStepElements;
    private Dictionary<int, List<StepElementInfo>> m_StoryStepElementsEnd;
    private List<StepElementInfo> m_CurrentStepElements;
    private List<StepElementInfo> m_CurrentStepElementsEnd;

    public List<ElementInfo> Elements;
    private Dictionary<int, List<ElementInfo>> m_StoryElements;
    private Dictionary<int, List<ElementInfo>> m_StoryElementsEnd;
    private List<ElementInfo> m_CurrentElements;
    private List<ElementInfo> m_CurrentElementsEnd;

    private int m_MaxStep;

    #region Initialize
    protected void Awake()
    {
        // Step elements
        m_StoryStepElements = new Dictionary<int, List<StepElementInfo>>();
        m_StoryStepElementsEnd = new Dictionary<int, List<StepElementInfo>>();
        m_CurrentStepElements = new List<StepElementInfo>();
        m_CurrentStepElementsEnd = new List<StepElementInfo>();
        m_MaxStep = 0;

        if (StepElements.Count > 0)
        {
            foreach (StepElementInfo si in StepElements)
            {
                if (!m_StoryStepElements.ContainsKey(si.BeginStep))
                {
                    m_StoryStepElements.Add(si.BeginStep, new List<StepElementInfo>());
                }
                if (!m_StoryStepElementsEnd.ContainsKey(si.EndStep))
                {
                    m_StoryStepElementsEnd.Add(si.EndStep, new List<StepElementInfo>());
                }

                m_StoryStepElements[si.BeginStep].Add(si);
                m_StoryStepElementsEnd[si.EndStep].Add(si);

                if(si.EndStep > m_MaxStep) m_MaxStep = si.EndStep;

                si.Element.gameObject.SetActive(false);
            }
        }

        // Elements
        m_StoryElements = new Dictionary<int, List<ElementInfo>>();
        m_StoryElementsEnd = new Dictionary<int, List<ElementInfo>>();
        m_CurrentElements = new List<ElementInfo>();
        m_CurrentElementsEnd = new List<ElementInfo>();

        if (Elements.Count > 0)
        {
            foreach (ElementInfo si in Elements)
            {
                if (!m_StoryElements.ContainsKey(si.BeginStep))
                {
                    m_StoryElements.Add(si.BeginStep, new List<ElementInfo>());
                }
                if (!m_StoryElementsEnd.ContainsKey(si.EndStep))
                {
                    m_StoryElementsEnd.Add(si.EndStep, new List<ElementInfo>());
                }

                m_StoryElements[si.BeginStep].Add(si);
                m_StoryElementsEnd[si.EndStep].Add(si);

                si.Element.gameObject.SetActive(false);
            }
        }
    }

    public void InitializeProgress(int state)
    {
        // TODO : do it properly (if the state != 0, it won't work !)
        SetStep(state,true);
    }
    #endregion

    #region Update
    public void UpdateStory()
    {
        // Update current interactive elements
        for (int i = 0; i < m_CurrentStepElements.Count; ++i)
        {
            if (m_CurrentStepElements[i].Element.UpdateElement())
            {
                int step = m_CurrentStepElements[i].EndStep;
                DeleteStoryStepElement(m_CurrentStepElements[i]);
                SetStep(step,false);
                i--;
            }
        }

        if (m_CurrentElements.Count > 0)
        {
            foreach (ElementInfo e in m_CurrentElements)
            {
                e.Element.UpdateElement();
            }
        }
    }

    private void DeleteStoryStepElement(StepElementInfo si)
    {
        if (si.OneTime)
        {
            si.Element.gameObject.SetActive(false);
            m_CurrentStepElements.Remove(si);
            m_CurrentStepElementsEnd.Remove(si);
            //m_StoryStepElementsEnd[si.EndStep].Remove(si);
            //if (m_StoryStepElementsEnd[si.EndStep].Count == 0)
            //{
            //    m_StoryStepElementsEnd.Remove(si.EndStep);
            //}
        }
    }

    private void SetStep(int step, bool initialization)
    {
        Debug.Log("Set step : " + step);
        if (!initialization)
        {
            // Check if there is (at least) an other critical element with the same end step or previous end step
            for (int i = 0; i < step; ++i)
            {
                if (m_StoryStepElementsEnd.ContainsKey(i))
                {
                    Debug.Log("There are other elements with the same end step");
                    foreach (StepElementInfo sei in m_StoryStepElementsEnd[i])
                    {
                        // This element is critical, abort !
                        if (sei.OneTime || sei.Element.IsActive)
                            return;
                    }

                    Debug.Log("But these are only no critical elements not actived");
                }
            }
        }

        // Deactivate previous story step element
        for (int i = 0; i <= step; ++i)
        {
            if (m_StoryStepElementsEnd.ContainsKey(i))
            {
                foreach (StepElementInfo sei in m_StoryStepElementsEnd[i])
                {
                    sei.Element.gameObject.SetActive(false);
                }
            }
        }

        // Deactivate next story step element
        for (int i = step + 1; i < m_MaxStep; ++i)
        {
            if (m_StoryStepElements.ContainsKey(i))
            {
                foreach (StepElementInfo sei in m_StoryStepElements[i])
                {
                    sei.Element.gameObject.SetActive(false);
                }
            }
        }

        // Add new story step elements
        if (initialization)
        {
            for (int i = 0; i <= step; ++i)
            {
                if (m_StoryStepElements.ContainsKey(i))
                {
                    foreach (StepElementInfo sei in m_StoryStepElements[i])
                    {
                        if (sei.EndStep > step)
                        {
                            sei.Element.gameObject.SetActive(true);
                            m_CurrentStepElements.Add(sei);
                        }
                    }
                }
            }
        }
        else if (m_StoryStepElements.ContainsKey(step))
        {
            foreach (StepElementInfo sei in m_StoryStepElements[step])
            {
                sei.Element.gameObject.SetActive(true);
                m_CurrentStepElements.Add(sei);
            }
        }
        else // There is no other elements => check if the level is finished
        {
            bool end = true;
            for (int i = step+1; i <= m_MaxStep; ++i)
            {
                if (m_StoryStepElementsEnd.ContainsKey(i))
                {
                    Debug.Log("There are other elements with the same end step or later");
                    foreach (StepElementInfo sei in m_StoryStepElementsEnd[i])
                    {
                        if (sei.OneTime || sei.Element.IsActive)
                        {
                            Debug.Log("And at least, one is critical !");
                            end = false;
                        }
                    }
                }
            }

            if (end)
            {
                Debug.Log("No more event elements => Level end");
                GameManager.Instance.NextLevel();
            }
        }

        // Add normal elements
        if (initialization)
        {
            for (int i = 0; i <= step; ++i)
            {
                if (m_StoryElements.ContainsKey(i))
                {
                    foreach (ElementInfo ei in m_StoryElements[i])
                    {
                        if (ei.EndStep > step)
                        {
                            ei.Element.gameObject.SetActive(true);
                            m_CurrentElements.Add(ei);
                        }
                    }
                }
            }
        }
        else if (m_StoryElements.ContainsKey(step))
        {
            foreach (ElementInfo ei in m_StoryElements[step])
            {
                ei.Element.gameObject.SetActive(true);
                m_CurrentElements.Add(ei);
            }
        }

        // Deactivate normal elements
        if (m_StoryElementsEnd.ContainsKey(step))
        {
            foreach (ElementInfo ei in m_StoryElementsEnd[step])
            {
                ei.Element.gameObject.SetActive(false);
                m_CurrentElements.Remove(ei);
            }
        }
    }
    #endregion
};