using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using System.IO;
using System.Xml;
using System.Xml.Serialization;

namespace EduNetworkBuilder
{
    [XmlInclude(typeof(NetworkLink))]
    [XmlInclude(typeof(NetworkDevice))]
    [Serializable]
    public class NetworkComponent
    {
        public bool IsDirty = true; //If something has changed and it needs to be re-drawn.  It starts as "true"
        public int UniqueIdentifier = NB.GetUniqueIdentifier();
        public string hostname = "";
        /// <summary>
        /// isInvisible is what happens when we have forgotton something exists.  We can have a forgotton switch, WAP, DHCP server
        /// etc.  Part of our training should be to find things. Network wires and devices can both be hidden.
        /// </summary>
        protected bool isInvisible = false; //Not used often.  Basically, to simulate a device (usually a switch) that we forgot about.


        public virtual void Print(Image BaseImage, CaptionType DrawTitle)
        {
        }

        public virtual bool Equals(NetworkComponent toCompare)
        {
            return false;
        }

        public virtual bool HasMac(string MAC)
        {
            return false;
        }

        public virtual void ProcessPacket(Packet tPacket)
        {

        }

        /// <summary>
        /// Done when something gets moved.
        /// </summary>
        public void UnHide()
        {
            isInvisible = false;
            IsDirty = true; //make sure it gets redrawn.
            if(this is NetworkDevice)
            {
                //we want to go through all links and unhide any links connected to this device
                Network myNet = NB.GetNetwork();
                foreach(NetworkLink nl in myNet.AllLinksConnectedToComponent(UniqueIdentifier))
                {
                    nl.UnHide();
                }
            }
        }

        public void Hide()
        {
            isInvisible = true;
            IsDirty = true;
            if (this is NetworkDevice)
            {
                //we want to go through all links and unhide any links connected to this device
                Network myNet = NB.GetNetwork();
                foreach (NetworkLink nl in myNet.AllLinksConnectedToComponent(UniqueIdentifier))
                {
                    nl.Hide();
                }
            }
        }


        public virtual void Destroy()
        {
            //This really does nothing.  But the link will trigger some stuff needing to be done
        }

        public virtual List<string> arp(UInt32 IP)
        {
            List<string> arps = new List<string>();
            return arps;  //links have no MAC addresses
        }

        public virtual void Save(XmlWriter writer)
        {  
        }

        public virtual void Load(XmlNode theNode)
        {
        }

        public virtual void UpdateFromComponent(NetworkComponent CopyFrom)
        {

        }

        public virtual void DoProcessing(Packet tPacket)
        {
        }

        public virtual void DoMoving(Packet tPacket)
        {
        }

        public virtual void DoInput(Packet tPacket)
        {

        }

        public virtual void DoOutput(Packet tPacket)
        {

        }

        public int GetUniqueIdentifier
        {
            get { return UniqueIdentifier; }
        }

        public static T Clone<T>(T source)
        {
            if (!typeof(T).IsSerializable)
            {
                throw new ArgumentException(NB.Translate("NC_CloneSerialzable"), NB.Translate("_source"));
            }

            // Don't serialize a null object, simply return the default for that object
            if (Object.ReferenceEquals(source, null))
            {
                return default(T);
            }

            IFormatter formatter = new BinaryFormatter();
            Stream stream = new MemoryStream();
            using (stream)
            {
                formatter.Serialize(stream, source);
                stream.Seek(0, SeekOrigin.Begin);
                return (T)formatter.Deserialize(stream);
            }
        }

    }
}
