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

Public Class MyMachGroupVM
   Inherits Core.MyMachGroupVM

#Region "FIELDS & PROPERTIES"

#Region "General"

   Private m_RefreshPartList_Timer As New DispatcherTimer

   Public Overrides Property SelPart As Core.PartVM
      Get
         Return m_SelPart
      End Get
      Set(value As Core.PartVM)
         m_SelPart = value
         ' seleziono pezzo
         EgtDeselectAll()
         If Not IsNothing(value) Then
            EgtSelectObj(SelPart.nPartId)
            DirectCast(m_SelPart, PartVM).SelectBTLPart()
         End If
         EgtDraw()
         NotifyPropertyChanged(NameOf(SelPart))
      End Set
   End Property
   Friend Sub SetSelPart(value As Core.PartVM)
      m_SelPart = value
      EgtDeselectAll()
      EgtSelectObj(SelPart.nPartId)
      NotifyPropertyChanged(NameOf(SelPart))
   End Sub

   Public Property sL As String
      Get
         Return LenToString(MyMachGroupM.dL, 3)
      End Get
      Set(value As String)
         Dim dValue As Double
         If StringToLenAdv(value, dValue, True) Then
            Dim nRawPartId As Integer = EgtGetFirstRawPart()
            If dValue <> MyMachGroupM.dL Then
               Select Case nType
                  Case BWType.BEAM
                     ' se c'e' almeno un pezzo
                     If m_PartVMList.Count > 0 Then
                        ' verifico se la dimensione e' maggiore dello spazio occupato dai pezzi
                        Dim dTotLength As Double = 0
                        For Each Part In m_PartVMList
                           dTotLength += Part.dL + Part.dOffset
                        Next
                        If dValue < dTotLength Then
                           dValue = dTotLength
                        End If
                     End If
                     EgtSetInfo(Id, MGR_RPT_BARLEN, dValue)
                     If Not ReDrawBeamMachgroup() Then
                        ' rispristino vecchio valore
                        EgtSetInfo(Id, MGR_RPT_BARLEN, MyMachGroupM.dL)
                        ReDrawBeamMachgroup()
                        NotifyPropertyChanged(NameOf(sL))
                     Else
                        MyMachGroupM.dL = dValue
                     End If
                     EgtDraw()
                  Case BWType.WALL
                     ' se c'e' almeno un pezzo
                     If m_PartVMList.Count > 0 Then
                        ' verifico se la dimensione e' maggiore del box minimo dei pezzi
                        Dim b3Parts As New BBox3d
                        Dim nBoxLayerId As Integer = EgtGetFirstNameInGroup(m_PartVMList(0).nPartId, "Box")
                        EgtGetBBoxGlob(nBoxLayerId, GDB_BB.EXACT, b3Parts)
                        For PartIndex = 1 To m_PartVMList.Count - 1
                           Dim b3Part As New BBox3d
                           nBoxLayerId = EgtGetFirstNameInGroup(m_PartVMList(PartIndex).nPartId, "Box")
                           EgtGetBBoxGlob(nBoxLayerId, GDB_BB.EXACT, b3Part)
                           b3Parts.Add(b3Part)
                        Next
                        Dim b3RawPart As New BBox3d
                        EgtGetRawPartBBox(nRawPartId, b3RawPart)
                        Dim dMinValue As Double = 0
                        Select Case CurrentMachine.NestingCorner
                           Case MCH_CR.BL, MCH_CR.TL
                              dMinValue = b3Parts.DimX + (b3Parts.Min.x - b3RawPart.Min.x) + WarehouseHelper.GetKerf()
                           Case MCH_CR.BR, MCH_CR.TR
                              dMinValue = b3Parts.DimX + (b3RawPart.Max.x - b3Parts.Max.x) + WarehouseHelper.GetKerf()
                        End Select
                        If dValue < dMinValue Then
                           dValue = dMinValue
                        End If
                     End If
                     If EgtModifyRawPartSize(nRawPartId, dValue, MyMachGroupM.dW, MyMachGroupM.dH) Then
                        ' riporto il grezzo nell'angolo tavola di origine
                        Dim b3Tab As New BBox3d
                        EgtGetTableArea(1, b3Tab)
                        Dim p3OrigOnTab As Point3d
                        Select Case CurrentMachine.OrigCorner
                           Case MCH_CR.BL
                              p3OrigOnTab = New Point3d(CurrentMachine.OrigOffsX, CurrentMachine.OrigOffsY, 0)
                           Case MCH_CR.BR
                              p3OrigOnTab = New Point3d(b3Tab.DimX() - CurrentMachine.OrigOffsX, CurrentMachine.OrigOffsY, 0)
                           Case MCH_CR.TL
                              p3OrigOnTab = New Point3d(CurrentMachine.OrigOffsX, b3Tab.DimY() - CurrentMachine.OrigOffsY, 0)
                           Case MCH_CR.TR
                              p3OrigOnTab = New Point3d(b3Tab.DimX() - CurrentMachine.OrigOffsX, b3Tab.DimY() - CurrentMachine.OrigOffsY, 0)
                        End Select
                        EgtMoveToCornerRawPart(nRawPartId, p3OrigOnTab, CurrentMachine.OrigCorner)
                        ' sposto tutti i pezzi di quanto si e' accorciato il grezzo
                        If CurrentMachine.NestingCorner = MCH_CR.TR OrElse CurrentMachine.NestingCorner = MCH_CR.BR Then
                           For Each Part In m_PartVMList
                              EgtMovePartInRawPart(Part.nPartId, New Vector3d(dValue - MyMachGroupM.dL, 0, 0))
                           Next
                        End If
                        ' ripristino eventuale PosZ
                        If MyMachGroupM.dPosZ >= 0 Then
                           EgtMoveRawPart(nRawPartId, New Vector3d(0, 0, MyMachGroupM.dPosZ))
                        End If
                        EgtSetInfo(Id, MGR_RPT_PANELLEN, dValue)
                        EgtDraw()
                        MyMachGroupM.dL = dValue
                     Else
                        NotifyPropertyChanged(NameOf(sL))
                     End If
               End Select
               UpdateUsage()
               ResetCalcTotalMachGroup()
            End If
         End If
      End Set
   End Property

   Public Property sW As String
      Get
         Return LenToString(MyMachGroupM.dW, 3)
      End Get
      Set(value As String)
         Dim dValue As Double
         If StringToLenAdv(value, dValue, True) Then
            If nType = BWType.WALL Then
               Dim nRawPartId As Integer = EgtGetFirstRawPart()
               If dValue <> MyMachGroupM.dW Then
                  ' se c'e' almeno un pezzo
                  If m_PartVMList.Count > 0 Then
                     ' verifico se la dimensione e' maggiore del box minimo dei pezzi
                     Dim b3Parts As New BBox3d
                     Dim nBoxLayerId As Integer = EgtGetFirstNameInGroup(m_PartVMList(0).nPartId, "Box")
                     EgtGetBBoxGlob(nBoxLayerId, GDB_BB.EXACT, b3Parts)
                     For PartIndex = 1 To m_PartVMList.Count - 1
                        Dim b3Part As New BBox3d
                        nBoxLayerId = EgtGetFirstNameInGroup(m_PartVMList(PartIndex).nPartId, "Box")
                        EgtGetBBoxGlob(nBoxLayerId, GDB_BB.EXACT, b3Part)
                        b3Parts.Add(b3Part)
                     Next
                     Dim b3RawPart As New BBox3d
                     EgtGetRawPartBBox(nRawPartId, b3RawPart)
                     Dim dMinValue As Double = 0
                     Select Case CurrentMachine.NestingCorner
                        Case MCH_CR.BL, MCH_CR.BR
                           dMinValue = b3Parts.DimY + (b3Parts.Min.y - b3RawPart.Min.y) + WarehouseHelper.GetKerf()
                        Case MCH_CR.TL, MCH_CR.TR
                           dMinValue = b3Parts.DimY + (b3RawPart.Max.y - b3Parts.Max.y) + WarehouseHelper.GetKerf()
                     End Select
                     If dValue < dMinValue Then
                        dValue = dMinValue
                     End If
                  End If
                  If EgtModifyRawPartSize(nRawPartId, MyMachGroupM.dL, dValue, MyMachGroupM.dH) Then
                     ' riporto il grezzo nell'angolo tavola di origine
                     Dim b3Tab As New BBox3d
                     EgtGetTableArea(1, b3Tab)
                     Dim p3OrigOnTab As Point3d
                     Select Case CurrentMachine.OrigCorner
                        Case MCH_CR.BL
                           p3OrigOnTab = New Point3d(CurrentMachine.OrigOffsX, CurrentMachine.OrigOffsY, 0)
                        Case MCH_CR.BR
                           p3OrigOnTab = New Point3d(b3Tab.DimX() - CurrentMachine.OrigOffsX, CurrentMachine.OrigOffsY, 0)
                        Case MCH_CR.TL
                           p3OrigOnTab = New Point3d(CurrentMachine.OrigOffsX, b3Tab.DimY() - CurrentMachine.OrigOffsY, 0)
                        Case MCH_CR.TR
                           p3OrigOnTab = New Point3d(b3Tab.DimX() - CurrentMachine.OrigOffsX, b3Tab.DimY() - CurrentMachine.OrigOffsY, 0)
                     End Select
                     EgtMoveToCornerRawPart(nRawPartId, p3OrigOnTab, CurrentMachine.OrigCorner)
                     ' sposto tutti i pezzi di quanto si e' accorciato il grezzo
                     If CurrentMachine.NestingCorner = MCH_CR.TR OrElse CurrentMachine.NestingCorner = MCH_CR.TL Then
                        For Each Part In m_PartVMList
                           EgtMovePartInRawPart(Part.nPartId, New Vector3d(0, dValue - MyMachGroupM.dW, 0))
                        Next
                     End If
                     ' ripristino eventuale PosZ
                     If MyMachGroupM.dPosZ >= 0 Then
                        EgtMoveRawPart(nRawPartId, New Vector3d(0, 0, MyMachGroupM.dPosZ))
                     End If
                     EgtSetInfo(Id, MGR_RPT_PANELWIDTH, dValue)
                     EgtDraw()
                     MyMachGroupM.dW = dValue
                  Else
                     NotifyPropertyChanged(NameOf(sW))
                  End If
                  UpdateUsage()
                  ResetCalcTotalMachGroup()
               End If
            End If
         End If
      End Set
   End Property

   Public Property sH As String
      Get
         Return LenToString(MyMachGroupM.dH, 3)
      End Get
      Set(value As String)
         Dim dValue As Double
         If StringToLenAdv(value, dValue, True) Then
            MyMachGroupM.dH = value
         End If
      End Set
   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 sStartCut As String
      Get
         Return LenToString(MyMachGroupM.dStartCut, 3)
      End Get
      Set(value As String)
         Dim dValue As Double
         If StringToLenAdv(value, dValue, True) Then
            Dim dOldValue As Double = MyMachGroupM.dStartCut
            ' verifico se con il nuovo StartCut tutti i pezzi stanno nella barra
            Dim dTotLength As Double = 0
            For PartIndex = 0 To m_PartVMList.Count - 1
               Dim Part As PartVM = m_PartVMList(PartIndex)
               If PartIndex = 0 Then
                  dTotLength += Part.dL + dValue
               Else
                  dTotLength += Part.dL + Part.dOffset
               End If
            Next
            If Me.dL < dTotLength Then
               NotifyPropertyChanged(NameOf(sStartCut))
               Return
            End If
            MyMachGroupM.dStartCut = dValue
            If Not ReDrawBeamMachgroup() Then
               ' rispristino vecchio valore
               MyMachGroupM.dStartCut = dOldValue
               ReDrawBeamMachgroup()
               NotifyPropertyChanged(NameOf(sStartCut))
            End If
            EgtDraw()
            If PartVMList.Count > 0 Then
               Dim Beam As PartVM = PartVMList(0)
               Beam.PartM.UpdateOffset()
               Beam.NotifyPropertyChanged(NameOf(Beam.sOffset))
            End If
            ' resetto validazione del pezzo primo pezzo
            If PartVMList.Count > 0 Then
               PartVMList(0).ResetCalcPart()
            Else
               ResetCalcMachGroup()
            End If
            UpdateUsage()
         Else
            NotifyPropertyChanged(NameOf(sStartCut))
         End If
      End Set
   End Property

