Imports System.Collections.ObjectModel
Imports System.Threading
Imports EgtBEAMWALL.Core
Imports EgtUILib
Imports EgtWPFLib5

Public Class OptimizePanelVM
   Inherits VMBase

#Region "FIELDS & PROPERTIES"

   Friend m_bNestingRunning As Boolean = False
   Friend m_StopNesting As Boolean = False

   Public Enum PartType As Integer
      MATERIAL = 0
      ALL = 1
   End Enum

   Friend Enum OriginType As Integer
      STANDARD = 0
      FROM_BTL = 1
   End Enum

   Private m_PartTypeList As New List(Of IdNameStruct)({New IdNameStruct(PartType.MATERIAL, EgtMsg(61957)),
                                                        New IdNameStruct(PartType.ALL, EgtMsg(61956))})
   Public ReadOnly Property PartTypeList As List(Of IdNameStruct)
      Get
         Return m_PartTypeList
      End Get
   End Property

   Private m_SelPartType As IdNameStruct
   Public Property SelPartType As IdNameStruct
      Get
         Return m_SelPartType
      End Get
      Set(value As IdNameStruct)
         m_SelPartType = value
      End Set
   End Property

   Private m_OriginTypeList As New List(Of IdNameStruct)({New IdNameStruct(OriginType.STANDARD, EgtMsg(61964)),
                                                        New IdNameStruct(OriginType.FROM_BTL, EgtMsg(61965))})
   Public ReadOnly Property OriginTypeList As List(Of IdNameStruct)
      Get
         Return m_OriginTypeList
      End Get
   End Property

   Private m_SelOriginType As IdNameStruct
   Public Property SelOriginType As IdNameStruct
      Get
         Return m_SelOriginType
      End Get
      Set(value As IdNameStruct)
         m_SelOriginType = value
         NotifyPropertyChanged(NameOf(NestingOption_Visibility))
      End Set
   End Property

   Private m_bLDIntersOther As Boolean = False
   Public Property bLDIntersOther As Boolean
      Get
         Return m_bLDIntersOther
      End Get
      Set(value As Boolean)
         m_bLDIntersOther = value
         WriteMainPrivateProfileString(S_NEST, K_LDINTERSOTHER, If(m_bLDIntersOther, 1, 0))
      End Set
   End Property
   Public ReadOnly Property NestingOption_Visibility As Visibility
      Get
         If Map.refMainMenuVM.SelPage = Pages.MACHINING Then
            If CurrentMachine.nType = MachineType.WALL OrElse CurrentMachine.nType = MachineType.BOTH Then
               If CurrentMachine.dHorDrillDiam > 0 And Map.refMainWindowVM.MainWindowM.GetKeyOption(KEY_OPT.NESTING_AUTO) And m_SelOriginType.Id = OriginType.STANDARD Then
                  Return Visibility.Visible
               End If
            End If
         End If
         Return Visibility.Collapsed
      End Get
   End Property

   Private m_nMinScore As Integer
   Public Property dMinScore As Double
      Get
         Return m_nMinScore
      End Get
      Set(value As Double)
         m_nMinScore = Math.Floor(Math.Min(100, Math.Max(value, 0)))
         WriteMainPrivateProfileString(S_NEST, K_MINSCORE, m_nMinScore)
      End Set
   End Property

   Private m_Optimize_IsEnabled As Boolean = True
   Public ReadOnly Property Optimize_IsEnabled As Boolean
      Get
         Return m_Optimize_IsEnabled
      End Get
   End Property
   Private m_CalcRotFlip_IsEnabled As Boolean = True
   Public ReadOnly Property CalcRotFlip_IsEnabled As Boolean
      Get
         Return m_CalcRotFlip_IsEnabled
      End Get
   End Property

   Public ReadOnly Property CalcRotFlip_Visibility As Visibility
      Get
         Return If(Map.refMainMenuVM.SelPage = Pages.VIEW AndAlso Map.refMainWindowVM.MainWindowM.GetKeyOption(KEY_OPT.NESTING_AUTO), Visibility.Visible, Visibility.Collapsed)
      End Get
   End Property
   Public ReadOnly Property Optimize_Visibility As Visibility
      Get
         Return If(Map.refMainMenuVM.SelPage = Pages.MACHINING AndAlso Not IsNothing(Map.refProjectVM.BTLStructureVM) AndAlso
                  (Map.refProjectVM.BTLStructureVM.nPROJTYPE = BWType.BEAM OrElse
                  (Map.refProjectVM.BTLStructureVM.nPROJTYPE = BWType.WALL AndAlso Map.refMainWindowVM.MainWindowM.GetKeyOption(KEY_OPT.NESTING_AUTO))), Visibility.Visible, Visibility.Collapsed)
      End Get
   End Property

   Public ReadOnly Property OriginType_Visibility As Visibility
      Get
         Return If(Optimize_Visibility = Visibility.Visible AndAlso OriginTypeList.Count > 1, Visibility.Visible, Visibility.Collapsed)
      End Get
   End Property

   Public ReadOnly Property ViewPage_Visibility As Visibility
      Get
         Return If(Map.refMainMenuVM.SelPage = Pages.VIEW, Visibility.Visible, Visibility.Collapsed)
      End Get
   End Property
   Public ReadOnly Property MachiningPage_Visibility As Visibility
      Get
         Return If(Map.refMainMenuVM.SelPage = Pages.MACHINING, Visibility.Visible, Visibility.Collapsed)
      End Get
   End Property

