using System;
using System.Diagnostics;
using System.EnterpriseServices;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Windows;
using EHF;

using Valg.EVA.Skanning.Scan.ReadSoftContracts.Events;
using Unity;
using Prism.Events;
using Valg.EVA.Skanning.Configuration;
using Valg.EVA.Skanning.ContainerExtensions;
using Valg.EVA.Skanning.Diagnostics;
using Valg.EVA.Skanning.UserInterfaceElements.Bootstrapping;
using Valg.EVA.Skanning.UserInterfaceElements.ErrorHandling;
using CommonServiceLocator;
using Unity.ServiceLocation;

namespace Valg.EVA.Skanning.Scan.Api
{
    [ClassInterface(ClassInterfaceType.AutoDispatch)]
    public class ReadSoftApi : ServicedComponent, IReadSoftApi
    {
        private readonly IEventAggregator eventAggregator;
        private readonly IGenericStartupErrorHandler genericStartupErrorHandler;
        private ScanApplication scanApplication;
        private readonly ScannedFormMapper scannedFormMapper;
        private readonly RecoverableReadsoftErrorsDispatcher recoverableErrorsDispatcher;
        private readonly bool constructorThrewException;
        private readonly IApplicationConfigurationReader applicationConfigurationReader;


        public ReadSoftApi()
        {
            var processName = Process.GetCurrentProcess().ProcessName;

            applicationConfigurationReader = new ApplicationConfigurationReader(new ConfigurationFileProvider($@"{Environment.CurrentDirectory}\Valg.EVA.Skanning.Scan.Presentation.dll.config"));
            var diagnosticsConfiguration = new DiagnosticsConfiguration(applicationConfigurationReader);
            var inprocessLogging = new InProcessLoggingSinkConfigurator(diagnosticsConfiguration);
            inprocessLogging.ConfigureLoggingSinks(processName);

            EvaSkanningEventSource.Log.StartupInitiated(processName);

            Task.Run(() => SystemInformationCollector.CollectAndReportSystemInformation());

            try
            {
#if DEBUG
                
                System.Diagnostics.Debugger.Launch();
#endif
                if (Application.Current == null)
                {
                    new Application();
                }

                var container = new UnityContainer();
                container.RegisterInstance(typeof(IApplicationConfigurationReader), applicationConfigurationReader, ContainerLifetimes.CreateContainerControlledLifetimeManager());

                AssemblyInstaller.ForceLoadAssemblies();

                AssemblyInstaller.InstallAssemblies(container);

                container.RegisterInstance(typeof(IUnityContainer), container);
                ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(container));
                AssemblyInstaller.StartStartableComponents(container);

                eventAggregator = container.Resolve<IEventAggregator>();

                PublishBootstrappingCompletedEvent();


                genericStartupErrorHandler = container.Resolve<IGenericStartupErrorHandler>();
                scannedFormMapper = container.Resolve<ScannedFormMapper>();
                recoverableErrorsDispatcher = container.Resolve<RecoverableReadsoftErrorsDispatcher>();
            }
            catch (Exception exception)
            {
                constructorThrewException = true;
                ApplicationUnhandledExceptionHandler.LogErrorAndShowMessageBox(exception);
            }
            finally
            {
                EvaSkanningEventSource.Log.StartupCompleted(processName);
            }
        }

        private void PublishBootstrappingCompletedEvent()
        {
            var bootCompleted = eventAggregator.GetEvent<ContainerBootstrappingCompletedEvent>();
            bootCompleted.Publish(new ContainerBootstrappingCompletedEventArgs());
        }

        
        
        
        
        
        
        
        
        
        public ehReturnValue Connect(IEHF_IScanApp scanAppClass, string file, string section)
        {
            

            if (constructorThrewException)
            {
                scanAppClass.CloseApp();
            }
            else
            {
                try
                {

                    
                    
                    
                    scanApplication = new ScanApplication(scanAppClass, eventAggregator, scannedFormMapper, applicationConfigurationReader);

                    scanApplication.SubscribeToReadsoftEvents(this);

                    scanApplication.SubscribeToApplicationEvents();

                    var scanAppConnectedEvent = eventAggregator.GetEvent<ScanAppSuccessfullyConnectedEvent>();
                    scanAppConnectedEvent.Publish(new ScanAppSuccessfullyConnectedEventArgs());
                }
                catch (Exception exception)
                {
                    genericStartupErrorHandler.HandleCriticalStartupError(exception);

                    if (scanAppClass != null)
                    {
                        
                        scanAppClass.CloseApp();
                    }
                }
            }

            return ehReturnValue.EV_OK_ABORT;
        }

        public class ScannerConfig
        { }

        public ehReturnValue Disconnect(IEHF_IScanApp scanAppClass)
        {
            Debug.WriteLine("Disconnect(...)");

            return ehReturnValue.EV_OK;
        }

        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        public ehReturnValue OnScanBatchDialogShow(int bundleCount, int bundleIndex)
        {
            Debug.WriteLine($"OnScanBatchDialogShow({bundleCount}, {bundleIndex})");
            try
            {
                recoverableErrorsDispatcher.DispatchJobSetupError(scanApplication);
                
            }
            catch (Exception exception)
            {
                recoverableErrorsDispatcher.DispatchGenericException(exception, scanApplication);
            }
            return ehReturnValue.EV_OK_ABORT;
        }

        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        public ehReturnValue OnScanBeforeSaveDlg(int situation)
        {
            Debug.WriteLine($"OnScanBeforeSaveDlg({situation})");

            try
            {
                scanApplication.SetReturnValueToNo();
            }
            catch (Exception exception)
            {
                recoverableErrorsDispatcher.DispatchGenericException(exception, scanApplication);
            }
            return ehReturnValue.EV_OK_ABORT;
        }

        
        
        
        
        
        
        
        
        public ehReturnValue OnFormScanEnd()
        {
            Debug.WriteLine("OnFormScanEnd()");

            try
            {
                scanApplication.MapAndSaveCurrentForm();
            }
            catch (Exception exception)
            {
                recoverableErrorsDispatcher.DispatchGenericException(exception, scanApplication);
            }

            return ehReturnValue.EV_OK;
        }

        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        public ehReturnValue OnScanNotifyUser(int errorSituation, string errorInfo)
        {
            Debug.WriteLine($"OnScanNotifyUser({errorSituation}, {errorInfo})");

            recoverableErrorsDispatcher.DispatchScanNotifyUserError(errorSituation, errorInfo, scanApplication);

            return ehReturnValue.EV_OK_ABORT;
        }

        public ehReturnValue OnAppError(int errorNo, int errorType, int errorId, int errorIdExt)
        {
            Debug.WriteLine($"OnAppError({errorNo}, {errorType}, {errorId}, {errorIdExt})");

            recoverableErrorsDispatcher.DispatchAppError(errorNo, errorType, errorId, errorIdExt, scanApplication);

            return ehReturnValue.EV_OK_ABORT;
        }

        public ehReturnValue OnJobStarted()
        {
            Debug.WriteLine("OnJobStarted()");
            return ehReturnValue.EV_OK;
        }

        public ehReturnValue OnJobStopped()
        {
            Debug.WriteLine("OnJobStopped()");
            return ehReturnValue.EV_OK;
        }
    }
}

