Imports System.Collections.ObjectModel
Imports System.Collections.Specialized
Imports System.ComponentModel
Imports System.IO
Imports EgtBEAMWALL.Core
Imports EgtBEAMWALL.DataLayer.DatabaseModels
Imports EgtUILib
Imports EgtWPFLib5

Public Class PartVM
   Inherits Core.PartVM

#Region "FIELDS & PROPERTIES"

#Region "General"

   ' variabile che indica se almeno un pezzo e' stato modificato durante il caricamento del progetto
   Private Shared m_PartModifiedOnLoading As Boolean = False

   Public Overloads ReadOnly Property dVolume As Double
      Get
         Return dVolume
      End Get
   End Property

   Private m_bSearchFound As Boolean
   Public ReadOnly Property bSearchFound As Boolean
      Get
         Return m_bSearchFound
      End Get
   End Property
   Friend Sub SetSearchFound()
      m_bSearchFound = True
      NotifyPropertyChanged(NameOf(Search_Background))
   End Sub
   Friend Sub ResetSearchFound()
      m_bSearchFound = False
      NotifyPropertyChanged(NameOf(Search_Background))
   End Sub

   Public ReadOnly Property Search_Background As SolidColorBrush
      Get
         Return If(m_bSearchFound, Brushes.Gold, Brushes.Transparent)
      End Get
   End Property

#End Region    ' General

#Region "Beam"

   Public Overrides Property sOffset As String
      Get
         Return LenToString(m_PartM.dOffset, 3)
      End Get
      Set(value As String)
         Dim dValue As Double
         If StringToLenAdv(value, dValue, True) Then
            Dim dOldValue As Double = m_PartM.dOffset
            Dim BeamMachGroup As MyMachGroupVM = DirectCast(ParentMachGroupVM, MyMachGroupVM)
            ' se prima trave della barra sostituisco valore anche a startoffset
            If ParentMachGroupVM.PartVMList(0) Is Me Then
               m_PartM.dOffset = dValue
               BeamMachGroup.dStartCut = dValue
            ElseIf dValue > CurrentMachine.dMinOffset Then
               m_PartM.dOffset = dValue
            Else
               m_PartM.dOffset = CurrentMachine.dMinOffset
            End If
            If Not BeamMachGroup.ReDrawBeamMachgroup() Then
               ' rispristino vecchio valore
               m_PartM.dOffset = dOldValue
               BeamMachGroup.dStartCut = dOldValue
               BeamMachGroup.ReDrawBeamMachgroup()
            End If
            EgtDraw()
            ' resetto validazione del pezzo
            ResetCalcPart()
            ParentMachGroupVM.UpdateUsage()
         Else
            NotifyPropertyChanged(NameOf(sOffset))
         End If
      End Set
   End Property

#End Region    ' Beam

