using MainShell.Common;
using MainShell.Common.Display.ViewModel;
using MainShell.EventArgsFolder;
using MainShell.Models;
using MainShell.Process;
using MainShell.ProcessResult;
using MainShell.Recipe.Models;
using MainShell.Resources.CustomControl;
using MaxwellFramework.Core.Interfaces;
using MwFramework.AlarmManager;
using MW.WorkFlow;
using Stylet;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;

namespace MainShell
{
    public class MainViewModel : BaseScreen, IPage, IHandle<ProcessFlowStateChangedEventArgs>
    {
        public string Name { get; set; } = "Home";

        private readonly IAlarmManager _alarmManager;
        private readonly RecipeManager _recipeManager;
        private readonly ProcessResultManager _processResultManager;
        private readonly IEventAggregator _eventAggregator;
        private readonly FlowStageMappingConfig _flowStageMappingConfig;
        private readonly WaferHandlingFlowConfig _waferHandlingFlowConfig;
        private readonly WorkflowRunner _runner;
        private readonly AutoProductionWorkflowBuilder _autoProductionWorkflowBuilder;
        private readonly PreparationAreaService _preparationAreaService;
        private bool _suspendDashboardPersist;
        private CancellationTokenSource _simulateCts;
        private bool _simulateFaultRequested;
        private string _currentSimulatingFlowName;
        private bool _isProcessPaused;

        public WorkflowRunner Runner => _runner;

        public bool IsProcessPaused
        {
            get
            {
                return _isProcessPaused;
            }
            private set
            {
                SetAndNotify(ref _isProcessPaused, value);
                NotifyOfPropertyChange(nameof(CanPauseProcess));
                NotifyOfPropertyChange(nameof(CanResumeProcess));
            }
        }

        public bool CanPauseProcess
        {
            get
            {
                return Runner.IsRunning && !IsProcessPaused;
            }
        }

        public bool CanResumeProcess
        {
            get
            {
                return Runner.IsRunning && IsProcessPaused;
            }
        }

        private static readonly Brush GrayBrush = new SolidColorBrush(Color.FromRgb(128, 128, 128));
        private static readonly Brush RunningBrush = new SolidColorBrush(Color.FromRgb(34, 197, 94));
        private static readonly Brush PausedBrush = new SolidColorBrush(Color.FromRgb(245, 158, 11));
        private static readonly Brush FaultedBrush = new SolidColorBrush(Color.FromRgb(239, 68, 68));
        private static readonly Brush CompletedBrush = new SolidColorBrush(Color.FromRgb(59, 130, 246));

        public CameraViewModel CameraSearchViewModel { get; }
        public CameraViewModel CameraLocateViewModel { get; }
        public CameraViewModel CameraInspectViewModel { get; }

        public DieMapModel SubstrateMapModel { get; } = new DieMapModel();
        public DieMapModel WaferMapModel { get; } = new DieMapModel();

        public ProductionDashboardState DashboardState => _processResultManager.DashboardState;

        public ObservableCollection<FlowNodeItem> FlowNodes { get; } = new ObservableCollection<FlowNodeItem>();
        private readonly Dictionary<string, FlowNodeItem> _flowNodeMap = new Dictionary<string, FlowNodeItem>(StringComparer.OrdinalIgnoreCase);
        public ObservableCollection<FlowNodeItem> WaferFlowNodes { get; } = new ObservableCollection<FlowNodeItem>();
        private readonly Dictionary<string, FlowNodeItem> _waferFlowNodeMap = new Dictionary<string, FlowNodeItem>(StringComparer.OrdinalIgnoreCase);

        private string _selectedFlowName;
        public string SelectedFlowName
        {
            get => _selectedFlowName;
            set => SetAndNotify(ref _selectedFlowName, value);
        }

        private string _currentFlowName = "未运行";
        public string CurrentFlowName
        {
            get => _currentFlowName;
            set => SetAndNotify(ref _currentFlowName, value);
        }

        private Brush _loadStageBrush = GrayBrush;
        public Brush LoadStageBrush
        {
            get => _loadStageBrush;
            set => SetAndNotify(ref _loadStageBrush, value);
        }

        private Brush _alignStageBrush = GrayBrush;
        public Brush AlignStageBrush
        {
            get => _alignStageBrush;
            set => SetAndNotify(ref _alignStageBrush, value);
        }

        private Brush _bondStageBrush = GrayBrush;
        public Brush BondStageBrush
        {
            get => _bondStageBrush;
            set => SetAndNotify(ref _bondStageBrush, value);
        }

