﻿using System;
using System.Reflection;
using SecureCommunicationComponent.Exceptions;

namespace SecureCommunicationComponent
{
    /// <summary>
    ///     Communicator Component
    /// </summary>
    public class Communicator : IDisposable
    {
        private static readonly MutexPool MutexPool = MutexPool.Instance;
        public Communicator()
        {
            MutexWrapper = MutexPool.Fetch();
        }

        internal MutexWrapper MutexWrapper { get; set; }
        public bool IsDisposed { get; private set; }

        /// <summary>
        ///     Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            VerifyIfDisposed();
            IsDisposed = true;
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        ///     Sends an alert
        /// </summary>
        /// <param name="adressee">The adressee.</param>
        /// <param name="message">The message.</param>
        /// <returns>Confirmation</returns>
        public string SendAlert(string adressee, string message)
        {
            VerifyIfDisposed();
            if (adressee.Trim().ToLower().StartsWith("a"))
            {
                throw new SecureCommunicationException($"Addressee cannot start with 'A' or 'a', your Addresee was: '{adressee}'. \nPlease review your information and try again.");
            }

            if (adressee.Trim().ToLower().StartsWith("b"))
            {
                var zero = 0;
                var result = 10 / zero;
            }

            if (adressee.Trim().ToLower().StartsWith("c"))
                try
                {
                    var zero = 0;
                    var result = 10 / zero;
                }
                catch (DivideByZeroException)
                {
                    //HWM2
                    //I understand the requirement was to create a SecureCommunicationException and have it as the inner exceptoin
                    //of the DivideByZeroException, but the InnerException property is a readonly and can only be setted
                    //at the momment of creating the instance, so I created the SecureCommunicationException and then
                    //a new DivideByZeroException with the SecureCommunicationException as the InnerException, then 
                    //throwed the DivideByZeroException.

                    var secureException = new SecureCommunicationException("An invalid operation has ocured within Secure Communication Component.");
                    throw new DivideByZeroException("Attempted to divide by zero..", secureException);
                }
            var version = Assembly.GetEntryAssembly().GetName().Version;
            return $"{version}. Received: {message}";
        }

        /// <summary>
        ///     Verifies if disposed.
        /// </summary>
        /// <exception cref="ObjectDisposedException">
        ///     This object has been disposed, it will no longer work. Clean your code and
        ///     create a new Communicator if you need to send a new alert.
        /// </exception>
        private void VerifyIfDisposed()
        {
            if (IsDisposed)
            {
                throw new ObjectDisposedException("This object has been disposed, it will no longer work. Clean your code and create a new Communicator if you need to send a new alert.");
            }
        }

        /// <summary>
        ///     Releases unmanaged and - optionally - managed resources.
        /// </summary>
        /// <param name="disposing">
        ///     <c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only
        ///     unmanaged resources.
        /// </param>
        protected void Dispose(bool disposing)
        {
            if (MutexWrapper != null)
            {
                MutexPool.Push(MutexWrapper);
            }
            MutexWrapper = null;
        }

        /// <summary>
        ///     Finalizes an instance of the <see cref="Communicator" /> class.
        /// </summary>
        ~Communicator()
        {
            Dispose(false);
        }
    }
}