#Region "Wall"

   Public Overrides Property sPOSX As String
      Get
         Select Case Map.refProjectVM.BTLStructureVM.nPROJTYPE
            Case BWType.WALL
               ' se parete, valuto angolo di posizionamento
               Select Case CurrentMachine.NestingCorner
                  Case MCH_CR.TL, MCH_CR.BL
                     Return LenToString(m_PartM.dPOSX, 3)
                  Case Else ' MCH_CR.TR, MCH_CR.BR
                     Return LenToString(m_ParentMachGroupVM.dL - dL - m_PartM.dPOSX, 3)
               End Select
            Case Else
               Return LenToString(m_PartM.dPOSX, 3)
         End Select
      End Get
      Set(value As String)
         Dim dValue As Double
         If StringToLenAdv(value, dValue, True) Then
            Dim dOldValue As Double = m_PartM.dPOSX
            Dim dNewValue As Double = dValue
            Select Case Map.refProjectVM.BTLStructureVM.nPROJTYPE
               Case BWType.WALL
                  ' se parete, valuto angolo di posizionamento
                  Select Case CurrentMachine.NestingCorner
                     Case MCH_CR.TL, MCH_CR.BL
                        dNewValue = dValue
                     Case Else ' MCH_CR.TR, MCH_CR.BR
                        dNewValue = m_ParentMachGroupVM.dL - dL - dValue
                  End Select
               Case Else
                  m_PartM.dPOSX = dValue
            End Select
            If EgtMovePartInRawPart(nPartId, New Vector3d(dNewValue - dOldValue, 0, 0)) Then
               EgtSetInfo(nPartId, MGR_PRT_POSX, dValue)
               NotifyPropertyChanged(NameOf(sPOSX))
               ' resetto validazione del pezzo
               ResetCalcPart()
            Else
               ' ripristino vecchio valore
               m_PartM.dPOSX = dOldValue
            End If
            EgtDraw()
         Else
            NotifyPropertyChanged(NameOf(sPOSX))
         End If
      End Set
   End Property

   Public Overrides Property sPOSY As String
      Get
         Select Case Map.refProjectVM.BTLStructureVM.nPROJTYPE
            Case BWType.WALL
               ' valuto angolo di posizionamento
               Select Case CurrentMachine.NestingCorner
                  Case MCH_CR.TL, MCH_CR.TR
                     Return LenToString(m_ParentMachGroupVM.dW - dW - m_PartM.dPOSY, 3)
                  Case Else ' MCH_CR.BL, MCH_CR.BR
                     Return LenToString(m_PartM.dPOSY, 3)
               End Select
            Case Else
               Return LenToString(m_PartM.dPOSY, 3)
         End Select
      End Get
      Set(value As String)
         Dim dValue As Double
         If StringToLenAdv(value, dValue, True) Then
            Dim dOldValue As Double = m_PartM.dPOSY
            Dim dNewValue As Double = dValue
            ' valuto angolo di posizionamento
            Select Case Map.refProjectVM.BTLStructureVM.nPROJTYPE
               Case BWType.WALL
                  Select Case CurrentMachine.NestingCorner
                     Case MCH_CR.TL, MCH_CR.TR
                        dNewValue = m_ParentMachGroupVM.dW - dW - dValue
                     Case MCH_CR.BL, MCH_CR.BR
                        dNewValue = dValue
                  End Select
               Case Else
                  m_PartM.dPOSY = dValue
            End Select
            If EgtMovePartInRawPart(nPartId, New Vector3d(0, dNewValue - dOldValue, 0)) Then
               EgtSetInfo(nPartId, MGR_PRT_POSY, dValue)
               NotifyPropertyChanged(NameOf(sPOSY))
               ' resetto validazione del pezzo
               ResetCalcPart()
            Else
               ' ripristino vecchio valore
               m_PartM.dPOSY = dOldValue
            End If
            EgtDraw()
         Else
            NotifyPropertyChanged(NameOf(sPOSY))
         End If
      End Set
   End Property

   Public Property bFLIP As Boolean
      Get
         Return m_PartM.nFLIP <> 0
      End Get
      Set(value As Boolean)
         If Map.refProjectVM.bCalcRunning Then Return
         ' se MachGroup gia' mandato in produzione, esco
         If m_ParentMachGroupVM.nProduction_State >= ItemState.Assigned Then Return
         If (value And m_PartM.nFLIP = 0) OrElse (Not value And m_PartM.nFLIP <> 0) Then
            ' salvo posizione 
            Dim dTempPosX As Double = m_PartM.dPOSX
            Dim dTempPosY As Double = m_PartM.dPOSY
            ' tolgo il pezzo dal grezzo
            EgtRemovePartFromRawPart(nPartId)
            ' recupero layer del box
            Dim nBoxLayerId As Integer = EgtGetFirstNameInGroup(nPartId, "Box")
            ' recupero box del layer box
            Dim b3Box As New BBox3d
            EgtGetBBoxGlob(nBoxLayerId, GDB_BB.STANDARD, b3Box)
            If EgtRotate(nPartId, b3Box.Center, Vector3d.X_AX, 180, GDB_RT.GLOB) Then
               m_PartM.nFLIP = If(value, 180, 0)
               EgtSetInfo(nPartId, MGR_PRT_FLIP, If(value, 180, 0))
            Else
               NotifyPropertyChanged(NameOf(bFLIP))
            End If
            ' recupero box del pezzo
            Dim b3Part As New BBox3d
            EgtGetBBoxGlob(nPartId, GDB_BB.STANDARD, b3Part)
            ' calcolo distanza tra i box
            Dim vtDeltaBox As Vector3d = b3Box.Min - b3Part.Min
            ' reinserisco il pezzo nel grezzo
            EgtAddPartToRawPart(nPartId, New Point3d(dTempPosX - vtDeltaBox.x, dTempPosY - vtDeltaBox.y, 0), ParentMachGroupVM.MyMachGroupM.nRawPartId)
            ' lo riseleziono
            EgtSelectObj(nPartId)
            ' resetto validazione del pezzo
            ResetCalcPart()
            EgtDraw()
         End If
      End Set
   End Property

