// 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.IO;

namespace Hiperscan.Common.SearchIpAddress
{
    public partial class SearchIPAdr
    {
        public SearchIPAdr()
        {
            this.devices = new List<string>();
        }

        public HashSet<FullAddress> Run(Parameter parameter, bool start_extern_proc = false)
        {
            if (start_extern_proc == true)
            {
                this.SearchServiceOverExtProcess(parameter);
            }
            else
            {
                this.SearchParameter = parameter;

                if (parameter.MdnsServiceTypes.Count > 0)
                    this.SearchServicesByMdns();

                if (parameter.PingServiceTypes.Count > 0)
                    this.SearchByPing();
            }

            return this.FullAddresses;
        }

        private void SearchServiceOverExtProcess(Parameter parameter)
        {
            Console.WriteLine("Start extern-service-process...");

            DirectoryInfo service_dir = null;
            if (String.IsNullOrEmpty(parameter.WindowsMdnsSearchPath) == true)
                service_dir = new DirectoryInfo(Directory.GetCurrentDirectory());
            else
                service_dir = new DirectoryInfo(parameter.WindowsMdnsSearchPath);

            FileInfo mdns_file = new FileInfo(Path.Combine(service_dir.FullName, "MDnsSearch.exe"));

            System.Diagnostics.Process proc = null;

            if (mdns_file.Exists)
            {
                proc = new System.Diagnostics.Process();
                proc.StartInfo.FileName = mdns_file.FullName;
                proc.StartInfo.CreateNoWindow = true;
                proc.StartInfo.UseShellExecute = false;
                proc.StartInfo.WorkingDirectory = service_dir.FullName;
                proc.StartInfo.RedirectStandardOutput = true;
                proc.StartInfo.StandardOutputEncoding = System.Text.Encoding.UTF8;
                proc.StartInfo.Arguments = parameter.WriteToArgs();

                proc.Start();
                proc.WaitForExit();
                StreamReader arp_stream = proc.StandardOutput;

                if (proc.ExitCode == 0)
                {
                    while (!arp_stream.EndOfStream)
                    {
                        FullAddress tmp = new FullAddress(arp_stream.ReadLine().Trim());
                        if (tmp.IsValid)
                            this.FullAddresses.Add(tmp);
                    }
                }
                else
                {
                    try
                    {
                        Console.WriteLine("Error while running extern-service-process: {0}", arp_stream.ReadToEnd());
                    }
                    catch (Exception)
                    {
                        Console.WriteLine("Error while running extern-service-process: {0}", proc?.ExitCode ?? -815);
                    }
                }
            }
        }

        public void WriteFullAddresses(string prefix = null)
        {
            prefix = prefix ?? String.Empty;
            foreach (FullAddress full_address in this.FullAddresses)
                Console.WriteLine(prefix + full_address.ToString());
        }

        private void CheckForEndOfSearch()
        {
            if (this.SearchParameter.Restrictions == SearchRestrictions.OnlyFirstDevice)
            {
                this.IsMdnsSearchFinished = this.HasAdresses;
                this.IsPingSearchFinished = this.HasAdresses;
                return;
            }

            if (this.SearchParameter.Restrictions == SearchRestrictions.FirstDevicePerService)
            {
                this.IsMdnsSearchFinished = this.SearchParameter.HaveAllMdnsServicesAnAddress;
                this.IsPingSearchFinished = this.SearchParameter.HaveAllPingServicesAnAddress;
            }
        }

        public bool HasAdresses
        {
            get
            {
                return this.FullAddresses.Count > 0;
            }
        }

        private HashSet<FullAddress> FullAddresses { get; set; } = new HashSet<FullAddress>();
        private object SynchGate { get; set; } = new object();
        private Parameter SearchParameter { get; set; } = null;
    }
}