#Region "Messages"

   Public ReadOnly Property LongDrillArea_Msg As String
      Get
         Return EgtMsg(61889)
      End Get
   End Property

   Public ReadOnly Property MinScore_Msg As String
      Get
         Return EgtMsg(61890)
      End Get
   End Property

   Public ReadOnly Property Optimize_Msg As String
      Get
         Return EgtMsg(61833)
      End Get
   End Property

   Public ReadOnly Property Warehouse_ToolTip As String
      Get
         Return EgtMsg(61920)
      End Get
   End Property

   Public ReadOnly Property CalcRotFlip_ToolTip As String
      Get
         Return EgtMsg(61932)
      End Get
   End Property

   Public ReadOnly Property UnlockFlip_ToolTip As String
      Get
         Return EgtMsg(61933)
      End Get
   End Property

   Public ReadOnly Property UnlockRot_ToolTip As String
      Get
         Return EgtMsg(61934)
      End Get
   End Property

#End Region    ' Messages

   ' Definizione comandi
   Private m_cmdOptimize As ICommand
   Private m_cmdCalcRotFlip As ICommand
   Private m_cmdUnlockRot As ICommand
   Private m_cmdUnlockFlip As ICommand
   Private m_cmdWarehouse As ICommand

#End Region    ' FIELDS & PROPERTIES

#Region "CONSTRUCTOR"

   Sub New()
      ' aggiungo riferimento a Map
      Map.SetRefOptimizePanelVM(Me)
      m_SelPartType = PartTypeList(0)
      m_SelOriginType = OriginTypeList(0)
      m_bLDIntersOther = False
      NotifyPropertyChanged(NameOf(SelPartType))
   End Sub

#End Region    ' CONSTRUCTOR