        private Brush _inspectStageBrush = GrayBrush;
        public Brush InspectStageBrush
        {
            get => _inspectStageBrush;
            set => SetAndNotify(ref _inspectStageBrush, value);
        }

        private Brush _unloadStageBrush = GrayBrush;
        public Brush UnloadStageBrush
        {
            get => _unloadStageBrush;
            set => SetAndNotify(ref _unloadStageBrush, value);
        }

        private string _substrateRecipe = "-";
        public string SubstrateRecipe
        {
            get => _substrateRecipe;
            set => SetAndNotify(ref _substrateRecipe, value);
        }

        private string _chipRecipe = "-";
        public string ChipRecipe
        {
            get => _chipRecipe;
            set => SetAndNotify(ref _chipRecipe, value);
        }

        private int _rejectCount = 12;
        public int RejectCount
        {
            get => _rejectCount;
            set => SetAndNotify(ref _rejectCount, value);
        }

        public MainViewModel(
            IAlarmManager alarmManager,
            RecipeManager recipeManager,
            ProcessResultManager processResultManager,
            IEventAggregator eventAggregator,
            WorkflowRunner runner,
            AutoProductionWorkflowBuilder autoProductionWorkflowBuilder,
            PreparationAreaService preparationAreaService)
        {
            _alarmManager = alarmManager;
            _recipeManager = recipeManager;
            _processResultManager = processResultManager;
            _eventAggregator = eventAggregator;
            _runner = runner;
            _autoProductionWorkflowBuilder = autoProductionWorkflowBuilder;
            _preparationAreaService = preparationAreaService ?? throw new ArgumentNullException(nameof(preparationAreaService));
            _flowStageMappingConfig = FlowStageMappingConfig.LoadOrCreate();
            _waferHandlingFlowConfig = WaferHandlingFlowConfig.LoadOrCreate();

            CameraSearchViewModel = new CameraViewModel(_eventAggregator, CameraType.TopPositionCamera);
            CameraLocateViewModel = new CameraViewModel(_eventAggregator, CameraType.MapCamera);
            CameraInspectViewModel = new CameraViewModel(_eventAggregator, CameraType.TopWideCamera);

            _eventAggregator.Subscribe(this);
            _recipeManager.RecipesChanged += OnRecipesChanged;
            DashboardState.PropertyChanged += OnDashboardStatePropertyChanged;
            _runner.PropertyChanged += OnRunnerPropertyChanged;

            InitializeFlowNodes();
            InitializeWaferFlowNodes();
            InitMapData();
            RefreshRecipeBindings();
            RefreshFlowBindings();
            RestoreDashboardState();
        }

        private void OnRunnerPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (!string.Equals(e.PropertyName, nameof(WorkflowRunner.IsRunning), StringComparison.Ordinal))
            {
                return;
            }

            if (!Runner.IsRunning)
            {
                IsProcessPaused = false;
            }

            NotifyOfPropertyChange(nameof(CanPauseProcess));
            NotifyOfPropertyChange(nameof(CanResumeProcess));
        }

