// Created with MonoDevelop
//
//    QuickStep: Acquire, view and identify spectra 
//    Copyright (C) 2018 Thomas Klose & Torsten Schache, 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.Net;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Serialization.Formatters;
using Hiperscan.Unix;


namespace Hiperscan.AnalysisModule
{
    public abstract class RemoteClient
    {
        public  RemoteClient(string hostname, int tcp_port)
        {
            string service_name = this.ServiceName + tcp_port.ToString();
            if (hostname == this.HostName)
                hostname = this.LocalHostAddress;

            IChannel channel = ChannelServices.GetChannel(service_name);
            if (channel == null)
            {
                System.Collections.IDictionary settings = new System.Collections.Hashtable
                {
                    ["name"] = service_name,
                    ["port"] = 0,
                    ["secure"] = false
                };

                if (hostname == this.LocalHostAddress)
                    settings["bindTo"] = hostname;

                BinaryServerFormatterSinkProvider provider = new BinaryServerFormatterSinkProvider
                {
                    TypeFilterLevel = TypeFilterLevel.Full
                };
                channel = new TcpChannel(settings, null, provider);
                ChannelServices.RegisterChannel(channel, false);
            }

            this.RemoteService = (IAnalysisServer) Activator.GetObject(this.ServiceType, $"tcp://{hostname}:{tcp_port}/{service_name}");
        }

        private string LocalHostAddress
        {
            get
            {
                string address = string.Empty;
                try
                {
                    address = IPAddress.Loopback.ToString();
                    if (string.IsNullOrEmpty(address) == true)
                        throw new Exception(Catalog.GetString("No IPv4 local address found."));
                }
                catch (Exception ex)
                {
                    address = IPAddress.IPv6Loopback.ToString();
                    if (string.IsNullOrEmpty(address) == true)
                        throw new Exception(Catalog.GetString("No IPv6 local address found."), ex);
                }

                return address;
            }
        }

        public IAnalysisServer RemoteService { get; protected set; }

        protected abstract string ServiceName { get; }
        protected abstract Type ServiceType { get; }
        private string HostName => "localhost";
    }
}