#End Region    ' Wall

   ' Definizione comandi
   Private m_cmdBackRotation As ICommand
   Private m_cmdForwardRotation As ICommand

#End Region    ' FIELDS & PROPERTIES

#Region "CONSTRUCTOR"

   Sub New(PartM As PartM, ParentMachGroupVM As MyMachGroupVM)
      MyBase.New(PartM, ParentMachGroupVM)
      ' aggiorno stato calcolo
      CalcGlobalUpdate()
      ' aggiorno stato di produzione
      ReadProductionData()
   End Sub

#End Region    ' CONSTRUCTOR

#Region "METHODS"

#Region "Part"

   Friend Sub ResetOffset()
      m_PartM.dOffset = WarehouseHelper.GetOffset(nType)
      NotifyPropertyChanged(NameOf(sOffset))
   End Sub

   ' Manage the MainWindow_Unloaded event. This method is invoked by the cmdMainWindow_Unloaded.
   Public Overrides Sub DeletePart()
      ' elimino pezzo copia
      EgtRemovePartFromRawPart(Me.nPartId)
      ' Recupero Id BTLPart originale
      Dim BTLPart As BTLPartVM = BTLPartVM.RetrieveBTLPartFromPart(nPartId)
      EgtErase(Me.nPartId)
      ' rimuovo dalla lista pezzi
      Dim Index As Integer = ParentMachGroupVM.PartVMList.IndexOf(ParentMachGroupVM.PartVMList.FirstOrDefault(Function(x) x.nPartId = nPartId))
      If Index = 0 Then
         If ParentMachGroupVM.PartVMList.Count > 1 Then
            ParentMachGroupVM.SelPart = ParentMachGroupVM.PartVMList(0)
         Else
            ParentMachGroupVM.SelPart = Nothing
         End If
      ElseIf Index = ParentMachGroupVM.PartVMList.Count - 1 Then
         If ParentMachGroupVM.PartVMList.Count > 1 Then
            ParentMachGroupVM.SelPart = ParentMachGroupVM.PartVMList(ParentMachGroupVM.PartVMList.Count - 2)
         Else
            ParentMachGroupVM.SelPart = Nothing
         End If
      Else
         ParentMachGroupVM.SelPart = ParentMachGroupVM.PartVMList(Index - 1)
      End If
      ParentMachGroupVM.PartVMList.Remove(Me)
      ' aggiorno Db
      DbControllers.m_PartController.Delete(Map.refProdManagerVM.CurrProd.nProdId, ParentMachGroupVM.Id, nPartId)
      If nType = MachineType.BEAM Then
         Dim BeamParentMachGroup As MyMachGroupVM = DirectCast(ParentMachGroupVM, MyMachGroupVM)
         If Not IsNothing(BeamParentMachGroup) Then BeamParentMachGroup.ReDrawBeamMachgroup()
      End If
      ' aggiorno contatore pezzi usati in Prod
      If Not IsNothing(BTLPart) Then BTLPart.RefreshPartInProd()
      EgtDraw()
   End Sub

   Private Sub Rotate(IsPositive As Boolean)
      ' salvo posizione 
      Dim dTempPosX As Double = m_PartM.dPOSX
      Dim dTempPosY As Double = m_PartM.dPOSY
      ' tolgo il pezzo dal grezzo
      EgtRemovePartFromRawPart(nPartId)
      ' recupero layer del box
      Dim nBoxLayerId As Integer = EgtGetFirstNameInGroup(nPartId, "Box")
      ' recupero box del layer box
      Dim b3Box As New BBox3d
      EgtGetBBoxGlob(nBoxLayerId, GDB_BB.STANDARD, b3Box)
      ' se invertito lo reinverto
      Dim bFliped As Boolean = bFLIP
      If bFliped Then EgtRotate(nPartId, b3Box.Center, Vector3d.X_AX, 180, GDB_RT.GLOB)
      Dim dAng As Double = If(IsPositive, 90, -90)
      ' eseguo rotazione
      Dim bOk As Boolean = EgtRotate(nPartId, b3Box.Center, -Vector3d.Z_AX, dAng, GDB_RT.GLOB)
      If bOk Then
         Dim TempRot = m_PartM.dROT
         TempRot += dAng
         If TempRot >= 360 Then
            TempRot -= 360
         ElseIf TempRot < 0 Then
            TempRot += 360
         End If
         m_PartM.dROT = TempRot
         EgtSetInfo(nPartId, MGR_PRT_ROT, m_PartM.dROT)
      End If
      ' ripristino eventuale inversione
      If bFliped Then EgtRotate(nPartId, b3Box.Center, Vector3d.X_AX, 180, GDB_RT.GLOB)
      ' recupero box del pezzo
      Dim b3Part As New BBox3d
      EgtGetBBoxGlob(nPartId, GDB_BB.STANDARD, b3Part)
      'aggiorno box del box con rotazione
      EgtGetBBoxGlob(nBoxLayerId, GDB_BB.STANDARD, b3Box)
      ' calcolo distanza tra i box
      Dim vtDeltaBox As Vector3d = b3Box.Min - b3Part.Min   ' Vector3d.NULL
      ' calcolo posizione rispetto al riferimento
      Select Case Map.refProjectVM.BTLStructureVM.nPROJTYPE
         Case BWType.WALL
            ' se parete, valuto angolo di posizionamento
            Select Case CurrentMachine.NestingCorner
               Case MCH_CR.TL
                  'vtDeltaBox = New Vector3d(b3Box.Min.x - b3Part.Min.x, b3Box.Max.y - b3Part.Max.y, 0)
                  dTempPosY = dTempPosY - dW + dL
               Case MCH_CR.BL
                  'vtDeltaBox = b3Box.Min - b3Part.Min
                  ' non cambio posizioni
               Case MCH_CR.TR
                  'vtDeltaBox = b3Box.Max - b3Part.Max
                  dTempPosX = dTempPosX - dL + dW
                  dTempPosY = dTempPosY - dW + dL
               Case MCH_CR.BR
                  'vtDeltaBox = New Vector3d(b3Box.Max.x - b3Part.Max.x, b3Box.Min.y - b3Part.Min.y, 0)
                  dTempPosX = dTempPosX - dL + dW
            End Select
         Case Else
            ' non cambio nulla
      End Select
      ' reinserisco il pezzo nel grezzo
      EgtAddPartToRawPart(nPartId, New Point3d(dTempPosX - vtDeltaBox.x, dTempPosY - vtDeltaBox.y, 0), ParentMachGroupVM.MyMachGroupM.nRawPartId)
      ' lo riseleziono
      EgtSelectObj(nPartId)
      ' resetto validazione del pezzo
      ResetCalcPart()
      NotifyPropertyChanged(NameOf(sROT))
   End Sub

   Friend Sub SelectBTLPart()
      ' eseguo la selezione nella lista pezzi
      Dim nBTLPartId As Integer = MyMachGroupPanelM.DuploGetOriginal(nPartId)
      If Not IsNothing(nBTLPartId) Then
         Map.refProjectVM.BTLStructureVM.SetSelBTLPart(Map.refProjectVM.BTLStructureVM.BTLPartVMList.FirstOrDefault(Function(x) x.nPartId = nBTLPartId), True)
      End If
   End Sub

   Private Sub ReadProductionData()
      If IsNothing(Map.refProdManagerVM.CurrProd) OrElse IsNothing(Map.refProdManagerVM.CurrProd.nProdId) Then Return
      Dim PartModel As PartModel = DbControllers.m_PartController.FindByPartId(Map.refProdManagerVM.CurrProd.nProdId, nPartId)
      If Not IsNothing(PartModel) Then
         PartM.SetProductionState(PartModel.State)
         PartM.dtStartTime = PartModel.DtStart
         PartM.dtEndTime = PartModel.DtEnd
         ' verifico se bloccare o sbloccare duplo
         Dim bLocked As Boolean = True
         EgtDuploGetLocked(nPartId, bLocked)
         If PartModel.State <= ItemState.ND And bLocked Then
            ' recupero se Duplo da aggiornare
            Dim bDuploToUpdate As Boolean = False
            EgtGetInfo(nPartId, GDB_SI_DUPTOUPDATE, bDuploToUpdate)
            ' verifico tipo di progetto
            Dim nBtlInfoId As Integer = EgtGetFirstNameInGroup(GDB_ID.ROOT, BTLINFO)
            Dim nBWType As Integer = 0
            EgtGetInfo(nBtlInfoId, BTL_GEN_PROJTYPE, nBWType)
            Dim DuploRot As Integer = 0
            Dim DuploFlip As Integer = 0
            Dim QParams As New Dictionary(Of String, Dictionary(Of String, String))
            ' se da aggiornare, leggo info del duplo che verrebbero perse
            If bDuploToUpdate Then
               ' recupero ROT (gradi) e FLIP (gradi) per non perderli
               EgtGetInfo(nPartId, MGR_PRT_ROT, DuploRot)
               EgtGetInfo(nPartId, MGR_PRT_FLIP, DuploFlip)
               If DuploFlip <> 0 Then DuploFlip = 180
               If nBWType = BWType.WALL Then
                  ' ciclo sugli outline
                  Dim nOutlineLayer As Integer = EgtGetFirstNameInGroup(nPartId, OUTLINE)
                  If nOutlineLayer <> GDB_ID.NULL Then
                     Dim nGlobPRId As Integer = 1
                     Dim nOutlineId As Integer = EgtGetFirstInGroup(nOutlineLayer)
                     While nOutlineId <> GDB_ID.NULL
                        ' verifico che sia outline
                        Dim nPRC As Integer
                        If EgtGetInfo(nOutlineId, MGR_FTR_PRC, nPRC) Then
                           Dim nPRId As Integer = 0
                           If Not EgtGetInfo(nOutlineId, MGR_FTR_PRID, nPRId) Then
                              EgtSetInfo(nOutlineId, MGR_FTR_PRID, nGlobPRId)
                              nPRId = nGlobPRId
                              nGlobPRId += 1
                           End If
                           Dim sKey As String = nPRId & "." & nPRC
                           QParams.Add(sKey, New Dictionary(Of String, String))
                           For QIndex = 1 To 10
                              Dim QKey As String = "Q" & QIndex.ToString("D2")
                              Dim QValue As Integer = 0
                              If EgtGetInfo(nOutlineId, QKey, QValue) Then
                                 QParams(sKey).Add(QKey, QValue)
                              End If
                           Next
                        End If
                        nOutlineId = EgtGetNext(nOutlineId)
                     End While
                  End If
                  ' ciclo sulle feature
                  Dim nFeatureLayer As Integer = EgtGetFirstNameInGroup(nPartId, PROCESSINGS)
                  If nFeatureLayer <> GDB_ID.NULL Then
                     Dim nFeatureId As Integer = EgtGetFirstInGroup(nFeatureLayer)
                     While nFeatureId <> GDB_ID.NULL
                        ' verifico che sia feature
                        Dim nPRC As Integer
                        If EgtGetInfo(nFeatureId, MGR_FTR_PRC, nPRC) Then
                           Dim nPRId As Integer = 0
                           EgtGetInfo(nFeatureId, MGR_FTR_PRID, nPRId)
                           Dim sKey As String = nPRId & "." & nPRC
                           QParams.Add(sKey, New Dictionary(Of String, String))
                           For QIndex = 1 To 10
                              Dim QKey As String = "Q" & QIndex.ToString("D2")
                              Dim QValue As Integer = 0
                              If EgtGetInfo(nFeatureId, QKey, QValue) Then
                                 QParams(sKey).Add(QKey, QValue)
                              End If
                           Next
                        End If
                        nFeatureId = EgtGetNext(nFeatureId)
                     End While
                  End If
               End If
            End If
            ' disabilito impostazione modificato
            Dim DisableMgr As New DisableModifiedMgr
            ' sblocco Duplo
            EgtDuploResetLocked(nPartId)
            ' ripristino precedente impostazione modificato
            DisableMgr.ReEnable()
            ' se da aggiornare, ripristino info del duplo che verrebbero perse
            If bDuploToUpdate Then
               ' ripristino i valori di ROT e FLIP
               EgtSetInfo(nPartId, MGR_PRT_ROT, DuploRot)
               EgtSetInfo(nPartId, MGR_PRT_FLIP, DuploFlip)
               If nBWType = BWType.WALL Then
                  ' ciclo sugli outline
                  Dim nOutlineLayer As Integer = EgtGetFirstNameInGroup(nPartId, OUTLINE)
                  If nOutlineLayer <> GDB_ID.NULL Then
                     Dim nOutlineId As Integer = EgtGetFirstInGroup(nOutlineLayer)
                     While nOutlineId <> GDB_ID.NULL
                        ' verifico che sia feature
                        Dim nPRC As Integer
                        If EgtGetInfo(nOutlineId, MGR_FTR_PRC, nPRC) Then
                           Dim nPRId As Integer = 0
                           EgtGetInfo(nOutlineId, MGR_FTR_PRID, nPRId)
                           Dim sKey As String = nPRId & "." & nPRC
                           ' ripristino parametri Q
                           If QParams.ContainsKey(sKey) Then
                              For Each QPar In QParams(sKey)
                                 EgtSetInfo(nOutlineId, QPar.Key, QPar.Value)
                              Next
                           End If
                        End If
                        nOutlineId = EgtGetNext(nOutlineId)
                     End While
                  End If
                  ' ciclo sulle feature
                  Dim nFeatureLayer As Integer = EgtGetFirstNameInGroup(nPartId, PROCESSINGS)
                  If nFeatureLayer <> GDB_ID.NULL Then
                     Dim nFeatureId As Integer = EgtGetFirstInGroup(nFeatureLayer)
                     While nFeatureId <> GDB_ID.NULL
                        ' verifico che sia feature
                        Dim nPRC As Integer
                        If EgtGetInfo(nFeatureId, MGR_FTR_PRC, nPRC) Then
                           Dim nPRId As Integer = 0
                           EgtGetInfo(nFeatureId, MGR_FTR_PRID, nPRId)
                           Dim sKey As String = nPRId & "." & nPRC
                           ' ripristino parametri Q
                           If QParams.ContainsKey(sKey) Then
                              For Each QPar In QParams(sKey)
                                 EgtSetInfo(nFeatureId, QPar.Key, QPar.Value)
                              Next
                           End If
                        End If
                        nFeatureId = EgtGetNext(nFeatureId)
                     End While
                  End If
               End If
            End If
            nProduction_State = ItemState.ND
            NotifyPropertyChanged(NameOf(Background))
            If bDuploToUpdate Then
               ResetCalcTotalPart()
            End If
         ElseIf PartModel.State > ItemState.ND And Not bLocked Then
            ' disabilito impostazione modificato
            Dim DisableMgr As New DisableModifiedMgr
            EgtDuploSetLocked(nPartId)
            ' ripristino precedente impostazione modificato
            DisableMgr.ReEnable()
         End If
      End If
   End Sub

