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

namespace EduNetworkBuilder
{
    [Serializable]
    public class TraversalClass
    {
        [Serializable]
        protected struct TraversalRecord
        {
            public string host;
            public TraversalTechnology WhatUsed;
            public string AdditionalData;

            public TraversalRecord(string Host, TraversalTechnology what, string Data)
            {
                host = Host;
                WhatUsed = what;
                AdditionalData = Data;
            }
        }

        List<TraversalRecord> PathTaken = new List<TraversalRecord>();
        public int Count { get { return PathTaken.Count; } }

        public TraversalClass(){ }

        public TraversalClass(TraversalClass CloneFrom)
        {
            Clone(CloneFrom, this);
        }

        public TraversalClass Clone()
        {
            TraversalClass newClass = new TraversalClass(this);
            return newClass;
        }

        public static void Clone(TraversalClass source, TraversalClass dest)
        {
            dest.PathTaken.AddRange(source.PathTaken);
        }

        public void AddPath(string Host, TraversalTechnology WithWhat, string Data)
        {
            PathTaken.Add(new TraversalRecord(Host, WithWhat, Data));
        }
        public void AddPath(TraversalClass OtherTraversal)
        {
            PathTaken.AddRange(OtherTraversal.PathTaken);
        }
        /// <summary>
        /// This is just a debug function to print off the whole path as we find it.
        /// </summary>
        public void DumpPath()
        {
            foreach(TraversalRecord one in PathTaken)
            {
                Console.WriteLine(string.Format("{0:12} : {1:-12} {2:10}",one.host, one.WhatUsed.ToString(),one.AdditionalData));
            }
            Console.WriteLine(""); //blank line.
        }

        public string Destination()
        {
            //When we do a ping, only the return trip is registered.  source/dest are reversed
            if (PathTaken.Count >= 1) return PathTaken[0].host;
            return "";
        }

        public string Source()
        {
            //When we do a ping, only the return trip is registered.  source/dest are reversed
            if (PathTaken.Count >= 1) return PathTaken[PathTaken.Count -1].host;
            return "";
        }

        public string HostnameFromTechnology(TraversalTechnology What)
        {             
            //make a randomized copy of the list, and return the first item that has the technology
            List<TraversalRecord> tPathTaken= NB.Randomize<TraversalRecord>(PathTaken);
            if (What != TraversalTechnology.any)
            {
                foreach (TraversalRecord one in tPathTaken)
                {
                    if (one.WhatUsed == What) return one.host;
                }
            } else
            {
                Network theNet = NB.GetNetwork();
                foreach (TraversalRecord one in tPathTaken)
                {
                    NetworkDevice ND = theNet.GetDeviceFromName(one.host);
                    if(ND != null && (ND.ForwardsPackets() || ND.RoutesPackets()) )  //get the first hub/switch/router/firewall
                        return one.host;
                }
            }
            return "";
        }

        public string DataFromTechnologyAndHost(TraversalTechnology What, string hostname)
        {
            //make a randomized copy of the list, and return the first item that has the technology
            List<TraversalRecord> tPathTaken = NB.Randomize<TraversalRecord>(PathTaken);
            if (What != TraversalTechnology.any)
            {
                foreach (TraversalRecord one in tPathTaken)
                {
                    if (one.WhatUsed == What && hostname == one.host) return one.AdditionalData;
                }
            }
            else
            {
                //We do not have any AdditionalData for a type of "any"
                return "";
            }
            return "";
        }
    }
}