        private void OnDashboardStatePropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            PersistDashboardState();
        }

        private void RestoreDashboardState()
        {
            var s = _processResultManager.DashboardState;
            _suspendDashboardPersist = true;
            try
            {
                if (!string.IsNullOrWhiteSpace(s.ProductId)) DashboardState.ProductId = s.ProductId;
                if (!string.IsNullOrWhiteSpace(s.ChipId)) DashboardState.ChipId = s.ChipId;

                DashboardState.ProcessedSubstrateTotal = s.ProcessedSubstrateTotal;
                DashboardState.PendingCount = s.PendingCount;
                DashboardState.ProcessedCount = s.ProcessedCount;
                DashboardState.RealTimeUph = s.RealTimeUph;
                DashboardState.YieldUph = s.YieldUph;
                DashboardState.MappingProgress = s.MappingProgress;
            }
            finally
            {
                _suspendDashboardPersist = false;
            }
        }

        private void PersistDashboardState()
        {
            if (_suspendDashboardPersist) return;

            var s = _processResultManager.DashboardState;
            s.ProductId = DashboardState.ProductId;
            s.ChipId = DashboardState.ChipId;
            s.ProcessedSubstrateTotal = DashboardState.ProcessedSubstrateTotal;
            s.PendingCount = DashboardState.PendingCount;
            s.ProcessedCount = DashboardState.ProcessedCount;
            s.RealTimeUph = DashboardState.RealTimeUph;
            s.YieldUph = DashboardState.YieldUph;
            s.MappingProgress = DashboardState.MappingProgress;

            _processResultManager.SaveDashboardState();
        }

        private void InitializeFlowNodes()
        {
            FlowNodes.Clear();
            _flowNodeMap.Clear();

            var flowDisplayNameMap = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
            {
                { ProcessFlowName.SubstrateLoadFlow, "基板上料" },
                { ProcessFlowName.SubstratePositionFlow, "基板定位" },
                { ProcessFlowName.ChipStraighteningFlow, "芯片拉直" },
                { ProcessFlowName.DiePositionFlow, "芯片定位" },
                { ProcessFlowName.DieTransferFlow, "芯片转移" },
                { ProcessFlowName.DieRecheckFlow, "精度复检" },
                { ProcessFlowName.SubstrateUnloadFlow, "基板下料" }
            };

            var flows = _flowStageMappingConfig.Rules
                .Where(r => !string.IsNullOrWhiteSpace(r.WorkflowName))
                .Where(r => !string.Equals(r.WorkflowName, ProcessFlowName.AutoProduction, StringComparison.OrdinalIgnoreCase))
                .GroupBy(r => r.WorkflowName, StringComparer.OrdinalIgnoreCase)
                .Select(g => g.First())
                .OrderBy(r => r.Stage)
                .ThenBy(r => r.WorkflowName)
                .ToList();

            foreach (var f in flows)
            {
                var name = flowDisplayNameMap.ContainsKey(f.WorkflowName) ? flowDisplayNameMap[f.WorkflowName] : f.WorkflowName;
                var node = new FlowNodeItem
                {
                    FlowName = f.WorkflowName,
                    DisplayName = name,
                    Brush = GrayBrush
                };
                FlowNodes.Add(node);
                _flowNodeMap[f.WorkflowName] = node;
            }

            if (FlowNodes.Count > 0)
            {
                SelectedFlowName = FlowNodes[0].FlowName;
            }
        }

        private void InitializeWaferFlowNodes()
        {
            WaferFlowNodes.Clear();
            _waferFlowNodeMap.Clear();

            var nodes = _waferHandlingFlowConfig.Nodes;
            foreach (var node in nodes)
            {
                AddWaferFlowNode(node.Key, node.DisplayName);
            }
        }

        private void AddWaferFlowNode(string key, string displayName)
        {
            var node = new FlowNodeItem
            {
                FlowName = key,
                DisplayName = displayName,
                Brush = GrayBrush
            };

            WaferFlowNodes.Add(node);
            _waferFlowNodeMap[key] = node;
        }

        private void OnRecipesChanged(object sender, EventArgs e)
        {
            Execute.OnUIThread(RefreshRecipeBindings);
        }

        private void RefreshRecipeBindings()
        {
            SubstrateRecipe = _recipeManager.CurrentSubstrateRecipe != null
                ? _recipeManager.CurrentSubstrateRecipe.RecipeName
                : "-";

            ChipRecipe = _recipeManager.CurrentWaferRecipe != null
                ? _recipeManager.CurrentWaferRecipe.RecipeName
                : "-";
        }

        private void RefreshFlowBindings()
        {
            var flow = _processResultManager.FlowState;
            var displayFlow = _flowStageMappingConfig.ResolveDisplayFlowName(flow.WorkflowName, flow.ParentActivityName, flow.CurrentActivityName);
            CurrentFlowName = string.IsNullOrWhiteSpace(displayFlow) ? "未运行" : displayFlow;
            ProcessExecutionStatus status;
            if (!Enum.TryParse(flow.Status, true, out status))
            {
                status = ProcessExecutionStatus.Unknown;
            }

            UpdateFlowVisual(status, flow.WorkflowName, flow.ParentActivityName, flow.CurrentActivityName);
        }

        private void UpdateFlowVisual(ProcessExecutionStatus status, string workflowName, string parentFlowName, string activityName)
        {
            LoadStageBrush = GrayBrush;
            AlignStageBrush = GrayBrush;
            BondStageBrush = GrayBrush;
            InspectStageBrush = GrayBrush;
            UnloadStageBrush = GrayBrush;

            var stage = _flowStageMappingConfig.Resolve(workflowName, parentFlowName, activityName);
            var stageIndex = (int)stage;

            if (stageIndex > 0) LoadStageBrush = CompletedBrush;
            if (stageIndex > 1) AlignStageBrush = CompletedBrush;
            if (stageIndex > 2) BondStageBrush = CompletedBrush;
            if (stageIndex > 3) InspectStageBrush = CompletedBrush;

            Brush currentBrush = GrayBrush;
            switch (status)
            {
                case ProcessExecutionStatus.Running:
                    currentBrush = RunningBrush;
                    break;
                case ProcessExecutionStatus.Paused:
                case ProcessExecutionStatus.Canceled:
                    currentBrush = PausedBrush;
                    break;
                case ProcessExecutionStatus.Faulted:
                    currentBrush = FaultedBrush;
                    break;
                case ProcessExecutionStatus.Completed:
                    currentBrush = CompletedBrush;
                    break;
            }

            switch (stageIndex)
            {
                case 0: LoadStageBrush = currentBrush; break;
                case 1: AlignStageBrush = currentBrush; break;
                case 2: BondStageBrush = currentBrush; break;
                case 3: InspectStageBrush = currentBrush; break;
                case 4: UnloadStageBrush = currentBrush; break;
            }
        }

        public void Handle(ProcessFlowStateChangedEventArgs message)
        {
            Execute.OnUIThread(() =>
            {
                var displayFlow = _flowStageMappingConfig.ResolveDisplayFlowName(message.WorkflowName, message.ParentActivityName, message.CurrentActivityName);
                CurrentFlowName = string.IsNullOrWhiteSpace(displayFlow) ? "未运行" : displayFlow;
                UpdateFlowVisual(message.Status, message.WorkflowName, message.ParentActivityName, message.CurrentActivityName);
                UpdateFlowNodes(message);
                UpdateWaferFlowNodes(message);
            });
        }

        private void UpdateFlowNodes(ProcessFlowStateChangedEventArgs message)
        {
            foreach (var node in FlowNodes)
            {
                node.Brush = GrayBrush;
            }

            var activeFlow = ResolveActiveMainFlowKey(message);
            if (string.IsNullOrWhiteSpace(activeFlow) || !_flowNodeMap.ContainsKey(activeFlow)) return;

            _flowNodeMap[activeFlow].Brush = ResolveStatusBrush(message.Status);
        }

        private string ResolveActiveMainFlowKey(ProcessFlowStateChangedEventArgs message)
        {
            if (!string.IsNullOrWhiteSpace(message.WorkflowName) && _flowNodeMap.ContainsKey(message.WorkflowName))
            {
                return message.WorkflowName;
            }

            if (!string.IsNullOrWhiteSpace(message.ParentActivityName) && _flowNodeMap.ContainsKey(message.ParentActivityName))
            {
                return message.ParentActivityName;
            }

            var displayFlow = _flowStageMappingConfig.ResolveDisplayFlowName(message.WorkflowName, message.ParentActivityName, message.CurrentActivityName);
            if (!string.IsNullOrWhiteSpace(displayFlow) && _flowNodeMap.ContainsKey(displayFlow))
            {
                return displayFlow;
            }

            return null;
        }

        private void UpdateWaferFlowNodes(ProcessFlowStateChangedEventArgs message)
        {
            foreach (var node in WaferFlowNodes)
            {
                node.Brush = GrayBrush;
            }

            var activeFlow = ResolveActiveWaferFlowKey(message);
            if (string.IsNullOrWhiteSpace(activeFlow) || !_waferFlowNodeMap.ContainsKey(activeFlow)) return;

            _waferFlowNodeMap[activeFlow].Brush = ResolveStatusBrush(message.Status);
        }

        private string ResolveActiveWaferFlowKey(ProcessFlowStateChangedEventArgs message)
        {
            return _waferHandlingFlowConfig.ResolveNodeKey(
                message.WorkflowName,
                message.ParentActivityName,
                message.CurrentActivityName);
        }

        private static Brush ResolveStatusBrush(ProcessExecutionStatus status)
        {
            switch (status)
            {
                case ProcessExecutionStatus.Running:
                    return RunningBrush;
                case ProcessExecutionStatus.Paused:
                case ProcessExecutionStatus.Canceled:
                    return PausedBrush;
                case ProcessExecutionStatus.Faulted:
                    return FaultedBrush;
                case ProcessExecutionStatus.Completed:
                    return CompletedBrush;
                default:
                    return GrayBrush;
            }
        }

        public async System.Threading.Tasks.Task StartProcess()
        {
            if (Runner.IsRunning) return;

            if (_simulateCts != null) return;

            IsProcessPaused = false;

            WorkflowStartRequest workflowStartRequest = _autoProductionWorkflowBuilder.Create(SelectedFlowName);

            try
            {
                WorkflowRunCompletedEventArgs completedArgs = await Runner.RunWithResultAsync(
                    workflowStartRequest.Definition,
                    workflowStartRequest.Context,
                    workflowStartRequest.StartStepId);

                if (completedArgs.FinalState == WorkflowState.Faulted)
                {
                    ShowWorkflowFailureDialog(completedArgs);
                }
            }
            catch (Exception ex)
            {
                LocalizedMessageBox.ShowFormat(
                    MessageKey.ProcessFailedWithReason,
                    MessageKey.TitleError,
                    MessageBoxButton.OK,
                    MessageBoxImage.Error,
                    ex.Message ?? LanguageResourceHelper.GetString(MessageKey.CommonUnknownError));
            }
            finally
            {
                IsProcessPaused = false;
            }
        }

        public void PauseProcess()
        {
            if (!Runner.IsRunning || IsProcessPaused || _simulateCts != null)
            {
                return;
            }

            Runner.Pause();
            _preparationAreaService.Pause();
            UpdateCurrentProcessStatus(ProcessExecutionStatus.Paused);
            IsProcessPaused = true;
        }

        public void ResumeProcess()
        {
            if (!Runner.IsRunning || !IsProcessPaused || _simulateCts != null)
            {
                return;
            }

            _preparationAreaService.Resume();
            Runner.Resume();
            UpdateCurrentProcessStatus(ProcessExecutionStatus.Running);
            IsProcessPaused = false;
        }

        private void ShowWorkflowFailureDialog(WorkflowRunCompletedEventArgs completedArgs)
        {
            if (completedArgs == null)
            {
                return;
            }

            object[] failureMessageArguments = completedArgs.FailureMessageArguments ?? Array.Empty<object>();
            if (completedArgs.FailureMessageKey != MessageKey.None)
            {
                if (failureMessageArguments.Length > 0)
                {
                    LocalizedMessageBox.ShowFormat(
                        completedArgs.FailureMessageKey,
                        MessageKey.TitleError,
                        MessageBoxButton.OK,
                        MessageBoxImage.Error,
                        failureMessageArguments);
                }
                else
                {
                    LocalizedMessageBox.Show(
                        completedArgs.FailureMessageKey,
                        MessageKey.TitleError,
                        MessageBoxButton.OK,
                        MessageBoxImage.Error);
                }

                return;
            }

            string failureMessage = string.IsNullOrWhiteSpace(completedArgs.FailureMessage)
                ? LanguageResourceHelper.GetString(MessageKey.CommonUnknownError)
                : completedArgs.FailureMessage;

            LocalizedMessageBox.ShowFormat(
                MessageKey.ProcessFailedWithReason,
                MessageKey.TitleError,
                MessageBoxButton.OK,
                MessageBoxImage.Error,
                failureMessage);
        }

        public async System.Threading.Tasks.Task StopProcess()
        {
            if (_simulateCts != null)
            {
                if (!string.IsNullOrWhiteSpace(_currentSimulatingFlowName))
                {
                    _eventAggregator.Publish(new ProcessFlowStateChangedEventArgs
                    {
                        WorkflowName = _currentSimulatingFlowName,
                        ParentActivityName = _currentSimulatingFlowName,
                        CurrentActivityName = _currentSimulatingFlowName,
                        Status = ProcessExecutionStatus.Canceled
                    });
                }
                _simulateCts.Cancel();
            }

            await _preparationAreaService.CancelAsync(CancellationToken.None);
            await Runner.StopAsync();
            IsProcessPaused = false;
        }

        private void UpdateCurrentProcessStatus(ProcessExecutionStatus status)
        {
            ProcessFlowState flowState = _processResultManager.FlowState;
            string workflowName = string.IsNullOrWhiteSpace(flowState.WorkflowName)
                ? ProcessFlowName.AutoProduction
                : flowState.WorkflowName;

            _processResultManager.UpdateFlowState(
                workflowName,
                flowState.ParentActivityName,
                flowState.CurrentActivityName,
                status,
                flowState.ErrorMessage);
        }

        public void TriggerSimulateFault()
        {
            _simulateFaultRequested = true;
        }

        private async Task SimulateFlowRuntimeAsync()
        {
            _simulateCts = new CancellationTokenSource();
            try
            {
                var token = _simulateCts.Token;
                foreach (var node in FlowNodes)
                {
                    token.ThrowIfCancellationRequested();
                    _currentSimulatingFlowName = node.FlowName;

                    _eventAggregator.Publish(new ProcessFlowStateChangedEventArgs
                    {
                        WorkflowName = node.FlowName,
                        ParentActivityName = node.FlowName,
                        CurrentActivityName = node.FlowName,
                        Status = ProcessExecutionStatus.Running
                    });

                    await Task.Delay(700, token);

                    if (_simulateFaultRequested)
                    {
                        _eventAggregator.Publish(new ProcessFlowStateChangedEventArgs
                        {
                            WorkflowName = node.FlowName,
                            ParentActivityName = node.FlowName,
                            CurrentActivityName = node.FlowName,
                            Status = ProcessExecutionStatus.Faulted,
                            ErrorMessage = "模拟流程异常"
                        });
                        return;
                    }

                    _eventAggregator.Publish(new ProcessFlowStateChangedEventArgs
                    {
                        WorkflowName = node.FlowName,
                        ParentActivityName = node.FlowName,
                        CurrentActivityName = node.FlowName,
                        Status = ProcessExecutionStatus.Completed
                    });

                    await Task.Delay(250, token);
                }
            }
            catch (OperationCanceledException)
            {
                if (!string.IsNullOrWhiteSpace(_currentSimulatingFlowName))
                {
                    _eventAggregator.Publish(new ProcessFlowStateChangedEventArgs
                    {
                        WorkflowName = _currentSimulatingFlowName,
                        ParentActivityName = _currentSimulatingFlowName,
                        CurrentActivityName = _currentSimulatingFlowName,
                        Status = ProcessExecutionStatus.Canceled
                    });
                }
            }
            finally
            {
                _currentSimulatingFlowName = null;
                _simulateFaultRequested = false;
                _simulateCts.Dispose();
                _simulateCts = null;
            }
        }

        private void ResetFlowVisuals()
        {
            foreach (var node in FlowNodes)
            {
                node.Brush = GrayBrush;
            }

            foreach (var node in WaferFlowNodes)
            {
                node.Brush = GrayBrush;
            }

            LoadStageBrush = GrayBrush;
            AlignStageBrush = GrayBrush;
            BondStageBrush = GrayBrush;
            InspectStageBrush = GrayBrush;
            UnloadStageBrush = GrayBrush;
            CurrentFlowName = "未运行";
        }

        public void ClearStatistics()
        {
            _suspendDashboardPersist = true;
            DashboardState.ProcessedSubstrateTotal = 0;
            DashboardState.RealTimeUph = 0;
            DashboardState.YieldUph = 0;
            DashboardState.MappingProgress = 0;
            DashboardState.ProcessedCount = 0;
            _suspendDashboardPersist = false;
            PersistDashboardState();
        }

        private void InitMapData()
        {
            SubstrateMapModel.Initialize(36, 36);
            WaferMapModel.Initialize(36, 36);

            var rand = new Random();
            for (int r = 0; r < 36; r++)
            {
                for (int c = 0; c < 36; c++)
                {
                    var dist = Math.Sqrt(Math.Pow(r - 18, 2) + Math.Pow(c - 18, 2));
                    if (dist > 17)
                    {
                        WaferMapModel.SetDieState(r, c, DieState.NotExist);
                    }
                    else
                    {
                        var v = rand.Next(100);
                        if (v < 3)
                            WaferMapModel.SetDieState(r, c, DieState.Error);
                        else if (v < 40)
                            WaferMapModel.SetDieState(r, c, DieState.Used);
                        else
                            WaferMapModel.SetDieState(r, c, DieState.Available);
                    }

                    var sv = rand.Next(100);
                    if (sv < 2)
                        SubstrateMapModel.SetDieState(r, c, DieState.Error);
                    else if (sv < 45)
                        SubstrateMapModel.SetDieState(r, c, DieState.Used);
                    else
                        SubstrateMapModel.SetDieState(r, c, DieState.Available);
                }
            }

            SubstrateMapModel.SetDieState(16, 20, DieState.Target);
            WaferMapModel.SetDieState(14, 14, DieState.Current);
        }

        protected override void OnViewLoaded()
        {
            base.OnViewLoaded();
        }

        public class FlowNodeItem : PropertyChangedBase
        {
            private Brush _brush;
            public string FlowName { get; set; }
            public string DisplayName { get; set; }
            public Brush Brush
            {
                get => _brush;
                set => SetAndNotify(ref _brush, value);
            }
        }
    }
}