#Region "METHODS"

   Friend Sub SetOptimizePanelIsEnabled(bIsEnabled As Boolean)
      ' se pareti e senza opzione nesting, lascio disabilitato
      If Map.refProjectVM.BTLStructureVM.nPROJTYPE = BWType.WALL AndAlso Not Map.refMainWindowVM.MainWindowM.GetKeyOption(KEY_OPT.NESTING_AUTO) Then
         m_Optimize_IsEnabled = False
         m_CalcRotFlip_IsEnabled = False
      Else
         m_Optimize_IsEnabled = bIsEnabled
         m_CalcRotFlip_IsEnabled = bIsEnabled
      End If
      NotifyPropertyChanged(NameOf(Optimize_IsEnabled))
      NotifyPropertyChanged(NameOf(CalcRotFlip_IsEnabled))
   End Sub

   Friend Function ProcessEvents(ByVal nProg As Integer, ByVal nPause As Integer) As Integer
      If nProg > 0 And nProg <= 100 Then
         NestingRunningWndVM.m_CurrState = SectionProgress.NestStates.NEST
         NestingRunningWndVM.m_CurrTime = nProg
      ElseIf nProg > 100 And nProg <= 200 Then
         NestingRunningWndVM.m_CurrState = SectionProgress.NestStates.ADDPART
         NestingRunningWndVM.m_CurrTime = nProg - 100
      ElseIf nProg > 200 And nProg <= 300 Then
         NestingRunningWndVM.m_CurrState = SectionProgress.NestStates.CALCRAWPART
         NestingRunningWndVM.m_CurrTime = nProg - 200
      End If
      ' Costringo ad aggiornare
      UpdateUI()
      ' Eventuale attesa
      Thread.Sleep(nPause)
      ' Ritorno eventuale stop
      If m_StopNesting Then
         m_StopNesting = False
         Return 1
      Else
         Return 0
      End If
   End Function

   Private Sub StartCalcRotFlip(BTLPart As BTLPartVM)
      ' ricalcolo rotflip
      m_bNestingRunning = True
      ' se vista tutti i pezzi
      Dim bShowBuilding As Boolean = False
      If Map.refShowBeamPanelVM.bShowAll Then
         ' verifico se assemblato e lo annullo per salvataggio
         bShowBuilding = Map.refShowBeamPanelVM.ShowBuilding_IsChecked
         If bShowBuilding Then Map.refProjectVM.BTLStructureVM.ShowBuilding(False, False)
      End If
      Dim NestingRunningWndVM As New NestingRunningWndVM(m_SelPartType.Id, BTLPart)
      Dim NestingRunningWnd As New NestingRunningWndV(Application.Current.MainWindow, NestingRunningWndVM)
      NestingRunningWnd.ShowDialog()
      ' se assemblato lo ripristino
      If bShowBuilding Then Map.refProjectVM.BTLStructureVM.ShowBuilding(True, False)
      EgtDraw()
      m_bNestingRunning = False
   End Sub

   Friend Sub UpdateOriginTypeList(bFromBtl As Boolean)
      m_OriginTypeList = New List(Of IdNameStruct)
      If Not IsNothing(Map.refProjectVM.BTLStructureVM) AndAlso
         (Map.refProjectVM.BTLStructureVM.nPROJTYPE = BWType.BEAM OrElse (Map.refProjectVM.BTLStructureVM.nPROJTYPE = BWType.WALL And Map.refMainWindowVM.MainWindowM.GetKeyOption(KEY_OPT.NESTING_AUTO))) Then
         m_OriginTypeList.Add(New IdNameStruct(OriginType.STANDARD, EgtMsg(61964)))
      End If
      If bFromBtl Then
         m_OriginTypeList.Add(New IdNameStruct(OriginType.FROM_BTL, EgtMsg(61965)))
      End If
      NotifyPropertyChanged(NameOf(OriginTypeList))
      NotifyPropertyChanged(NameOf(OriginType_Visibility))
      NotifyPropertyChanged(NameOf(SelOriginType))
   End Sub

#End Region    ' METHODS

#Region "COMMANDS"

#Region "CalcRotFlip"

   ''' <summary>
   ''' Returns a command that do Open.
   ''' </summary>
   Public ReadOnly Property CalcRotFlip_Command As ICommand
      Get
         If m_cmdCalcRotFlip Is Nothing Then
            m_cmdCalcRotFlip = New Command(AddressOf CalcRotFlip)
         End If
         Return m_cmdCalcRotFlip
      End Get
   End Property

   ''' <summary>
   ''' Execute the Open.  This method is invoked by the OpenCommand.
   ''' </summary>
   Friend Sub CalcRotFlip()
      If IsNothing(Map.refProjectVM.BTLStructureVM) OrElse IsNothing(Map.refProjectVM.BTLStructureVM.BTLPartVMList) OrElse Map.refProjectVM.BTLStructureVM.BTLPartVMList.Count = 0 Then Return
      ' lancio calcolo RotFlip
      StartCalcRotFlip(Nothing)
   End Sub

#End Region ' CalcRotFlip

