// Created with MonoDevelop
//
//    SearchIPAddr: find spectrometer in local network
//    Copyright (C) 2020 A. Höpfner, Hiperscan GmbH Dresden, Germany
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.


using System;
using System.Collections.Generic;
using System.Linq;

namespace Hiperscan.Common.SearchIpAddress
{
    public partial class SearchIPAdr
    {
        public class Parameter
        {
            public Parameter()
            {

            }

            public Parameter(string[] args)
            {
                if (args.Length > 5)
                    throw new ArgumentException("Invalid number of arguments");

                if (args.Length > 0)
                {
                    foreach (string serivice_name in args[0].Split('|'))
                        this.AddServiceName(serivice_name);
                }
                else
                {
                    this.AddServiceName(ServiceTypes.MDNS_AILINK);
                }

                if (args.Length > 1)
                    this.TimeoutMSec = Int32.Parse(args[1]);

                if (args.Length > 2)
                    this.Restrictions = (SearchRestrictions)Enum.Parse(typeof(SearchRestrictions), args[2]);

                if (args.Length > 3)
                    this.PingSubNetStart = Int32.Parse(args[3]);

                if (args.Length > 4)
                    this.PingSubNetEnd = Int32.Parse(args[4]);
            }

            public string WriteToArgs()
            {
                return String.Format("{0} {1} {2} {3} {4}",
                                     this.ServicesAsString,
                                     this.TimeoutMSec,
                                     this.Restrictions,
                                     this.PingSubNetStart,
                                     this.PingSubNetEnd);
            }

            public override string ToString()
            {
                string value = "Search ip address -> parameters:\n";
                value += String.Format("\tServices:           {0}\n", this.ServicesAsString);
                value += String.Format("\tTimeout msec:        {0}\n", this.TimeoutMSec);
                value += String.Format("\tRestrictions:        {0}\n", this.Restrictions);
                value += String.Format("\tPing start:          {0}\n", this.PingSubNetStart);
                value += String.Format("\tPing end:            {0}\n", this.PingSubNetEnd);
                value += String.Format("\tMdsn external path:  {0}\n", this.WindowsMdnsSearchPath);
                value += String.Format("\tPredefined address:  {0}\n", (this.UserdefinedAddress == null ? "None" : this.UserdefinedAddress.ToString()));
                value += String.Format("\tLast chance address: {0}\n", (this.LastChanceAddress == null ? "None" : this.LastChanceAddress.ToString()));
                return value;
            }

            public bool HasServiceAnAdresses(string service_name)
            {
                return this.Services[service_name] > 0;
            }

            public void AddServiceFound(string service_name)
            {
                 this.Services[service_name]++;
            }

            public bool AddServiceName(string service_name)
            {
                if (this.Services.ContainsKey(service_name))
                    return false;

                this.Services.Add(service_name, 0);
                return true;
            }

            public HashSet<string> MdnsServiceTypes
            {
                get
                {
                    IEnumerable<string> types = this.Services.Keys
                                            .Select(x => x)
                                            .Where(x => x.StartsWith("_", StringComparison.InvariantCulture));

                    return new HashSet<string>(types);
                }
            }

            public bool HaveAllMdnsServicesAnAddress
            {
                get
                {
                    foreach (string service in this.MdnsServiceTypes)
                    {
                        if (this.Services[service] != 1)
                            return false;
                    }

                    return true;
                }
            }

            public HashSet<string> PingServiceTypes
            {
                get
                {
                    IEnumerable<string> types = this.Services.Keys
                                            .Select(x => x)
                                                    .Where(x => x.StartsWith("_", StringComparison.InvariantCulture) == false);

                    return new HashSet<string>(types);
                }
            }

            public bool HaveAllPingServicesAnAddress
            {
                get
                {
                    foreach (string service in this.PingServiceTypes)
                    {
                        if (this.Services[service] != 1)
                            return false;
                    }

                    return true;
                }
            }

            public string ServicesAsString
            {
                get
                {
                    return String.Join("|", this.Services.Keys.ToArray());
                }
            }

            private Dictionary<string, int> Services { get; set; } = new Dictionary<string, int>();
            public int TimeoutMSec { get; set; } = 5000;
            public string WindowsMdnsSearchPath { get; set; } = String.Empty;
            public int PingSubNetStart { get; set; } = 2;
            public int PingSubNetEnd { get; set; } = 255;
            public SearchRestrictions Restrictions { get; set; } = SearchRestrictions.All;

            public FullAddress LastChanceAddress { get; set; } = null;
            public FullAddress UserdefinedAddress { get; set; } = null;
        }
    }
}
