﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Net.NetworkInformation;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.IO.Ports;
using System.Threading;

namespace Demo.WindowsForms
{
    class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        /// 
        // Instantiate the communications port 
        public SerialPort port = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
        static MainForm windowGUI;

        [STAThread]
        static void Main()
        {
            Application.SetCompatibleTextRenderingDefault(false);
            var program = new Program();
            windowGUI = new MainForm();
            program.SerialInitialize();
            Application.EnableVisualStyles();

            Application.Run(windowGUI);
        }

        //inits the serial port and event handler
        public void SerialInitialize()
        {
            // http://msmvps.com/blogs/coad/archive/2005/03/23/SerialPort-_2800_RS_2D00_232-Serial-COM-Port_2900_-in-C_2300_-.NET.aspx
            // Attach a method to be called when there is data waiting in the port's buffer
            port.DataReceived += new SerialDataReceivedEventHandler(ReceiveData);

            // Open the port for communications
            port.Open();

        }

        //process received data
        public void ReceiveData(object sender, SerialDataReceivedEventArgs e)
        {
            // Show all the incoming data in the port's buffer
            string testChk = port.ReadLine();
            windowGUI.ParseIncomingData(testChk);
        }
    }

    //public class Dummy
    //{

    //} - removed 4-15

    class IpInfo
    {
        public string Ip;
        //public int Port;
        //public TcpState State;
        //public string ProcessName;

        public string CountryName;
        public string RegionName;
        public string City;
        public double Latitude;
        public double Longitude;
        public DateTime CacheTime;

        //public DateTime StatusTime;
        //public bool TracePoint;
    }

    struct IpStatus
    {
        private string countryName;
        public string CountryName
        {
            get
            {
                return countryName;
            }
            set
            {
                countryName = value;
            }
        }

        private int connectionsCount;
        public int ConnectionsCount
        {
            get
            {
                return connectionsCount;
            }
            set
            {
                connectionsCount = value;
            }
        }
    }

    class DescendingComparer : IComparer<IpStatus>
    {
        public bool SortOnlyCountryName = false;

        public int Compare(IpStatus x, IpStatus y)
        {
            int r = 0;

            if (!SortOnlyCountryName)
            {
                r = y.ConnectionsCount.CompareTo(x.ConnectionsCount);
            }

            if (r == 0)
            {
                return x.CountryName.CompareTo(y.CountryName);
            }
            return r;
        }
    }

    class TraceRoute
    {
        readonly static string Data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
        readonly static byte[] DataBuffer;
        readonly static int timeout = 8888;

        static TraceRoute()
        {
            DataBuffer = Encoding.ASCII.GetBytes(Data);
        }

        public static List<PingReply> GetTraceRoute(string hostNameOrAddress)
        {
            var ret = GetTraceRoute(hostNameOrAddress, 1);

            return ret;
        }

        private static List<PingReply> GetTraceRoute(string hostNameOrAddress, int ttl)
        {
            List<PingReply> result = new List<PingReply>();

            using (Ping pinger = new Ping())
            {
                PingOptions pingerOptions = new PingOptions(ttl, true);

                PingReply reply = pinger.Send(hostNameOrAddress, timeout, DataBuffer, pingerOptions);

                //Debug.WriteLine("GetTraceRoute[" + hostNameOrAddress + "]: " + reply.RoundtripTime + "ms " + reply.Address + " -> " + reply.Status);

                if (reply.Status == IPStatus.Success)
                {
                    result.Add(reply);
                }
                else if (reply.Status == IPStatus.TtlExpired)
                {
                    // add the currently returned address
                    result.Add(reply);

                    // recurse to get the next address...
                    result.AddRange(GetTraceRoute(hostNameOrAddress, ttl + 1));
                }
                else
                {
                    Debug.WriteLine("GetTraceRoute: " + hostNameOrAddress + " - " + reply.Status);
                }
            }

            return result;
        }
    }