#Region "UnlockRot"

   ''' <summary>
   ''' Returns a command that do Open.
   ''' </summary>
   Public ReadOnly Property UnlockRot_Command As ICommand
      Get
         If m_cmdUnlockRot Is Nothing Then
            m_cmdUnlockRot = New Command(AddressOf UnlockRot)
         End If
         Return m_cmdUnlockRot
      End Get
   End Property

   ''' <summary>
   ''' Execute the Open.  This method is invoked by the OpenCommand.
   ''' </summary>
   Friend Sub UnlockRot()
      If IsNothing(Map.refProjectVM.BTLStructureVM) OrElse IsNothing(Map.refProjectVM.BTLStructureVM.BTLPartVMList) OrElse Map.refProjectVM.BTLStructureVM.BTLPartVMList.Count = 0 Then Return
      If (Keyboard.Modifiers And ModifierKeys.Shift) = ModifierKeys.Shift Then
         For Each BTLPart In Map.refProjectVM.BTLStructureVM.BTLPartVMList
            If IsNothing(BTLPart) Then Continue For
            If BTLPart.bLockRotation Then
               BTLPart.bLockRotation = False
            End If
         Next
         ' lancio calcolo RotFlip
         StartCalcRotFlip(Nothing)
      Else
         Dim SelBTLPart As BTLPartVM = Map.refProjectVM.BTLStructureVM.SelBTLPart
         If IsNothing(SelBTLPart) Then Return
         If SelBTLPart.bLockRotation Then
            SelBTLPart.bLockRotation = False
            ' lancio calcolo RotFlip
            StartCalcRotFlip(SelBTLPart)
         End If
      End If
   End Sub

#End Region ' UnlockRot

#Region "UnlockFlip"

   ''' <summary>
   ''' Returns a command that do Open.
   ''' </summary>
   Public ReadOnly Property UnlockFlip_Command As ICommand
      Get
         If m_cmdUnlockFlip Is Nothing Then
            m_cmdUnlockFlip = New Command(AddressOf UnlockFlip)
         End If
         Return m_cmdUnlockFlip
      End Get
   End Property

   ''' <summary>
   ''' Execute the Open.  This method is invoked by the OpenCommand.
   ''' </summary>
   Friend Sub UnlockFlip()
      If IsNothing(Map.refProjectVM.BTLStructureVM) OrElse IsNothing(Map.refProjectVM.BTLStructureVM.BTLPartVMList) OrElse Map.refProjectVM.BTLStructureVM.BTLPartVMList.Count = 0 Then Return
      If (Keyboard.Modifiers And ModifierKeys.Shift) = ModifierKeys.Shift Then
         For Each BTLPart In Map.refProjectVM.BTLStructureVM.BTLPartVMList
            If IsNothing(BTLPart) Then Continue For
            BTLPart.bLockInversion = False
         Next
         ' lancio calcolo RotFlip
         StartCalcRotFlip(Nothing)
      Else
         Dim SelBTLPart As BTLPartVM = Map.refProjectVM.BTLStructureVM.SelBTLPart
         If IsNothing(SelBTLPart) Then Return
         SelBTLPart.bLockInversion = False
         ' lancio calcolo RotFlip
         StartCalcRotFlip(SelBTLPart)
      End If
   End Sub

#End Region ' UnlockFlip