#End Region    ' Beam

#Region "Wall"

   Public Property sPosZ As String
      Get
         Return LenToString(MyMachGroupM.dPosZ, 3)
      End Get
      Set(value As String)
         Dim dValue As Double
         If StringToLenAdv(value, dValue, True) Then
            Dim nRawPartId As Integer = EgtGetFirstRawPart()
            If Math.Abs(dValue - MyMachGroupM.dPosZ) > EPS_SMALL Then
               Select Case nType
                  Case BWType.BEAM
                     ' non utilizzato
                  Case BWType.WALL
                     ' se operazione di spostamento in z ha successo
                     If dValue >= 0 AndAlso EgtMoveRawPart(nRawPartId, New Vector3d(0, 0, dValue - MyMachGroupM.dPosZ)) Then
                        EgtSetInfo(Id, MGR_RPT_PANELPOSZ, dValue)
                        EgtDraw()
                        MyMachGroupM.dPosZ = dValue
                     Else
                        NotifyPropertyChanged(NameOf(sPosZ))
                     End If
               End Select
               ResetCalcTotalMachGroup()
            End If
         End If
      End Set
   End Property

#End Region    ' Wall

#End Region    ' FIELDS & PROPERTIES

#Region "CONSTRUCTORS"

   Sub New(MyMachGroupM As MyMachGroupM)
      MyBase.New(MyMachGroupM)
      ' aggiorno stato di produzione
      ReadProductionState()
      m_RefreshPartList_Timer.Interval = TimeSpan.FromMilliseconds(50)
      AddHandler m_RefreshPartList_Timer.Tick, AddressOf RefreshPartList_Tick
   End Sub

