using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Data;

namespace ConfigMaker
{

    /// <summary>
    /// Класс для работы с таблицой диапазонов IP адресов.
    /// </summary>
    public class IpaddrTable
    {
        private ArrayList at;

        public int StartFilterId
        {
            get { return startFilterId; }
            set { startFilterId = value; }
        }
        protected int startFilterId;

        /// <summary>
        /// Конструктор по-умолчанию. Инициализирует свойство-мембер,
        /// которое хранит диапазоны IP адресов в коллекции ArrayList.
        /// </summary>
        public IpaddrTable()
        {
            at = new ArrayList();
            startFilterId = 0;
        }

        /// <summary>
        /// Проверяет принадлежность определенного IP адреса к данной таблице
        /// диапазонов IP адресов.
        /// </summary>
        /// <param name="addr">IP адрес, который необходимо проверить на принадлежность</param>
        /// <returns></returns>
        public bool CheckIpaddr(UInt32 addr)
        {
            bool bFound = false;

            foreach (IpaddrPair i in at)
            {
                if ((i.startIp <= addr) && (i.endIp >= addr))
                {
                    bFound = true;
                    break;
                };
            };

            return bFound;
        }

        /// <summary>
        /// Добавление новой записи в таблицу диапазонов IP адресов.
        /// </summary>
        /// <param name="startIp">Начальный IP адрес нового диапазона</param>
        /// <param name="endIp">Конечный IP адрес нового диапазона</param>
        public void AddEntry(UInt32 startIp, UInt32 endIp)
        {
            IpaddrPair ipair = new IpaddrPair(startIp, endIp);

            AddEntry(ipair);
        }

        public void AddEntry(String network, int mask)
        {
            UInt32 net;

            try
            {
                net = Ipaddr.FromString(network);
            }
            catch
            {
                throw new Exception("Неправильно задан адрес сети.");
            };

            UInt32 m = 0;
            for (int q = 32; q > mask; q--)
            {
                m = m << 1;
                m = m + 0x00000001;
            };

            AddEntry(net, net + m);
        }

        /// <summary>
        /// Добавление новой записи в таблицу диапазонов IP адресов.
        /// </summary>
        /// <param name="ipair">Новый диапазон в формате IpaddrPair</param>
        public void AddEntry(IpaddrPair ipair)
        {
            if (ipair.startIp > ipair.endIp)
            {
                throw new Exception("Неверно задан диапазон IP адресов.");
            };

            at.Add(ipair);
        }
    }

    /// <summary>
    /// Класс для хранения диапазона IP адресов
    /// </summary>
    public class IpaddrPair
    {
        public UInt32 startIp;
        public UInt32 endIp;

        /// <summary>
        /// Конструктор по-умолчанию
        /// </summary>
        public IpaddrPair()
        {
            startIp = 0;
            endIp = 0;
        }

        /// <summary>
        /// Конструктор по-умолчанию с параметрами
        /// </summary>
        /// <param name="start">Начальный IP адрес</param>
        /// <param name="end">Конечный IP адрес</param>
        public IpaddrPair(UInt32 start, UInt32 end)
        {
            startIp = start;
            endIp = end;
        }
    }

    /// <summary>
    /// Класс для работы с IPv4 адресами.
    /// Используется исключительно для вызова вспомогательных
    /// статичных методов.
    /// </summary>
    public class Ipaddr
    {
        /// <summary>
        /// Функция преобразования IP адреса из string в UInt32
        /// </summary>
        /// <param name="ipaddr_str">IP адрес как строка в десятично-точечной нотации</param>
        /// <returns></returns>
        public static UInt32 FromString(string ipaddr_str)
        {
            string[] octets = ipaddr_str.Split('.');

            if (octets.Length != 4)
            {
                throw new Exception("Bad Ipaddress");
            };

            UInt32 a1 = UInt32.Parse(octets[0]);
            UInt32 a2 = UInt32.Parse(octets[1]);
            UInt32 a3 = UInt32.Parse(octets[2]);
            UInt32 a4 = UInt32.Parse(octets[3]);

            if ((a1 < 0) || (a2 < 0) || (a3 < 0) || (a4 < 0))
            {
                throw new Exception("Bad Ipaddress");
            };

            if ((a1 > 255) || (a2 > 255) || (a3 > 255) || (a4 > 255))
            {
                throw new Exception("Bad Ipaddress");
            };

            UInt32 retval = a1 << 24;
            retval += a2 << 16;
            retval += a3 << 8;
            retval += a4;

            return retval;
        }

