using MainShell.Alarm;
using MainShell.Common;
using MainShell.Common.VisionTemple.ViewModel;
using MainShell.Hardware;
using MainShell.Hardware.Acs;
using MainShell.HeightMeasure.Model;
using MainShell.Log;
using MainShell.Motion;
using MainShell.Process;
using MainShell.ProcessResult;
using MainShell.Recipe.Models;
using MainShell.Recipe.Services;
using MainShell.Recipe.ViewModel;
using MainShell.Vision;
using MaxwellFramework;
using MaxwellFramework.Core.Interfaces;
using MW.WorkFlow;
using MXJM.FileWritable;
using Stylet;
using StyletIoC;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;

namespace MainShell
{
    public class StartBootstrapper : Bootstrapper
    {
        private const int FileWriteQueueShutdownTimeoutMilliseconds = 5000;

        private Task _fileWriteQueueProcessTask;

        protected override void OnStart()
        {
            string configuredMachineId = System.Configuration.ConfigurationManager.AppSettings["MachineId"];
            string machineId = string.IsNullOrWhiteSpace(configuredMachineId) ? Environment.MachineName : configuredMachineId;
            LogManager.InitializeMachineId(machineId);

            // 获得语言类型
            string lang = System.Configuration.ConfigurationManager.AppSettings["Lang"];
            // 添加平台语言包
            ResourceDictionary mwLang = new ResourceDictionary() { Source = new Uri("pack://siteoforigin:,,,/../Language/MaxwellFramework_" + lang.ToString() + ".xaml", UriKind.RelativeOrAbsolute) };
            Application.Current.Resources.MergedDictionaries.Add(mwLang);

            // 添加项目语言包,注意项目名称
            ResourceDictionary mxLang = new ResourceDictionary() { Source = new Uri("pack://siteoforigin:,,,/../Language/MXJM_" + lang.ToString() + ".xaml", UriKind.RelativeOrAbsolute) };
            Application.Current.Resources.MergedDictionaries.Add(mxLang);
            base.OnStart();
        }

        private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            IoC.Get<MachineState>().IsExiting = true;
        }

        protected override void ConfigureIoC(IStyletIoCBuilder builder)
        {
            base.ConfigureIoC(builder);
            builder.Bind<HeaderDeviceStatusController>().ToSelf().InSingletonScope();
            builder.Bind<IActiveRecipeService<SubstrateRecipe>>().To<ActiveRecipeService<SubstrateRecipe>>().InSingletonScope();
            builder.Bind<WorkflowRunner>().ToSelf().InSingletonScope();
            builder.Bind<AutoProductionWorkflowBuilder>().ToSelf().InSingletonScope();
            builder.Bind<IChipPreparationService>().To<ChipPreparationService>().InSingletonScope();
            builder.Bind<PreparationAreaService>().ToSelf().InSingletonScope();
            builder.Bind<CurrentChipStateService>().ToSelf().InSingletonScope();
            builder.Bind<AutoProductionRuntimeStateService>().ToSelf().InSingletonScope();
            builder.Bind<ChipPreparationRequestHandler>().ToSelf().InSingletonScope();
            builder.Bind<IWorkflowRuntimeTracker>().To<WorkflowRuntimeTracker>().InSingletonScope();
            builder.Bind<AlarmOperate>().ToSelf().InSingletonScope();
            builder.Bind<RecipeManager>().ToSelf().InSingletonScope();
            builder.Bind<PIDOperater>().ToSelf().InSingletonScope();
            builder.Bind<ProcessCompensationViewModel>().ToSelf().InSingletonScope();
            builder.Bind<IHeightMeasure>().To<DiastimeterHeightMeasure>().InSingletonScope();
            builder.Bind<SubstrateHeightMeasureService>().ToSelf().InSingletonScope();
            builder.Bind<DiastimeterPollingService>().ToSelf().InSingletonScope();
            builder.Bind<IWaferMachineAdapter>().To<DefaultWaferMachineAdapter>().InSingletonScope();
            builder.Bind<IWaferCaptureExecutor>().To<PlaceholderWaferCaptureExecutor>().InSingletonScope();
            builder.Bind<IWaferDieRecognizer>().To<WaferDieRecognizer>().InSingletonScope();
            builder.Bind<IWaferRecognitionResultCollector>().To<WaferRecognitionResultCollector>().InSingletonScope();
            builder.Bind<IWaferDiePositionResultService>().To<WaferDiePositionResultService>().InSingletonScope();
            builder.Bind<IWaferScanPlanner>().To<WaferScanPlanner>().InSingletonScope();
            builder.Bind<FileWriteQueue>().ToSelf().InSingletonScope();
            builder.Bind<VisionTempleWindowViewModel>().ToSelf().InSingletonScope();
            builder.Bind<DiePositionService>().ToSelf().InSingletonScope();
            builder.Bind<DieRecheckService>().ToSelf().InSingletonScope();
            builder.Bind<ProcessResultManager>().ToSelf().InSingletonScope();
            builder.Bind<IDeviceIoMonitorService>().To<DeviceIoMonitorService>().InSingletonScope();
            builder.Bind<IDeviceCylinderService>().To<DeviceCylinderService>().InSingletonScope();
            builder.Bind<ISubstrateLoadDeviceService>().To<SubstrateLoadDeviceService>().InSingletonScope();

            // Motion and approach alignment services
            builder.Bind<SafeAxisMotion>().ToSelf().InSingletonScope();
            builder.Bind<IDieTransferPathGenerator>().To<DieTransferPathGenerator>().InSingletonScope();
            builder.Bind<ICenterRecognizer>().To<CenterRecognizer>().InSingletonScope();
            builder.Bind<ICoordinateTransformer>().To<CoordinateTransformer>().InSingletonScope();
            builder.Bind<ApproachAlignmentService>().ToSelf().InSingletonScope();

            // Vision algorithm module
            builder.Bind<IImageCaptureService>().To<ImageCaptureService>().InSingletonScope();
            builder.Bind<IFindTemplateService>().To<FindTemplateService>().InSingletonScope();
            builder.Bind<IFindEdgeCircleService>().To<FindEdgeCircleService>().InSingletonScope();
            builder.Bind<IFindDieService>().To<FindDieService>().InSingletonScope();
            builder.Bind<ICommonVisionAlgorithmService>().To<CommonVisionAlgorithmService>().InSingletonScope();
            builder.Bind<IVisionStartupInitializationService>().To<VisionStartupInitializationService>().InSingletonScope();

            //AcsInit
            builder.Bind<IAcsAddressAccessService>().To<AcsAddressAccessService>().InSingletonScope();
            builder.Bind<IAcsStartupInitializationService>().To<AcsStartupInitializationService>().InSingletonScope();
        }