#End Region    ' CONSTRUCTORS

#Region "METHODS"

#Region "Machgroup"

   Friend Sub SetSelPart(PartVM As PartVM)
      m_SelPart = PartVM
      NotifyPropertyChanged(NameOf(SelPart))
   End Sub

   Public Overrides Sub RefreshGroupData()

   End Sub

   Public Shadows Function Copy(Optional Qty As Integer = 1) As Core.MyMachGroupVM
      Dim BeamWallMachGroup As MyMachGroupVM = Nothing
      If nType = BWType.BEAM Then
         EgtResetCurrMachGroup()
         ' recupero lista dei pezzi BTL originali
         Dim PartList As New List(Of BTLPartVM)
         For Each Part In m_PartVMList
            PartList.Add(BTLPartVM.RetrieveBTLPartFromPart(Part.nPartId))
         Next
         ' verifico che nessun pezzo da copiare abbia raggiunto il numero massimo
         If Not VerifyPartCount(PartList, Qty) Then Return Nothing
         ' creo nuovi gruppi di lavorazione
         For Ind = 1 To Qty
            Map.refMachGroupPanelVM.AddMachGroup()
            Dim nCurrMachGroup As Integer = EgtGetCurrMachGroup()
            Dim sCurrMachGroupName As String = ""
            EgtGetMachGroupName(nCurrMachGroup, sCurrMachGroupName)
            ' scrivo dati per variabili P di comunicazione con la macchina in gruppo di lavorazione
            EgtSetInfo(nCurrMachGroup, MGR_RPT_PRODID, Map.refProdManagerVM.CurrProd.nProdId)
            EgtSetInfo(nCurrMachGroup, MGR_RPT_MATERIAL, sMATERIAL)
            EgtSetInfo(nCurrMachGroup, MGR_RPT_PATTID, nCurrMachGroup)
            ' scrivo dati costruzione grezzo in gruppo di lavorazione
            EgtSetInfo(nCurrMachGroup, MGR_RPT_BARLEN, dL)
            For Index = 0 To m_PartVMList.Count - 1
               ' creo copia del pezzo
               Dim nPartDuploId As Integer = EgtDuploNew(PartList(Index).nPartId)
               ' elimino valori calcolo dell'originale
               MyMachGroupPanelVM.DuploRemoveProjCalc(nPartDuploId)
               ' lo rendo std
               EgtSetMode(nPartDuploId, GDB_MD.STD)
               ' scrivo dati costruzione grezzo in gruppo di lavorazione
               EgtSetInfo(nCurrMachGroup, MGR_RPT_PART & (Index + 1), nPartDuploId & "," & m_PartVMList(Index).sPOSX)
            Next
            BeamWallMachGroup = Map.refMachGroupPanelVM.GetLastMachGroup()
            ' eseguo script creazione grezzo
            Dim sLogPath As String = Map.refMainWindowVM.MainWindowM.sTempDir & "\RawPartLog.txt"
            If Not ExecBeam(sLogPath, Map.refMachinePanelVM.SelectedMachine.Name, CalcIntegration.CmdTypes.RAWPART, False) Then
               BeamWallMachGroup.DeleteMachGroup()
               Dim LogFile As String() = File.ReadAllLines(sLogPath)
               If LogFile.Count >= 2 AndAlso Not IsNothing(LogFile(1)) Then
                  MessageBox.Show(LogFile(1), EgtMsg(30007), MessageBoxButton.OK, MessageBoxImage.Error)
               End If
               Return Nothing
            End If
            ' aggiorno contatore pezzi usati in Prod
            For Each Part In PartList
               Part.RefreshPartInProd()
            Next
            'aggiorno lista pezzi
            BeamWallMachGroup.MyMachGroupM.RefreshPartList()
            BeamWallMachGroup.MyMachGroupM.RefreshGroupData()
            ' aggiorno dati ultilizzo barra
            BeamWallMachGroup.UpdateUsage()
            Core.ViewPanelVM.BWSetView(VT.ISO_SW, False)
         Next
         ' se pareti
      Else
         ' recupero lista dei pezzi BTL originali
         Dim CopyPartList As New List(Of CopyPart)
         Dim PartList As New List(Of BTLPartVM)
         For Each Part As PartVM In m_PartVMList
            Dim BTLPartVM As BTLPartVM = BTLPartVM.RetrieveBTLPartFromPart(Part.nPartId)
            CopyPartList.Add(New CopyPart(BTLPartVM, Part.sPOSX, Part.sPOSY, Part.dROT, Part.nFLIP))
            PartList.Add(BTLPartVM)
         Next

         'Dim sPartArray(m_PartVMList.Count - 1) As String
         '' ciclo per salvare in un array di stringhe i valori di POSX e POSY prima di resettare
         'Dim ind As Integer = 0
         'For Each Part In m_PartVMList
         '   sPartArray(ind) = Part.sPOSX & "," & Part.sPOSY & "," & 0 & "," & 0
         '   ind += 1
         'Next
         EgtResetCurrMachGroup()
         '' recupero lista dei pezzi BTL originali
         'Dim PartList As New List(Of BTLPartVM)
         'For Each Part In m_PartVMList
         '   PartList.Add(BTLPartVM.RetrieveBTLPartFromPart(Part.nPartId))
         'Next
         ' verifico che nessun pezzo da copiare abbia raggiunto il numero massimo
         If Not VerifyPartCount(PartList, Qty) Then Return Nothing
         ' creo nuovi gruppi di lavorazione
         For ind = 1 To Qty
            Map.refMachGroupPanelVM.AddMachGroup()
            Dim nCurrMachGroup As Integer = EgtGetCurrMachGroup()
            Dim sCurrMachGroupName As String = ""
            EgtGetMachGroupName(nCurrMachGroup, sCurrMachGroupName)
            ' scrivo dati per variabili P di comunicazione con la macchina in gruppo di lavorazione
            EgtSetInfo(nCurrMachGroup, MGR_RPT_PRODID, Map.refProdManagerVM.CurrProd.nProdId)
            EgtSetInfo(nCurrMachGroup, MGR_RPT_MATERIAL, sMATERIAL)
            EgtSetInfo(nCurrMachGroup, MGR_RPT_PATTID, nCurrMachGroup)
            ' scrivo dati costruzione grezzo in gruppo di lavorazione
            EgtSetInfo(nCurrMachGroup, MGR_RPT_PANELLEN, dL)
            EgtSetInfo(nCurrMachGroup, MGR_RPT_PANELWIDTH, dW)
            For Index = 0 To CopyPartList.Count - 1
               Dim CopyPart As CopyPart = CopyPartList(Index)
               ' creo copia del pezzo
               Dim nPartDuploId As Integer = EgtDuploNew(CopyPart.BTLPart.nPartId)
               ' elimino valori calcolo dell'originale
               MyMachGroupPanelVM.DuploRemoveProjCalc(nPartDuploId)
               ' lo rendo std
               EgtSetMode(nPartDuploId, GDB_MD.STD)
               ' annullo eventuale inversione del pezzo originale
               Dim b3Duplo As New BBox3d
               EgtGetBBoxGlob(nPartDuploId, GDB_BB.STANDARD, b3Duplo)
               If CopyPart.BTLPart.nINVERTED > 0 Then
                  EgtRotate(nPartDuploId, b3Duplo.Center(), Vector3d.X_AX, 180, GDB_RT.GLOB)
               End If
               ' calcolo rotazione
               Dim dRot As Double = CopyPart.dRot - CopyPart.BTLPart.nROTATED
               If dRot <> 0 Then
                  EgtRotate(nPartDuploId, b3Duplo.Center(), -Vector3d.Z_AX, dRot, GDB_RT.GLOB)
               End If
               ' effettuo eventuale flip
               If CopyPart.nFlip > 0 Then
                  EgtRotate(nPartDuploId, b3Duplo.Center(), Vector3d.X_AX, 180, GDB_RT.GLOB)
               End If
               EgtSetInfo(nPartDuploId, MGR_PRT_ROT, CopyPart.dRot)
               EgtSetInfo(nPartDuploId, MGR_PRT_FLIP, CopyPart.nFlip)
               ' scrivo dati costruzione grezzo in gruppo di lavorazione
               EgtSetInfo(nCurrMachGroup, MGR_RPT_PART & (Index + 1), nPartDuploId & "," & CopyPart.sPosX & "," & CopyPart.sPosY & ",0,0")
            Next
            BeamWallMachGroup = Map.refMachGroupPanelVM.GetLastMachGroup()
            ' eseguo script creazione grezzo
            Dim sLogPath As String = Map.refMainWindowVM.MainWindowM.sTempDir & "\RawPartLog.txt"
            If Not ExecWall(sLogPath, Map.refMachinePanelVM.SelectedMachine.Name, CalcIntegration.CmdTypes.RAWPART, False, False) Then
               BeamWallMachGroup.DeleteMachGroup()
               Dim LogFile As String() = File.ReadAllLines(sLogPath)
               If LogFile.Count >= 2 AndAlso Not IsNothing(LogFile(1)) Then
                  MessageBox.Show(LogFile(1), EgtMsg(30007), MessageBoxButton.OK, MessageBoxImage.Error)
               End If
               Return Nothing
            End If
            ' aggiorno contatore pezzi usati in Prod
            For Each Part In PartList
               Part.RefreshPartInProd()
            Next
            'aggiorno lista pezzi
            BeamWallMachGroup.MyMachGroupM.RefreshPartList()
            BeamWallMachGroup.MyMachGroupM.RefreshGroupData()
            ' aggiorno dati ultilizzo barra
            BeamWallMachGroup.UpdateUsage()
            Core.ViewPanelVM.BWSetView(VT.TOP, False)
         Next
      End If
      Return BeamWallMachGroup
   End Function

   Friend Function ReDrawBeamMachgroup() As Boolean
      ' scrivo dati di tutti i pezzi
      Dim dPosX As Double = MyMachGroupM.dStartCut
      Dim nIndex As Integer
      For nIndex = 0 To PartVMList.Count - 1
         If nIndex <> 0 Then
            dPosX += PartVMList(nIndex).PartM.dOffset
         End If
         PartVMList(nIndex).dPOSX = dPosX
         EgtSetInfo(Id, MGR_RPT_PART & nIndex + 1, PartVMList(nIndex).nPartId & "," & DoubleToString(dPosX, 3))
         dPosX += PartVMList(nIndex).dL
      Next
      ' elimino eventuali successive info pezzi di troppo
      nIndex = PartVMList.Count + 1
      Dim sTemp As String = ""
      While EgtGetInfo(Id, MGR_RPT_PART & nIndex, sTemp)
         EgtSetInfo(Id, MGR_RPT_PART & nIndex, "")
         nIndex += 1
      End While
      ' elimino vecchio grezzo ed eseguo script creazione nuovo
      Dim nRawId As Integer = EgtGetFirstRawPart()
      While nRawId <> GDB_ID.NULL
         EgtRemovePartFromRawPart(EgtGetFirstPartInRawPart(nRawId))
         EgtRemoveRawPart(nRawId)
         nRawId = EgtGetFirstRawPart()
      End While
      Dim sLogPath As String = Map.refMainWindowVM.MainWindowM.sTempDir & "\RawPartLog.txt"
      Return ExecBeam(sLogPath, Map.refMachinePanelVM.SelectedMachine.Name, CalcIntegration.CmdTypes.RAWPART, False)
   End Function

   Friend Sub MoveBeam(Beam As PartVM, MoveDirection As MoveDirections)
      Dim nBeamIndex As Integer = PartVMList.IndexOf(Beam)
      If nBeamIndex = 0 AndAlso MoveDirection = MoveDirections.UP Then Return
      If nBeamIndex = PartVMList.Count - 1 AndAlso MoveDirection = MoveDirections.DOWN Then Return
      ' se pezzo mosso diventa primo
      Dim FirstBeam As PartVM = PartVMList(0)
      If (nBeamIndex = 1 AndAlso MoveDirection = MoveDirections.UP) OrElse (nBeamIndex = 0 AndAlso MoveDirection = MoveDirections.DOWN) Then
         '' resetto offset per vecchio primo
         FirstBeam.ResetOffset()
      End If
      PartVMList.Move(nBeamIndex, nBeamIndex + MoveDirection)
      ReDrawBeamMachgroup()
      ' aggiorno offset primo pezzo
      PartVMList(0).PartM.UpdateOffset()
      PartVMList(0).NotifyPropertyChanged(NameOf(FirstBeam.sOffset))
   End Sub

   Friend Sub ReorderBeam()
      Dim TempPartList = PartVMList.OrderBy(Function(x) x.dL).ToList()
      ' verifico se sono già in oridne
      Dim bSort As Boolean = True
      For PartIndex = 0 To PartVMList.Count - 1
         If PartVMList(PartIndex).nPartId <> TempPartList(PartIndex).nPartId Then
            bSort = False
            Exit For
         End If
      Next
      If bSort Then Return
      ' resetto offset primo pezzo
      Dim FirstBeam As PartVM = PartVMList(0)
      FirstBeam.ResetOffset()
      For PartIndex = 0 To TempPartList.Count - 1
         If PartVMList(PartIndex).nPartId <> TempPartList(PartIndex).nPartId Then
            PartVMList.Move(PartVMList.IndexOf(TempPartList(PartIndex)), PartIndex)
         End If
      Next
      ReDrawBeamMachgroup()
      ' aggiorno offset primo pezzo
      FirstBeam.PartM.UpdateOffset()
      FirstBeam.NotifyPropertyChanged(NameOf(FirstBeam.sOffset))
   End Sub

   Private Function VerifyPartCount(SelParts As List(Of BTLPartVM), Optional Qty As Integer = 1) As Boolean
      Dim sPartToAdd As String = "Raggiunto numero di pezzi da produrre per:"
      Dim bPartToAdd As Boolean = False
      For Each Part In SelParts
         ' verifico se ci sono pezzi da aggiungere
         If Not Part.CanAddPartToCount(Qty) Then
            bPartToAdd = True
            sPartToAdd &= Environment.NewLine & "- PDN" & Part.nPDN & " | BTL QTY " & Part.nCNT & " | ADDED QTY " & Part.nADDED
         End If
      Next
      sPartToAdd &= Environment.NewLine & "Aggiungerli?"
      If bPartToAdd Then
         If MessageBox.Show(sPartToAdd, "", MessageBoxButton.YesNo, MessageBoxImage.Question) = MessageBoxResult.Yes Then
            For Each Part In SelParts
               If Not Part.CanAddPartToCount() Then Part.AddNewPartToAdded()
            Next
         Else
            Return False
         End If
      End If
      Return True
   End Function

   Private Sub ReadProductionState()
      If IsNothing(Map.refProdManagerVM.CurrProd) OrElse IsNothing(Map.refProdManagerVM.CurrProd.nProdId) Then Return
      Dim MachGroupModel As MachGroupModel = DbControllers.m_MachGroupController.FindByMachGroupId(Map.refProdManagerVM.CurrProd.nProdId, Id)
      If Not IsNothing(MachGroupModel) Then
         If Not String.IsNullOrEmpty(MachGroupModel.SupervisorId) Then
            SetSupervisorId(MachGroupModel.SupervisorId)
         End If
         nProduction_State = MachGroupModel.State
         dtStartTime = MachGroupModel.DtStart
         dtEndTime = MachGroupModel.DtEnd
      End If
   End Sub

   Friend Sub ResetCalcTotalMachGroup()
      ResetCalcMachGroup()
      For Each Part In PartVMList
         Part.ResetCalcPart()
         For Each Feature As BTLFeatureVM In Part.FeatureVMList
            Feature.ResetCalcFeature()
         Next
      Next
   End Sub

   Public Sub ResetSupervisorId()
      ' resetto stato per MachGroup
      nProduction_State = ItemState.ND
      SetSupervisorId("")
      Dim bTotDuploToUpdate As Boolean = False
      Dim bTotIsModified As Boolean = False
      ' sblocco duplo di tutti i part
      For Each Part In PartVMList
         ' recupero se Duplo da aggiornare
         Dim bDuploToUpdate As Boolean = False
         If EgtGetInfo(Part.nPartId, GDB_SI_DUPTOUPDATE, bDuploToUpdate) AndAlso bDuploToUpdate Then
            bTotDuploToUpdate = True
         End If
         ' 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(Part.nPartId, MGR_PRT_ROT, DuploRot)
            EgtGetInfo(Part.nPartId, MGR_PRT_FLIP, DuploFlip)
            If DuploFlip <> 0 Then DuploFlip = 180
            If nBWType = BWType.WALL Then
               ' ciclo sugli outline
               Dim nOutlineLayer As Integer = EgtGetFirstNameInGroup(Part.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
                           bTotIsModified = True
                           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(Part.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(Part.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(Part.nPartId, MGR_PRT_ROT, DuploRot)
            EgtSetInfo(Part.nPartId, MGR_PRT_FLIP, DuploFlip)
            If nBWType = BWType.WALL Then
               ' ciclo sugli outline
               Dim nOutlineLayer As Integer = EgtGetFirstNameInGroup(Part.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(Part.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
         Part.nProduction_State = ItemState.ND
         Part.NotifyPropertyChanged(NameOf(Part.Background))
         If bDuploToUpdate Then
            Dim Duplo As PartVM = CALCPanelVM.GetPartVMFromPartId(Part.nPartId)
            Duplo.ResetCalcTotalPart()
         End If
      Next
      If bTotDuploToUpdate Then
         m_RefreshPartList_Timer.Start()
      End If
      If bTotIsModified Then
         Dim CurrFilePath As String = ""
         EgtGetCurrFilePath(CurrFilePath)
         EgtSaveFile(CurrFilePath, NGE.CMPTEXT)
      End If
      NotifyPropertyChanged(NameOf(IsReadOnly))
      NotifyPropertyChanged(NameOf(Background))
   End Sub

   Private Sub RefreshPartList_Tick()
      m_RefreshPartList_Timer.Stop()
      Dim nCurrMachGroupId As Integer = EgtGetCurrMachGroup()
      EgtSetCurrMachGroup(Id)
      DirectCast(MachGroupM, MyMachGroupM).RefreshPartList()
      EgtSetCurrMachGroup(nCurrMachGroupId)
   End Sub

#End Region    ' Machgroup

#Region "Parts"

   Protected Overrides Sub CreatePartVMList()
      Dim all As List(Of PartVM) = (From PartM In MyMachGroupM.GetParts()
                                    Select New PartVM(PartM, Me)).ToList()

      For Each PartVM As PartVM In all
         AddHandler PartVM.PropertyChanged, AddressOf OnPartVMPropertyChanged
      Next

      m_PartVMList = New ObservableCollection(Of Core.PartVM)(all)
      AddHandler m_PartVMList.CollectionChanged, AddressOf OnPartVMListChanged
   End Sub

   Public Overrides Sub RefreshPartList()
      If nType = BWType.BEAM Then
         ' leggo StartCut da posizione primo pezzo
         Dim sInfo As String = ""
         Dim sSplitInfo() As String
         Dim bFound As Boolean = False
         EgtGetInfo(Id, MGR_RPT_PART & 1, sInfo)
         If Not String.IsNullOrWhiteSpace(sInfo) Then
            sSplitInfo = sInfo.Split(","c)
            StringToDoubleAdv(sSplitInfo(1), MyMachGroupM.dStartCut)
         Else
            MyMachGroupM.dStartCut = 0
         End If
      End If
   End Sub

#End Region    ' Parts

#End Region    ' METHODS

#Region "COMMANDS"

#Region "DeleteMachGroup"

   ' Manage the MainWindow_Unloaded event. This method is invoked by the cmdMainWindow_Unloaded.
   Public Overrides Sub DeleteMachGroup(Optional bMultipleCommand As Boolean = False)
      If EgtSetCurrMachGroup(Me.Id) Then
         ' elimino tutte le copie
         Dim nRawPartId As Integer = EgtGetFirstRawPart()
         If nType = BWType.BEAM Then
            Dim nBeamId As Integer = EgtGetFirstPartInRawPart(nRawPartId)
            While nRawPartId <> GDB_ID.NULL
               If EgtRemovePartFromRawPart(nBeamId) Then
                  Dim BTLPart As BTLPartVM = BTLPartVM.RetrieveBTLPartFromPart(nBeamId)
                  EgtErase(nBeamId)
                  If Not IsNothing(BTLPart) Then BTLPart.RefreshPartInProd()
               End If
               nRawPartId = EgtGetNextRawPart(nRawPartId)
               nBeamId = EgtGetFirstPartInRawPart(nRawPartId)
            End While
         Else
            Dim nWallId As Integer = EgtGetFirstPartInRawPart(nRawPartId)
            While nWallId <> GDB_ID.NULL
               If EgtRemovePartFromRawPart(nWallId) Then
                  Dim BTLPart As BTLPartVM = BTLPartVM.RetrieveBTLPartFromPart(nWallId)
                  EgtErase(nWallId)
                  If Not IsNothing(BTLPart) Then BTLPart.RefreshPartInProd()
               End If
               nWallId = EgtGetFirstPartInRawPart(nRawPartId)
            End While
         End If
         ' elimino MachGroup
         EgtRemoveMachGroup(Me.Id)
      End If
      ' cambio pezzo selezionato
      If bMultipleCommand Then
         Dim Index As Integer = Map.refMachGroupPanelVM.MachGroupVMList.IndexOf(Me)
         If Index = 0 Then
            If Map.refMachGroupPanelVM.MachGroupVMList.Count > 1 Then
               Map.refMachGroupPanelVM.SelectedMachGroup = Map.refMachGroupPanelVM.MachGroupVMList(1)
            Else
               Map.refMachGroupPanelVM.SelectedMachGroup = Nothing
               EgtDraw()
            End If
         ElseIf Index = Map.refMachGroupPanelVM.MachGroupVMList.Count - 1 Then
            If Map.refMachGroupPanelVM.MachGroupVMList.Count > 1 Then
               Map.refMachGroupPanelVM.SelectedMachGroup = Map.refMachGroupPanelVM.MachGroupVMList(Map.refMachGroupPanelVM.MachGroupVMList.Count - 2)
            Else
               Map.refMachGroupPanelVM.SelectedMachGroup = Nothing
               EgtDraw()
            End If
         Else
            Map.refMachGroupPanelVM.SelectedMachGroup = Map.refMachGroupPanelVM.MachGroupVMList(Index - 1)
         End If
      End If
      ' rimuovo dalla lista grezzi
      Map.refMachGroupPanelVM.MachGroupVMList.Remove(Me)
   End Sub

#End Region ' DeleteMachGroup

#End Region    ' COMMANDS

#Region "EVENTS"

   Protected Overrides Sub OnPartAdded(sender As Object, e As PartAddedEventArgs)
      Dim PartVM As PartVM = New PartVM(e.NewPart, Me)
      PartVMList.Add(PartVM)
   End Sub

#End Region    ' EVENTS

End Class

Class CopyPart

   Private m_BTLPart As BTLPartVM
   Public ReadOnly Property BTLPart As BTLPartVM
      Get
         Return m_BTLPart
      End Get
   End Property
   Private m_sPosX As String
   Public ReadOnly Property sPosX As String
      Get
         Return m_sPosX
      End Get
   End Property
   Private m_sPosY As String
   Public ReadOnly Property sPosY As String
      Get
         Return m_sPosY
      End Get
   End Property
   Private m_dRot As Double
   Public ReadOnly Property dRot As Double
      Get
         Return m_dRot
      End Get
   End Property
   Private m_nFlip As Integer
   Public ReadOnly Property nFlip As Integer
      Get
         Return m_nFlip
      End Get
   End Property

   Sub New(BTLPart As BTLPartVM, sPosX As String, sPosY As String, dRot As Double, nFlip As Integer)
      m_BTLPart = BTLPart
      m_sPosX = sPosX
      m_sPosY = sPosY
      m_dRot = dRot
      m_nFlip = nFlip
   End Sub

End Class