        /// <summary>
        /// Функция преобразования IP адреса из UInt32 в десятично-точечную нотацию.
        /// </summary>
        /// <param name="a">IP адрес как UInt32</param>
        /// <returns></returns>
        public static string ToString(UInt32 a)
        {
            UInt32 a1 = (a >> 24) & 0x000000FF;
            UInt32 a2 = (a >> 16) & 0x000000FF;
            UInt32 a3 = (a >> 8) & 0x000000FF;
            UInt32 a4 = a & 0x000000FF;

            string retval = string.Format("{0}.{1}.{2}.{3}", a1, a2, a3, a4);

            return retval;
        }

        public static string Get3Octet(string ip_addr)
        {
            UInt32 a = FromString(ip_addr);
            return Get3Octet(a);
        }

        public static string Get3Octet(UInt32 a)
        {
            UInt32 a1 = (a >> 24) & 0x000000FF;
            UInt32 a2 = (a >> 16) & 0x000000FF;
            UInt32 a3 = (a >> 8) & 0x000000FF;
            UInt32 a4 = a & 0x000000FF;

            string retval = string.Format("{0}.{1}.{2}", a1, a2, a3);

            return retval;
        }

        public static String NormalizeIp(String ip)
        {
            String retval = ip;

            Regex r_no = new Regex(@"^(\d{1,3}\.){3}\d{1,3}$");
            Match m_no = r_no.Match(ip);
            if (m_no.Success)
                return retval;

            Regex r_24 = new Regex(@"^(\d{1,3}\.){2}\d{1,3}$");
            Match m_24 = r_24.Match(ip);
            if (m_24.Success)
            {
                retval += ".0";
                return retval;
            }

            Regex r_16 = new Regex(@"^\d{1,3}\.\d{1,3}$");
            Match m_16 = r_16.Match(ip);
            if (m_16.Success)
            {
                retval += ".0.0";
                return retval;
            }

            throw new Exception("bad ip address");
        }
    }

    public class Ipmask
    {
        public static UInt32 GetBitMaskFromLen(int mask)
        {
            UInt32 m2 = 0xFFFFFFFF;

            if ((mask < 32) && (mask >= 0))
            {
                m2 = 0;
                for (int i = 0; i < mask; i++)
                {
                    m2 = m2 >> 1;
                    m2 = m2 + 0x80000000;
                };
            };

            return m2;
        }
    }

    public class Ipnet
    {
        public UInt32 addr;
        public int masklen;

        public Ipnet()
        {
            addr = 0;
            masklen = 32;
        }

        public Ipnet(UInt32 _addr, int _masklen)
        {
            addr = _addr;
            masklen = _masklen;
        }
    }

    public class Macaddr
    {
        public static bool Compare(String m1, String m2)
        {
            String mac1 = m1.ToLower();
            int k1 = mac1.IndexOf(':');
            while (k1 >= 0)
            {
                mac1 = mac1.Remove(k1, 1);
                k1 = mac1.IndexOf(':');
            };

            String mac2 = m2.ToLower();
            int k2 = mac2.IndexOf(':');
            while (k2 >= 0)
            {
                mac2 = mac2.Remove(k2, 1);
                k2 = mac2.IndexOf(':');
            };

            if (mac1 != mac2)
                return false;

            return true;
        }

        public static bool IsFakeAddr(string mac_str)
        {
            string s = mac_str.ToLower().TrimEnd();

            if (s.StartsWith("ff:ff:ff:ff"))
                return true;

            if (s.StartsWith("00:ff:00:ff"))
                return true;

            if (s.StartsWith("ff:00:ff:00"))
                return true;

            return false;
        }

        public static bool CheckAddr(string mac_str)
        {
            string s = mac_str.ToLower().TrimEnd();
            if (s.Length == 0)
                return true;

            string[] octets = s.Split(':');

            if (octets.Length != 6)
            {
                throw new Exception("Bad Ipaddress");
            };

            for (int i = 0; i < 6; i++)
            {
                if (!CheckOctet(octets[i]))
                    return false;
            }

            return true;
        }

        public static bool CheckOctet(string s)
        {
            if (s.Length != 2)
                return false;

            char[] o = new char[2];
            o = s.ToCharArray(0, 2);

            bool ok1 = false;
            bool ok2 = false;

            if (char.IsDigit(o[0]))
                ok1 = true;

            switch(o[0])
            {
                case 'a': ok1 = true; break;
                case 'b': ok1 = true; break;
                case 'c': ok1 = true; break;
                case 'd': ok1 = true; break;
                case 'e': ok1 = true; break;
                case 'f': ok1 = true; break;
            };

            if (char.IsDigit(o[1]))
                ok2 = true;

            switch (o[1])
            {
                case 'a': ok2 = true; break;
                case 'b': ok2 = true; break;
                case 'c': ok2 = true; break;
                case 'd': ok2 = true; break;
                case 'e': ok2 = true; break;
                case 'f': ok2 = true; break;
            };

            if (ok1 == false || ok2 == false)
                return false;

            return true;
        }
    }
}