#End Region    ' Part

#Region "Feature"

   Protected Overrides Sub CreateBTLFeatureVMList()
      Dim all As List(Of BTLFeatureVM) = (From BTLFeatureM In m_PartM.GetBTLFeatures()
                                          Select New BTLFeatureVM(BTLFeatureM)).ToList()

      For Each BTLFeatureVM As BTLFeatureVM In all
         AddHandler BTLFeatureVM.PropertyChanged, AddressOf OnBTLFeatureVMPropertyChanged
         If ParentMachGroupVM.nType = BWType.WALL Then
            For Each BTLParamVM As BTLParamVM In BTLFeatureVM.QBTLParamVMList
               AddHandler BTLParamVM.PropertyChanged, AddressOf OnBTLQParamVMPropertyChanged
            Next
            AddHandler BTLFeatureVM.QBTLParamVMList.CollectionChanged, AddressOf OnBTLQParamVMListChanged
         End If
      Next

      m_FeatureVMList = New ObservableCollection(Of Core.BTLFeatureVM)(all)
      AddHandler m_FeatureVMList.CollectionChanged, AddressOf OnBTLFeatureVMListChanged

   End Sub

   Friend Sub ResetCalcTotalPart()
      ResetCalcPart()
      For Each Feature In FeatureVMList
         DirectCast(Feature, BTLFeatureVM).ResetCalcFeature()
      Next
   End Sub

