using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;

namespace EduNetworkBuilder
{
    public class ActionCollection
    {
        Network StartingState = null;
        public List<NetworkAction> NetActions = new List<NetworkAction>();
        NetworkAction CurrentNetAction = null;

        public Network GetNet { get { return StartingState; } }
        public int GetActionCount {  get { if (CurrentNetAction == null) return 0; return CurrentNetAction.Actions.Count; } }

        public void RegisterNet(Network starting)
        {
            StartingState = Network.DeepClone(starting);
            CurrentNetAction = new NetworkAction(starting);
        }

        public void Add(ActionClass What)
        {
            if(CurrentNetAction == null)
            {
                Network start = NB.GetNetwork();
                if (start == null) return;//Do nothing
                CurrentNetAction = new NetworkAction(start);
            }
            CurrentNetAction.Add(What);
        }

        public bool RunAction(int WhichIndex)
        {
            if (CurrentNetAction == null) return false;
            if (WhichIndex < CurrentNetAction.Actions.Count)
            {
                CurrentNetAction.Actions[WhichIndex].DoAction();
                return true;
            }
            return false;
        }

        /// <summary>
        /// Take the current actionlist and save it to the stored actionlists.
        /// We use this when we have successfully solved a network and want to store
        /// this solution process
        /// </summary>
        public void PushActionToList()
        {
            //remove an old one if it exists
            if (CurrentNetAction != null)
            {
                NetworkAction NA = GetActionlistFromName(CurrentNetAction.NetworkName);
                if (NA != null) NetActions.Remove(NA);
            }
            //Add this one
            NetActions.Add(CurrentNetAction);
        }

        /// <summary>
        /// Return true if we already have a solved state for this network
        /// </summary>
        /// <param name="starting"></param>
        /// <returns></returns>
        public bool AlreadyHaveNet(Network starting)
        {
            //Look up the network to see if we have it already
            return AlreadyHaveNet(NameFromNet(starting));
        }
        public bool AlreadyHaveNet(string starting)
        {
            NetworkAction NA = GetActionlistFromName(starting);
            if (NA != null) return true; //one exists
            return false;
        }
        public NetworkAction GetActionlistFromNet(Network starting)
        {
            return GetActionlistFromName(NameFromNet(starting));
        }
        public NetworkAction GetActionlistFromName(string starting)
        {
            foreach (NetworkAction NA in NetActions)
            {
                if (NA.NetworkName == starting) return NA;
            }
            return null;
        }
        private string NameFromNet(Network theNet)
        {
            return theNet.PuzzleName;
        }
    }

    public class NetworkAction
    {
        public string NetworkName = "";
        public List<ActionClass> Actions = new List<ActionClass>();
        public NetworkAction(string Name)
        {
            NetworkName = Name;
            Actions.Clear();
        }
        public NetworkAction(Network Start)
        {
            if (Start == null)
                Start = NB.GetNetwork();
            if (Start != null)
                NetworkName = Start.PuzzleName;
            else
                NetworkName = "Empty";
            Actions.Clear();
        }
        public void Add(ActionClass What)
        {
            Actions.Add(What);
        }
    }

    public class ActionClass
    {
        public NBAction Action = NBAction.none;
        public int SourceID = -1; //used for basically everything
        public NB_IPAddress Destination; //used for pinging, arp, traceroute
        public HostNicID SourceNIC; //used for links
        public HostNicID DestNic; //Used for links
        public Point Location; //Used when making a new device or moving an old device
        public NetworkComponentType newItemType = NetworkComponentType.none; //Making new device
        public NetworkDevice ChangedDevice = null;

        public void DoAction()
        {
            Network myNet = NB.GetNetwork();
            NetworkDevice source = myNet.GetDeviceFromID(SourceID);
            NetworkComponent sourceC = myNet.GetComponentFromID(SourceID);

            switch (Action)
            {
                case NBAction.changedevice:
                    break;
                case NBAction.changelocation:
                    if (source != null)
                    {
                        source.ChangeLocation(Location);
                        source.UnHide(); //In case it was hidden
                    }
                    break;
                case NBAction.deletecomponent:
                    //Deleting the item is easy, but we also need to delete any links to that item
                    List<HostNicID> NicIDs = new List<HostNicID>();
                    if (source != null)
                    {
                        if (myNet.ItemIsCritical(source.hostname))
                            return; //we cannot delete this
                        NicIDs = source.GetHostNicIDs();
                        foreach (HostNicID nicID in NicIDs)
                        {
                            myNet.RemoveLinksToNic(nicID);
                        }
                        myNet.RemoveComponent(source);
                    } else if(sourceC != null && sourceC is NetworkLink)
                    {
                        if (myNet.ItemIsCritical(sourceC.hostname))
                            return; //We cannot remove this link
                        NetworkLink SourceL = (NetworkLink)sourceC;
                        SourceL.Destroy(); //Mark both ends as being deleted
                        myNet.RemoveComponent(SourceL); //Get rid of this link
                    }
                    break;
                case NBAction.newdevice:
                    break;
                case NBAction.dhcp:
                    break;
                case NBAction.arp:
                    source.AskArpFromHere(Destination);
                    break;
                case NBAction.cleararp:
                    source.ClearArps();
                    break;
                case NBAction.ping:                    
                    source.PingFromHere(Destination) ;
                    break;
                case NBAction.traceroute:
                    source.TracerouteFromHere(Destination);
                    break;
            }
        }
    }
}