        protected override void Configure()
        {
            // This is called after Stylet has created the IoC container, so this.Container exists, but before the
            // Root ViewModel is launched.
            // Configure your services, etc, in here

            base.Configure();
        }

        protected override void OnLaunch()
        {
            // This is called just after the root ViewModel has been launched
            // Something like a version check that displays a dialog might be launched from here
            Application.Current.MainWindow.Closing += MainWindow_Closing;
            var mainWin = Application.Current.MainWindow;

            // 执行注入
            Loading.Initialize(mainWin);
            HeaderDeviceStatusOverlayHost.Attach(mainWin, IoC.Get<HeaderDeviceStatusController>());
            IoC.Get<AlarmOperate>();
            StartFileWriteQueueProcessing();
            IoC.Get<ChipPreparationRequestHandler>();
            base.OnLaunch();
        }

        protected override void PrepareForInit(IProjectManager projectManager)
        {
            Application.Current.MainWindow.Topmost = false;

            projectManager.AddInitTask("HardwareInit", "硬件初始化", () =>
            {
                IoC.Get<HardwareManager>().Initialize();
                IoC.Get<IDeviceIoMonitorService>().Start();
                return true;
            }, null, true);

            projectManager.AddInitTask("RecipeInit", "配方初始化", () =>
            {
                IoC.Get<RecipeManager>().LoadLastLoadedRecipe();
                return true;
            }, null, true);

            projectManager.AddInitTask("ParameterInit", "参数初始化", () =>
            {
                IoC.Get<IAcsStartupInitializationService>().Initialize();
                IoC.Get<IVisionStartupInitializationService>().Initialize();
                return true;
            }, null, true);
        }

        protected override void OnExit(ExitEventArgs e)
        {
            try
            {
                IoC.Get<IDeviceIoMonitorService>().Stop();
                StopFileWriteQueueProcessing();
            }
            catch (InvalidOperationException)
            {
                // Startup can fail before the container is fully initialized.
            }
            catch (Exception ex)
            {
                LogManager.LogSysError(ex);
            }

            // Called on Application.Exit
            base.OnExit(e);
        }

        private void StartFileWriteQueueProcessing()
        {
            FileWriteQueue fileWriteQueue = IoC.Get<FileWriteQueue>();
            _fileWriteQueueProcessTask = fileWriteQueue.ProcessQueueAsync(CancellationToken.None, false);
        }

        private void StopFileWriteQueueProcessing()
        {
            FileWriteQueue fileWriteQueue = IoC.Get<FileWriteQueue>();
            fileWriteQueue.Close();
            WaitForFileWriteQueueShutdown();
        }

        private void WaitForFileWriteQueueShutdown()
        {
            if (_fileWriteQueueProcessTask == null)
            {
                return;
            }

            try
            {
                bool completed = _fileWriteQueueProcessTask.Wait(FileWriteQueueShutdownTimeoutMilliseconds);
                if (!completed)
                {
                    "FileWriteQueue退出等待超时。".LogSysError();
                    return;
                }

                if (_fileWriteQueueProcessTask.IsFaulted && _fileWriteQueueProcessTask.Exception != null)
                {
                    LogManager.LogSysError(_fileWriteQueueProcessTask.Exception);
                }
            }
            catch (AggregateException ex)
            {
                AggregateException flattenedException = ex.Flatten();
                if (flattenedException.InnerException != null)
                {
                    LogManager.LogSysError(flattenedException.InnerException);
                }
                else
                {
                    LogManager.LogSysError(flattenedException);
                }
            }
            catch (Exception ex)
            {
                LogManager.LogSysError(ex);
            }
            finally
            {
                _fileWriteQueueProcessTask = null;
            }
        }

        protected override void OnUnhandledException(DispatcherUnhandledExceptionEventArgs e)
        {
            base.OnUnhandledException(e);
            LogManager.LogUnhandledException(e.Exception, "Error.txt");
        }
    }
}