#End Region    ' Feature

#End Region    ' METHODS

#Region "COMMANDS"

#Region "BackRotation"

   Public ReadOnly Property BackRotation_Command As ICommand
      Get
         If m_cmdBackRotation Is Nothing Then
            m_cmdBackRotation = New Command(AddressOf BackRotation)
         End If
         Return m_cmdBackRotation
      End Get
   End Property

   Public Sub BackRotation()
      ' se sta calcolando, esco subito
      If Map.refProjectVM.bCalcRunning Then Return
      ' se MachGroup gia' mandato in produzione, esco
      If m_ParentMachGroupVM.nProduction_State >= ItemState.Assigned Then Return
      Rotate(False)
      EgtDraw()
   End Sub

#End Region ' BackRotation

#Region "ForwardRotation"

   Public ReadOnly Property ForwardRotation_Command As ICommand
      Get
         If m_cmdForwardRotation Is Nothing Then
            m_cmdForwardRotation = New Command(AddressOf ForwardRotation)
         End If
         Return m_cmdForwardRotation
      End Get
   End Property

   Public Sub ForwardRotation()
      If Map.refProjectVM.bCalcRunning Then Return
      ' se MachGroup gia' mandato in produzione, esco
      If m_ParentMachGroupVM.nProduction_State >= ItemState.Assigned Then Return
      Rotate(True)
      EgtDraw()
   End Sub

