//  
//   Rebex Sample Code License
// 
//   Copyright 2026, REBEX CR s.r.o.
//   All rights reserved.
//   https://www.rebex.net/
// 
//   Permission to use, copy, modify, and/or distribute this software for any
//   purpose with or without fee is hereby granted.
// 
//   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
//   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
//   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
//   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
//   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
//   OTHER DEALINGS IN THE SOFTWARE.
// 

using System;
using Rebex.Net;
using Rebex.Security.Certificates;
using System.Net;
using System.Collections.Concurrent;
using System.Threading.Tasks;

namespace Rebex.Samples
{
    /// <summary>
    /// This sample launches a simple Syslog server.
    /// </summary>
    class Program
    {
        static CertificateChain ServerCertificate;

        static readonly BlockingCollection<SyslogMessageReceivedEventArgs> Queue = new BlockingCollection<SyslogMessageReceivedEventArgs>();

        static long MessagesReceived;
        static int? FirstMessageTimestamp;
        static int? LastMessageTimestamp;

        static void Main(string[] args)
        {
            // set the trial license key
            Rebex.Licensing.Key = Rebex.Samples.TrialKey.Key;


            // parse arguments
            if (!ParseArguments(args))
            {
                ShowHelp();
                return;
            }

            // create Syslog server instance
            var server = new SyslogServer();

            // bind desired endpoints
            server.Bind(SyslogServer.DefaultPort, SyslogTransportProtocol.Udp);
            server.Bind(SyslogServer.DefaultPort, SyslogTransportProtocol.Tcp);

            // if server certificate was specified, set up TLS as well
            if (ServerCertificate != null)
            {
                server.Bind(SyslogServer.DefaultTlsPort, SyslogTransportProtocol.Tls);
                server.Settings.TlsParameters.Certificate = ServerCertificate;
            }

            // register an event handler for received messages
            server.MessageReceived += (s, e) =>
            {
                Queue.Add(e);
            };

            // register an event handler for errors
            server.ErrorOccurred += (s, e) =>
            {
                Console.WriteLine("Syslog server: error occurred (on {0}): {1}", e.RemoteEndPoint, e.Error);
            };

            // start the server
            Console.WriteLine("Syslog server: starting...");
            foreach (var binding in server.Bindings)
            {
                Console.WriteLine("Syslog server: listening on {0}://{1}", binding.Protocol, binding.EndPoint);
            }
            server.Start();
            Console.WriteLine("Syslog server: started.");

            // start event consumer
            var consumer = Task.Factory.StartNew(ConsumeSyslogMessages);


            // wait for a key to finish
            Console.WriteLine(" *** Press any key to stop the server *** ");
            Console.ReadKey();
            Console.WriteLine();


            // stop the server
            Console.WriteLine("Syslog server: stopping...");
            server.Stop();
            Console.WriteLine("Syslog server: stopped.");

            // free consumer thread
            Queue.CompleteAdding();

            // wait for consumer to finish
            consumer.Wait();

            // display final info
            if (MessagesReceived > 1)
            {
                var totalTime = TimeSpan.FromMilliseconds(LastMessageTimestamp.Value - FirstMessageTimestamp.Value);
                Console.WriteLine("Syslog server: received {0} messages, processed during {1}.", MessagesReceived, totalTime);
                Console.WriteLine("Syslog server: speed approx. {0:0.##} messages/sec.", MessagesReceived / totalTime.TotalSeconds);
            }
            else if (MessagesReceived == 1)
            {
                Console.WriteLine("Syslog server: received 1 message.");
            }
            else
            {
                Console.WriteLine("Syslog server: received 0 messages.");
            }
        }

        static void ConsumeSyslogMessages()
        {
            // process received messages
            foreach (var args in Queue.GetConsumingEnumerable())
            {
                ProcessSyslogMessage(args.Message, args.RemoteEndPoint, args.ReceivedTime);
            }
        }

        static void ProcessSyslogMessage(SyslogMessage message, IPEndPoint ep, DateTime received)
        {
            LastMessageTimestamp = Environment.TickCount;

            if (!FirstMessageTimestamp.HasValue)
            {
                FirstMessageTimestamp = LastMessageTimestamp;
            }

            MessagesReceived++;

            Console.WriteLine(" [{0:s}] received syslog message from {1} <{2}|{3}> host='{4}' app={5}[{6}] {7}",
                received,
                ep,
                message.Facility,
                message.Severity,
                message.Hostname ?? "-",
                message.ApplicationName,
                message.ProcessId ?? "-",
                message.Text);
        }

        static bool ParseArguments(string[] args)
        {
            if (args == null || args.Length == 0)
            {
                return true;
            }

            if (args.Length > 2)
            {
                Console.WriteLine("ERROR: Wrong number of arguments.");
                return false;
            }

            string certificatePath = args[0];
            string certificatePassword = (args.Length > 1) ? args[1] : string.Empty;

            try
            {
                ServerCertificate = CertificateChain.LoadPfx(certificatePath, certificatePassword);
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine("ERROR: Cannot load server certificate: {0}", ex.Message);
                return false;
            }
        }

        static void ShowHelp()
        {
            Console.WriteLine();
            Console.WriteLine(@"Usage: SyslogServer [pfxPath [pfxPassword]]");
            Console.WriteLine();
            Console.WriteLine(@"Example: SyslogServer");
            Console.WriteLine(@"Example: SyslogServer c:\data\server.pfx");
            Console.WriteLine(@"Example: SyslogServer c:\data\server.pfx TopSecret");
        }
    }
}