#Region "Optimize"

   ''' <summary>
   ''' Returns a command that do Open.
   ''' </summary>
   Public ReadOnly Property Optimize_Command As ICommand
      Get
         If m_cmdOptimize Is Nothing Then
            m_cmdOptimize = New Command(AddressOf Optimize)
         End If
         Return m_cmdOptimize
      End Get
   End Property

   ''' <summary>
   ''' Execute the Open.  This method is invoked by the OpenCommand.
   ''' </summary>
   Friend Sub Optimize()
      If IsNothing(m_SelPartType) OrElse IsNothing(m_SelOriginType) Then Return
      If IsNothing(Map.refProjectVM.BTLStructureVM) OrElse IsNothing(Map.refProjectVM.BTLStructureVM.BTLPartVMList) OrElse Map.refProjectVM.BTLStructureVM.BTLPartVMList.Count = 0 Then Return
      ' se nessun grezzo, rendo tutti i pezzi visibili
      If Map.refProjectVM.MachGroupPanelVM.MachGroupVMList.Count = 0 Then
         Map.refProjectVM.BTLStructureVM.ShowAll(False)
      End If
      ' apro finestra di attesa nesting
      m_bNestingRunning = True
      Dim NestingRunningWndVM As NestingRunningWndVM
      If m_SelOriginType.Id = OriginType.FROM_BTL Then
         NestingRunningWndVM = New NestingRunningWndVM(m_SelPartType.Id)
      Else
         NestingRunningWndVM = New NestingRunningWndVM(m_SelPartType.Id, m_bLDIntersOther, m_nMinScore)
      End If
      Dim NestingRunningWnd As New NestingRunningWndV(Application.Current.MainWindow, NestingRunningWndVM)
      NestingRunningWnd.ShowDialog()
      m_bNestingRunning = False
      ' se nessun grezzo, rimetto tutti i pezzi invisibili
      If Map.refProjectVM.MachGroupPanelVM.MachGroupVMList.Count = 0 Then
         Map.refProjectVM.BTLStructureVM.HideAll(True)
      End If
      ' mostro risultati
      Dim sResult As String = ""
      Dim dStartOffset As Double = WarehouseHelper.GetStartOffset()
      For Each Section In NestingRunningWndVM.SectionProgressList
         Dim bSectionInitiated As Boolean = False
         If Section.SectionPartList.Count > 0 AndAlso Section.SParamList.Count = 0 Then
            sResult &= "Section " & Section.Section.sSectionXMaterial & ": no raw part found in the warehouse!" & Environment.NewLine
            bSectionInitiated = True
         End If
         For Each Part In Section.SectionPartList
            If Part.nINPROD <> Part.nCNT + Part.nADDED Then
               ' verifico se inizializzare sezione
               If Not bSectionInitiated Then
                  sResult &= "Section " & Section.Section.sSectionXMaterial & ":" & Environment.NewLine
                  bSectionInitiated = True
               End If
               ' recupero VM
               Dim PartVM As BTLPartVM = Map.refProjectVM.BTLStructureVM.BTLPartVMList.FirstOrDefault(Function(x) x.BTLPartM Is Part)
               If Not IsNothing(PartVM) AndAlso Map.refProjectVM.BTLStructureVM.nPROJTYPE = BWType.BEAM AndAlso Section.SParamList.Count > 0 Then
                  Dim dMaxL As Double = Section.SParamList.Max(Function(x) x.dL)
                  If PartVM.dL + dStartOffset < dMaxL Then
                     sResult &= " - " & Part.nPDN & ": material L(" & dMaxL & ") too short for a part with L(" & PartVM.dL & ")!" & Environment.NewLine
                  Else
                     sResult &= " - " & Part.nPDN & ": partially nested!" & "(" & Part.nINPROD & "/" & Part.nCNT + Part.nADDED & ")" & Environment.NewLine
                  End If
               ElseIf Not IsNothing(PartVM) AndAlso Map.refProjectVM.BTLStructureVM.nPROJTYPE = BWType.WALL Then
                  If Not Section.SParamList.Any(Function(x) x.dL > PartVM.dL AndAlso x.dW > PartVM.dW) Then
                     sResult &= " - " & Part.nPDN & ": no material can fit part dimensions(" & PartVM.dW & " x " & PartVM.dL & ")!" & Environment.NewLine
                  Else
                     sResult &= " - " & Part.nPDN & ": partially nested!" & "(" & Part.nINPROD & "/" & Part.nCNT + Part.nADDED & ")" & Environment.NewLine
                  End If
               Else
                  sResult &= " - " & Part.nPDN & ": partially nested!" & "(" & Part.nINPROD & "/" & Part.nCNT + Part.nADDED & ")" & Environment.NewLine
               End If
            End If
         Next
      Next
      If Not String.IsNullOrWhiteSpace(sResult) Then
         MessageBox.Show(Application.Current.MainWindow, sResult, "", MessageBoxButton.OK, MessageBoxImage.Warning)
      End If
   End Sub

#End Region ' Optimize

#Region "Warehouse"

   ''' <summary>
   ''' Returns a command that do Open.
   ''' </summary>
   Public ReadOnly Property Warehouse_Command As ICommand
      Get
         If m_cmdWarehouse Is Nothing Then
            m_cmdWarehouse = New Command(AddressOf Warehouse)
         End If
         Return m_cmdWarehouse
      End Get
   End Property

   ''' <summary>
   ''' Execute the Open.  This method is invoked by the OpenCommand.
   ''' </summary>
   Friend Sub Warehouse()
      If Not IsNothing(Map.refProjectVM.BTLStructureVM) Then 'If Not IsNothing(Map.refProdManagerVM.CurrProd) Then
         Dim WarehouseWnd As New WarehouseWndV(Application.Current.MainWindow, New WarehouseWndVM())
         WarehouseWnd.ShowDialog()
      End If
   End Sub

#End Region ' Warehouse

#End Region    ' COMMANDS

End Class
