using UnityEngine;
using System.Collections.Generic;

public interface ITurnLoopActorList
{
    int ActorCount { get; }
    TurnActor GetNextActor();
    void AddActor(TurnActor actor);
    void RemoveActor(TurnActor actor);
    bool StartsNewTurn(TurnActor actor);
}

public class TurnLoopActorList : ITurnLoopActorList
{
    LinkedList<TurnActor> actorList = new LinkedList<TurnActor>();
    LinkedListNode<TurnActor> nextActorToGo = null;

    public int ActorCount
    {
        get { return actorList.Count; }
    }

    public TurnActor GetNextActor()
    {
        if (nextActorToGo == null)
            AdvanceActor();
        if (nextActorToGo == null)
            return null;

        TurnActor goer = nextActorToGo.Value;
        AdvanceActor();
        return goer;
    }

    public void AddActor(TurnActor actor)
    {
        if (nextActorToGo == null)
        {
            //Debug.Log("TurnList: Added " + actor.name + " in first slot");
            nextActorToGo = actorList.AddFirst(actor);            
        }
        else if(actor.TurnOrderPriority == -1) 
        {
            AddAsNextToGo(actor);          
        }
        else
        {
            AddInPriorityOrder(actor);
        }
    }

    private void AddAsNextToGo(TurnActor actor)
    {
        //Debug.Log("TurnList: Added " + actor.name + " as Next To Go, before " + nextActorToGo.Value + " and after " + ((nextActorToGo.Previous == null) ? "null" : nextActorToGo.Previous.Value.ToString()));
        nextActorToGo = actorList.AddBefore(nextActorToGo, actor);
    }

    private void AddInPriorityOrder(TurnActor actor)
    {
        LinkedListNode<TurnActor> check = actorList.First;

        while(true)
        {
            if (check.Value.TurnOrderPriority > actor.TurnOrderPriority)
            {
                LinkedListNode<TurnActor> inserted = actorList.AddBefore(check, actor);
                //Debug.Log("TurnList: Added actor " + actor.name + " [Priority " + actor.TurnOrderPriority + "] before " + check.Value.name + " Priority [" + check.Value.TurnOrderPriority + "]");
                if (nextActorToGo == check)
                    nextActorToGo = inserted;
                break;
            }

            if (check.Next == actorList.First || check.Next == null)  // circled whole loop
            {
                actorList.AddAfter(check, actor);
                //Debug.Log("TurnList: Added at the end, actor " + actor.name + " [Priority " + actor.TurnOrderPriority + "] after " + check.Value.name + " Priority [" + check.Value.TurnOrderPriority + "]");
                break;
            }

            check = check.Next;
        }

    }

    public void RemoveActor(TurnActor actor)
    {
        if (nextActorToGo != null && nextActorToGo.Value == actor)
            AdvanceActor();
        actorList.Remove(actor);
    }

    public bool StartsNewTurn(TurnActor actor)
    {
        if (actorList.First == null)
            return false;

        return (actorList.First.Value == actor);
    }

    private void AdvanceActor()
    {
        if (nextActorToGo == null)
            nextActorToGo = actorList.First;
        else
            nextActorToGo = nextActorToGo.Next ?? actorList.First;
    }
}