#End Region ' ForwardRotation

#End Region    ' COMMANDS

#Region "EVENTS"

   Protected Overrides Sub OnBTLFeatureVMPropertyChanged(sender As Object, e As PropertyChangedEventArgs)
      Select Case e.PropertyName
         Case NameOf(sender.bDO)
            ' setto pezzo da ricalcolare
            ResetCalcTotalPart()
      End Select
   End Sub

   Private Sub OnBTLQParamVMListChanged(sender As Object, e As NotifyCollectionChangedEventArgs)
      If Not IsNothing(e.NewItems) AndAlso e.NewItems.Count > 0 Then
         For Each BTLParamVM As BTLParamVM In e.NewItems
            AddHandler BTLParamVM.PropertyChanged, AddressOf OnBTLQParamVMPropertyChanged
         Next
      End If
      If Not IsNothing(e.OldItems) AndAlso e.OldItems.Count > 0 Then
         For Each BTLParamVM As BTLParamVM In e.OldItems
            RemoveHandler BTLParamVM.PropertyChanged, AddressOf OnBTLQParamVMPropertyChanged
         Next
      End If
   End Sub

   Private Sub OnBTLQParamVMPropertyChanged(sender As Object, e As PropertyChangedEventArgs)
      Select Case e.PropertyName
         Case NameOf(sender.dValue), NameOf(sender.sValue)
            ' setto pezzo da ricalcolare
            ResetCalcTotalPart()
      End Select
   End Sub

#End Region    ' EVENTS

End Class