#if !MONO
    #region Managed IP Helper API

    public struct TcpTable : IEnumerable<TcpRow>
    {
        #region Private Fields

        private IEnumerable<TcpRow> tcpRows;

        #endregion

        #region Constructors

        public TcpTable(IEnumerable<TcpRow> tcpRows)
        {
            this.tcpRows = tcpRows;
        }

        #endregion

        #region Public Properties

        public IEnumerable<TcpRow> Rows
        {
            get
            {
                return this.tcpRows;
            }
        }

        #endregion

        #region IEnumerable<TcpRow> Members

        public IEnumerator<TcpRow> GetEnumerator()
        {
            return this.tcpRows.GetEnumerator();
        }

        #endregion

        #region IEnumerable Members

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.tcpRows.GetEnumerator();
        }

        #endregion
    }

    public struct TcpRow
    {
        #region Private Fields

        private IPEndPoint localEndPoint;
        private IPEndPoint remoteEndPoint;
        private TcpState state;
        private int processId;

        #endregion

        #region Constructors

        public TcpRow(IpHelper.TcpRow tcpRow)
        {
            this.state = tcpRow.state;
            this.processId = tcpRow.owningPid;

            int localPort = (tcpRow.localPort1 << 8) + (tcpRow.localPort2) + (tcpRow.localPort3 << 24) + (tcpRow.localPort4 << 16);
            long localAddress = tcpRow.localAddr;
            this.localEndPoint = new IPEndPoint(localAddress, localPort);

            int remotePort = (tcpRow.remotePort1 << 8) + (tcpRow.remotePort2) + (tcpRow.remotePort3 << 24) + (tcpRow.remotePort4 << 16);
            long remoteAddress = tcpRow.remoteAddr;
            this.remoteEndPoint = new IPEndPoint(remoteAddress, remotePort);
        }

        #endregion

        #region Public Properties

        public IPEndPoint LocalEndPoint
        {
            get
            {
                return this.localEndPoint;
            }
        }

        public IPEndPoint RemoteEndPoint
        {
            get
            {
                return this.remoteEndPoint;
            }
        }

        public TcpState State
        {
            get
            {
                return this.state;
            }
        }

        public int ProcessId
        {
            get
            {
                return this.processId;
            }
        }

        #endregion
    }

    public static class ManagedIpHelper
    {
        public static readonly List<TcpRow> TcpRows = new List<TcpRow>();

        #region Public Methods

        public static void UpdateExtendedTcpTable(bool sorted)
        {
            TcpRows.Clear();

            IntPtr tcpTable = IntPtr.Zero;
            int tcpTableLength = 0;

            if (IpHelper.GetExtendedTcpTable(tcpTable, ref tcpTableLength, sorted, IpHelper.AfInet, IpHelper.TcpTableType.OwnerPidConnections, 0) != 0)
            {
                try
                {
                    tcpTable = Marshal.AllocHGlobal(tcpTableLength);
                    if (IpHelper.GetExtendedTcpTable(tcpTable, ref tcpTableLength, true, IpHelper.AfInet, IpHelper.TcpTableType.OwnerPidConnections, 0) == 0)
                    {
                        IpHelper.TcpTable table = (IpHelper.TcpTable)Marshal.PtrToStructure(tcpTable, typeof(IpHelper.TcpTable));

                        IntPtr rowPtr = (IntPtr)((long)tcpTable + Marshal.SizeOf(table.Length));
                        for (int i = 0; i < table.Length; ++i)
                        {
                            TcpRows.Add(new TcpRow((IpHelper.TcpRow)Marshal.PtrToStructure(rowPtr, typeof(IpHelper.TcpRow))));
                            rowPtr = (IntPtr)((long)rowPtr + Marshal.SizeOf(typeof(IpHelper.TcpRow)));
                        }
                    }
                }
                finally
                {
                    if (tcpTable != IntPtr.Zero)
                    {
                        Marshal.FreeHGlobal(tcpTable);
                    }
                }
            }
        }

        #endregion
    }

    #endregion

    #region P/Invoke IP Helper API

    /// <summary>
    /// <see cref="http://msdn2.microsoft.com/en-us/library/aa366073.aspx"/>
    /// </summary>
    public static class IpHelper
    {
        #region Public Fields

        public const string DllName = "iphlpapi.dll";
        public const int AfInet = 2;

        #endregion

        #region Public Methods

        /// <summary>
        /// <see cref="http://msdn2.microsoft.com/en-us/library/aa365928.aspx"/>
        /// </summary>
        [DllImport(IpHelper.DllName, SetLastError = true)]
        public static extern uint GetExtendedTcpTable(IntPtr tcpTable, ref int tcpTableLength, bool sort, int ipVersion, TcpTableType tcpTableType, int reserved);

        #endregion

        #region Public Enums

        /// <summary>
        /// <see cref="http://msdn2.microsoft.com/en-us/library/aa366386.aspx"/>
        /// </summary>
        public enum TcpTableType
        {
            BasicListener,
            BasicConnections,
            BasicAll,
            OwnerPidListener,
            OwnerPidConnections,
            OwnerPidAll,
            OwnerModuleListener,
            OwnerModuleConnections,
            OwnerModuleAll,
        }

        #endregion

        #region Public Structs

        /// <summary>
        /// <see cref="http://msdn2.microsoft.com/en-us/library/aa366921.aspx"/>
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct TcpTable
        {
            public uint Length;
            public TcpRow row;
        }

        /// <summary>
        /// <see cref="http://msdn2.microsoft.com/en-us/library/aa366913.aspx"/>
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct TcpRow
        {
            public TcpState state;
            public uint localAddr;
            public byte localPort1;
            public byte localPort2;
            public byte localPort3;
            public byte localPort4;
            public uint remoteAddr;
            public byte remotePort1;
            public byte remotePort2;
            public byte remotePort3;
            public byte remotePort4;
            public int owningPid;
        }

        #endregion
    }

    #endregion
#endif
}
