Imports System.Collections.ObjectModel
Imports System.IO
Imports OmagCUT.TreeViewItem
Imports EgtUILib
Imports EgtWPFLib

Public Class CSVPage

   ' Riferimenti a pagine
   Private m_MainWindow As MainWindow = DirectCast(Application.Current.MainWindow, MainWindow)
   Private WithEvents m_CurrProjPage As CurrentProjectPageUC
   ' Flag di pagina attiva
   Private m_bActive As Boolean = False
   ' Flag tipologia (False -> Cvs semplificato)
   Private m_bFull As Boolean = False
   ' Flag inserimento diretto
   Private m_bDirect As Boolean = True
   ' Flag prima apertura
   Private m_bFirst As Boolean = True
   ' Dati lista
   Private m_sCsvPath As String = String.Empty
   Private m_sFilePath As String = String.Empty
   Private m_CsvPartList As New List(Of CsvPart)
   Private m_ItemsList As New ObservableCollection(Of PartCathegoryItem)
   Private m_sCompoDir As String = String.Empty
   ' Dati del grezzo
   Private m_nRawId As Integer = GDB_ID.NULL
   Private m_ptRawMin As Point3d
   Private m_ptRawMax As Point3d

   Dim m_bIsCounterLy As Boolean = False
   Dim m_nCurrNubrOfParts As Integer = 0
   Dim m_nIdToSel As Integer = GDB_ID.NULL

   Private Sub CSVPage_Initialized(sender As Object, e As EventArgs) Handles Me.Initialized
      ' Assegno la lista dei pezzi Csv come sorgente del treeview
      PartsTreeView.ItemsSource = m_ItemsList
      ' Messaggi
      InsertBtn.Content = EgtMsg(MSG_CSVPAGEUC + 2)    ' Inserisci
      RemoveBtn.Content = EgtMsg(MSG_CSVPAGEUC + 4)    ' Rimuovi
      ' Determino se versione semplificata
      m_bFull = m_MainWindow.GetKeyOption(MainWindow.KEY_OPT.CSV_AUTO) And
                (GetPrivateProfileInt(S_CSV, K_FULL, 1, m_MainWindow.GetIniFile()) <> 0)
      PlusBtn.Visibility = If(m_bFull, Windows.Visibility.Visible, Windows.Visibility.Hidden)
      MinusBtn.Visibility = If(m_bFull, Windows.Visibility.Visible, Windows.Visibility.Hidden)
      RemoveBtn.Visibility = If(m_bFull, Windows.Visibility.Visible, Windows.Visibility.Hidden)
      ' Determino se inserimento diretto
      m_bDirect = m_bFull AndAlso (GetPrivateProfileInt(S_CSV, K_CSV_DIRECT, 1, m_MainWindow.GetIniFile()) <> 0)
      ' Determino se gestione pezzi rovinati attiva
      If Not m_MainWindow.m_CurrentMachine.bProdLine Or Not m_MainWindow.m_CurrentMachine.nSaveProduced = 0 Then
         RuinedPartsBtn.IsEnabled = False
      End If
      ' Leggo lista pezzi corrente
      Dim sCsvFile As String = String.Empty
      GetPrivateProfileString(S_CSV, K_CSVLASTFILE, "", sCsvFile, m_MainWindow.GetIniFile())
      If Not String.IsNullOrEmpty(sCsvFile) Then
         LoadCsvPartList(sCsvFile)
      End If
   End Sub

   Private Sub CSVPage_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
      ' Impostazioni
      m_CurrProjPage = m_MainWindow.m_CurrentProjectPageUC
      m_bActive = True
      ' Se prima esecuzione
      If m_bFirst Then
         ' Leggo direttorio componenti
         GetPrivateProfileString(S_COMPO, K_COMPODIR, "", m_sCompoDir, m_MainWindow.GetIniFile())
         ' Visualizzazione lista
         ShowTreeView()
         m_bFirst = False
      End If
      ' Recupero dimensioni del grezzo e kerf
      m_nRawId = EgtGetFirstRawPart()
      GetRawBox(m_ptRawMin, m_ptRawMax)
      ' Reset bottoni Plus e Minus
      PlusBtn.IsChecked = False
      MinusBtn.IsChecked = False
   End Sub

   Private Sub CSVPage_Unloaded(sender As Object, e As RoutedEventArgs) Handles Me.Unloaded
      m_bActive = False
      m_CurrProjPage.m_SceneButtons.MeasureBtn.IsChecked = False
   End Sub

   Private Sub OnMyMouseDownScene(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles m_CurrProjPage.OnMouseDownScene
      ' Verifico di essere il gestore attivo
      If Not m_bActive Then
         Return
      End If
      ' Si può selezionare solo con il tasto sinistro e se stato NULL
      If e.Button <> Windows.Forms.MouseButtons.Left Or
         Not m_CurrProjPage.CurrentProjectScene.IsStatusNull() Then
         Return
      End If
      ' Verifico se selezionato indicativo di pezzo
      EgtSetObjFilterForSelWin(True, True, True, True, True)
      Dim nSel As Integer
      EgtSelect(e.Location, Scene.DIM_SEL, Scene.DIM_SEL, nSel)
      Dim nId As Integer = EgtGetFirstObjInSelWin()
      While nId <> GDB_ID.NULL
         ' Recupero l'identificativo del pezzo cui appartiene
         Dim nPartId As Integer = EgtGetParent(EgtGetParent(nId))
         Dim bPartInTable As Boolean = (EgtGetParent(nPartId) = m_nRawId)
         If EgtIsPart(nPartId) Or bPartInTable Then
            Dim nStat As Integer = GDB_ST.ON_
            EgtGetStatus(nPartId, nStat)

            ' verifico se l'lemento selezionato è il numero di pezzi
            If EgtGetType(nId) = GDB_TY.EXT_TEXT Then
               Dim NameLayer As String = String.Empty
               EgtGetName(EgtGetParent(nId), NameLayer)
               If NameLayer = INFO_COUNTERLY Then
                  Dim sText As String = String.Empty
                  If EgtTextGetContent(nId, sText) Then
                     Dim sItems() As String = sText.Split("#")
                     If sItems.Count > 1 Then
                        m_nCurrNubrOfParts = 0
                        If StringToInt(sItems(1), m_nCurrNubrOfParts) And m_nCurrNubrOfParts > 0 Then
                           m_bIsCounterLy = True
                           m_nIdToSel = nPartId
                        End If
                     End If
                  End If
               End If
            End If

            If Not m_bIsCounterLy Then
               ' Se già selezionato, lo deselezione
               If nStat = GDB_ST.SEL Then
                  EgtDeselectObj(nPartId)
                  ' Altrimenti lo seleziono
               Else
                  EgtSelectObj(nPartId)
               End If
            End If

            Exit While
         End If
         nId = EgtGetNextObjInSelWin()
      End While
      EgtDraw()
   End Sub

   Private Sub OnMyMouseUpScene(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles m_CurrProjPage.OnMouseUpScene
      If m_bIsCounterLy Then
         ' apro una finestra di dialogo per chiedere se inserire tutti i pezzi della famiglia
         Dim SelectWD As New SelectPartFromFamilyWD(m_MainWindow, m_nCurrNubrOfParts)
         Dim sRefGroup As String = String.Empty
         EgtGetInfo(m_nIdToSel, INFO_REFGROUP, sRefGroup)
         ' deseleziono il pezzo corrente
         m_MainWindow.m_CadCutPageUC.m_NestPage.DeselectPartInFaimily(sRefGroup)
         Select Case SelectWD.NumberOfSelection
            Case 0    ' Annulla
               ' continuo senza eseguire niente
            Case Else
               ' seleziono il numero di pezzi indicati
               m_MainWindow.m_CadCutPageUC.m_NestPage.SelectPartInFaimily(sRefGroup, SelectWD.NumberOfSelection)
         End Select
         m_bIsCounterLy = False
         ' disassegno il riferimento all'oggetto appena creato
         SelectWD = Nothing
         EgtDraw()
      End If
   End Sub

   Private Sub OkBtn_Click(sender As Object, e As RoutedEventArgs) Handles OkBtn.Click
      m_MainWindow.m_CadCutPageUC.CadCutPageGrid.Children.Remove(Me)
      m_MainWindow.m_CadCutPageUC.CadCutPageGrid.Children.Add(m_MainWindow.m_CadCutPageUC.m_NestPage)
      m_MainWindow.m_ActivePage = MainWindow.Pages.CadCut
   End Sub

   Private Sub NewBtn_Click(sender As Object, e As RoutedEventArgs) Handles NewBtn.Click
      ' Salvo lista dei pezzi attuale
      SaveCsvPartList()
      ' Pulisco path e lista dei pezzi Csv
      m_sCsvPath = String.Empty
      m_CsvPartList.Clear()
      ' Visualizzazione lista
      ShowTreeView()
      ' Registro in ini nessuna path
      WritePrivateProfileString(S_CSV, K_CSVLASTFILE, "", m_MainWindow.GetIniFile())
   End Sub

   Private Function CreateListOfDeniedFiles() As List(Of String)
      Dim LocalList As New List(Of String)
      LocalList.Add("MERGE")
      Dim Index1 As Integer = 0
      Dim Index2 As Integer = 0
      For Index1 = 0 To m_CsvPartList.Count - 1
         Dim sFileName As String = m_CsvPartList(Index1).m_sPath
         sFileName = Path.GetFileNameWithoutExtension(sFileName).ToUpper.Trim()
         Dim bNewFile As Boolean = True
         For Index2 = 0 To LocalList.Count - 1
            If sFileName = LocalList(Index2) Then
               bNewFile = False
               Exit For
            End If
         Next
         If bNewFile Then
            LocalList.Add(Path.GetFileNameWithoutExtension(sFileName).ToUpper.Trim)
         End If
      Next
      Return LocalList
   End Function

   Private Sub OpenBtn_Click(sender As Object, e As RoutedEventArgs) Handles OpenBtn.Click
      '' Salvo lista dei pezzi attuale
      'SaveCsvPartList()
      ' Leggo direttorio corrente dei file CSV
      Dim sCurrDir As String = ""
      GetPrivateProfileString(S_CSV, K_CSVCURRDIR, "C:\", sCurrDir, m_MainWindow.GetIniFile())
      ' Apro dialogo scelta file
      Dim OpenFileWnd As OpenFileWD
      Dim sDeniedFiles As List(Of String) = CreateListOfDeniedFiles()
      ' imposto il filtro
      If m_bFull Then
         OpenFileWnd = New OpenFileWD(m_MainWindow, sCurrDir, ".CSV", ".EPL", sDeniedFiles)
      Else
         OpenFileWnd = New OpenFileWD(m_MainWindow, sCurrDir, ".CSV")
      End If
      If Not OpenFileWnd.ShowDialog() Then Return
      ' verifico che il file inserito non appartenga al Merge attuale

      ' Salvo lista dei pezzi attuale
      SaveCsvPartList()
      ' Salvo direttorio corrente
      WritePrivateProfileString(S_CSV, K_CSVCURRDIR, OpenFileWnd.GetFileDir(), m_MainWindow.GetIniFile())
      ' Apertura file
      Dim sPath = OpenFileWnd.GetFilePath()
      If String.Compare(Path.GetExtension(sPath), ".CSV", True) = 0 Then
         LoadCsvFile(sPath)
      Else
         LoadCsvPartList(sPath)
      End If
      ' Salvo path di carico del file CSV
      m_CurrProjPage.SetLoadPath(sPath)
      ' Visualizzazione lista
      ShowTreeView()
   End Sub

   Private Sub RuinedPartsBtn_Click(sender As Object, e As RoutedEventArgs) Handles RuinedPartsBtn.Click
      ' Salvo lista dei pezzi attuale
      SaveCsvPartList()
      ' Apertura file
      Dim sPath = m_MainWindow.GetRuinedPartsDir() & "\" & CURR_RUINED_EPL
      LoadCsvPartList(sPath)
      ' Salvo path di carico del file CSV
      m_CurrProjPage.SetLoadPath(sPath)
      ' Visualizzazione lista
      ShowTreeView()
   End Sub

   Private Function LoadCsvFile(sCsvPath As String) As Boolean
      ' Pulisco path e lista dei pezzi Csv
      m_sFilePath = String.Empty
      m_sCsvPath = String.Empty

      ' mantengo la lista attuale dei pezzi
      'm_CsvPartList.Clear()

      ' aggiungo i pezzi su una lista temporanea
      Dim LocalPartList As New List(Of CsvPart)
      ' Eseguo la lettura del file Csv
      If Not ReadCsvFile(sCsvPath, m_bFull, m_sCsvPath, LocalPartList) Then
         m_CurrProjPage.SetErrorMessage(EgtMsg(91206))    'Errore nella lettura del file CSV
         Return False
      End If

      ' Creo un nuovo file che ospitarà il merge de
      Dim sNewMergeFile As String = Path.GetDirectoryName(m_sCsvPath) & "\Merge.csv"
      m_sCsvPath = sNewMergeFile
      m_sFilePath = m_sCsvPath

      ' Elimino pezzi nulli
      RemoveWrongParts(LocalPartList)
      ' Aggiorno
      If m_bFull Then
         MySaveCsvPartList(LocalPartList)
         ' Salvo come epl
         SaveCsvPartList()
         ' Rinomino file originale
         Dim sBakPath As String = sCsvPath & ".bak"
         Dim sBakName As String = Path.GetFileName(sBakPath)
         ' cancello eventuale vecchio backup
         If My.Computer.FileSystem.FileExists(sBakPath) Then
            My.Computer.FileSystem.DeleteFile(sBakPath)
         End If
         ' eseguo rinomina
         My.Computer.FileSystem.RenameFile(sCsvPath, sBakName)
      End If
      ' attacco i nuovi pezzi alla lista corrente
      For Each Item As CsvPart In LocalPartList
         m_CsvPartList.Add(Item)
      Next
      Return True
   End Function

   Private Sub LoadCsvPartList(sFile As String)
      ' Se Csv semplificato non va letta
      If Not m_bFull Then Return
      ' Pulisco path e lista dei pezzi Csv
      m_sCsvPath = String.Empty

      ' mantengo la lista attuale dei pezzi
      'm_CsvPartList.Clear()

      ' aggiungo i pezzi su una lista temporanea
      Dim LocalPartList As New List(Of CsvPart)

      ' Lettura del file
      If ReadCsvPartList(sFile, m_sCsvPath, LocalPartList) Then
         ' Creo un nuovo file che ospitarà il merge de
         Dim sNewMergeFile As String = Path.GetDirectoryName(m_sCsvPath) & "\Merge.csv"
         m_sCsvPath = sNewMergeFile
         m_sFilePath = m_sCsvPath
      End If
      ' Elimino pezzi nulli
      RemoveWrongParts(LocalPartList)
      ' attacco i nuovi pezzi alla lista corrente
      For Each Item As CsvPart In LocalPartList
         m_CsvPartList.Add(Item)
      Next
   End Sub

   Private Sub ShowTreeView()
      ' Path del file Csv
      Dim TempPath As New Text.StringBuilder(260)
      PathCompactPathEx(TempPath, m_sCsvPath, 28, 0)
      CsvPathTxBl.Content = TempPath.ToString()
      ' Pezzi del file Csv
      m_ItemsList.Clear()
      Dim sCurrMat As String = String.Empty
      Dim dCurrTh As Double = 0
      Dim sCurrPath As String = String.Empty
      Dim nCatToNest As Integer = 0
      Dim nCatCount As Integer = 0
      Dim PartCathegory As New PartCathegoryItem("", 0)
      For i As Integer = 1 To m_CsvPartList.Count()
         ' Dati pezzo corrente
         Dim CurrPart As CsvPart = m_CsvPartList(i - 1)
         ' Gestione categoria
         If i = 1 Then
            sCurrMat = CurrPart.m_sMaterial
            dCurrTh = CurrPart.m_dTh
            sCurrPath = CurrPart.m_sPath
         ElseIf String.Compare(sCurrMat, CurrPart.m_sMaterial, True) <> 0 Or
                String.Compare(sCurrPath, CurrPart.m_sPath, True) <> 0 Or
                Math.Abs(dCurrTh - CurrPart.m_dTh) > 10 * EPS_SMALL Then
            If m_bFull Then
               PartCathegory.Name = If(String.IsNullOrWhiteSpace(sCurrMat), "***", sCurrMat) &
                                    " - " & LenToString(dCurrTh, 2) &
                                    " - " & nCatToNest.ToString() & "/" & nCatCount.ToString()
               If Not String.IsNullOrWhiteSpace(sCurrPath) Then
                  PartCathegory.Name &= vbCrLf & Path.GetFileNameWithoutExtension(sCurrPath)
               End If
            Else
               PartCathegory.Name = nCatToNest.ToString() & "/" & nCatCount.ToString()
               If Not String.IsNullOrWhiteSpace(sCurrPath) Then
                  PartCathegory.Name &= vbCrLf & Path.GetFileNameWithoutExtension(sCurrPath)
               End If
            End If
            PartCathegory.IsExpanded = True
            m_ItemsList.Add(PartCathegory)
            sCurrMat = CurrPart.m_sMaterial
            dCurrTh = CurrPart.m_dTh
            sCurrPath = CurrPart.m_sPath
            PartCathegory = New PartCathegoryItem("", 0)
            nCatToNest = 0
            nCatCount = 0
         End If
         ' Gestione pezzo
         nCatToNest += CurrPart.m_nToNest
         nCatCount += CurrPart.m_nCount
         Dim sCount As String = CurrPart.m_nToNest.ToString() & "/" & CurrPart.m_nCount.ToString()
         If CurrPart.m_nAdd > 0 Then sCount &= "+" & CurrPart.m_nAdd.ToString()
         Dim sDim As String = LenToString(CurrPart.m_dDimX, 1) & "x" & LenToString(CurrPart.m_dDimY, 1)
         PartCathegory.Items.Add(New PartCustomItem(CurrPart.m_sName, i, sCount, sDim, CurrPart.m_bActive))
      Next
      ' Inserisco ultima categoria
      If m_bFull Then
         PartCathegory.Name = If(String.IsNullOrWhiteSpace(sCurrMat), "***", sCurrMat) &
                              " - " & LenToString(dCurrTh, 2) &
                              " - " & nCatToNest.ToString() & "/" & nCatCount.ToString()
         If Not String.IsNullOrWhiteSpace(sCurrPath) Then
            PartCathegory.Name &= vbCrLf & Path.GetFileNameWithoutExtension(sCurrPath)
         End If
      Else
         PartCathegory.Name = nCatToNest.ToString() & "/" & nCatCount.ToString()
         If Not String.IsNullOrWhiteSpace(sCurrPath) Then
            PartCathegory.Name &= vbCrLf & Path.GetFileNameWithoutExtension(sCurrPath)
         End If
      End If
      PartCathegory.IsExpanded = True
      m_ItemsList.Add(PartCathegory)
   End Sub

   Private Sub UpdateTreeView()
      For Each CatItem As PartCathegoryItem In m_ItemsList
         Dim sCurrMat As String = String.Empty
         Dim dCurrTh As Double = 0
         Dim sCurrPath As String = String.Empty
         Dim nCatToNest As Integer = 0
         Dim nCatCount As Integer = 0
         For Each PrtItem As PartCustomItem In CatItem.Items
            Dim PartData As CsvPart = m_CsvPartList(PrtItem.nType - 1)
            Dim sCount As String = PartData.m_nToNest.ToString() & "/" & PartData.m_nCount.ToString()
            If PartData.m_nAdd > 0 Then sCount &= "+" & PartData.m_nAdd.ToString()
            PrtItem.sText1 = sCount
            sCurrMat = PartData.m_sMaterial
            dCurrTh = PartData.m_dTh
            sCurrPath = PartData.m_sPath
            nCatToNest += PartData.m_nToNest
            nCatCount += PartData.m_nCount
         Next
         If m_bFull Then
            CatItem.Name = If(String.IsNullOrWhiteSpace(sCurrMat), "***", sCurrMat) &
                           " - " & LenToString(dCurrTh, 2) &
                           " - " & nCatToNest.ToString() & "/" & nCatCount.ToString()
            If Not String.IsNullOrWhiteSpace(sCurrPath) Then
               CatItem.Name &= vbCrLf & Path.GetFileNameWithoutExtension(sCurrPath)
            End If
         Else
            CatItem.Name = nCatToNest.ToString() & "/" & nCatCount.ToString()
            If Not String.IsNullOrWhiteSpace(sCurrPath) Then
               CatItem.Name &= vbCrLf & Path.GetFileNameWithoutExtension(sCurrPath)
            End If
         End If
      Next
   End Sub

   Private Sub PartsTreeView_PreviewMouseUp(sender As Object, e As MouseButtonEventArgs) Handles PartsTreeView.PreviewMouseUp
      ' Pezzi disattivabili solo se Csv completo
      If Not m_bFull Then Return
      If TypeOf PartsTreeView.SelectedItem Is PartCathegoryItem Then
         Dim SelectedCathegory As PartCathegoryItem = DirectCast(PartsTreeView.SelectedItem, PartCathegoryItem)
         ' Determino quanti attivi per decidere cosa fare
         Dim nItemOn As Integer = 0
         For Each Item As PartCustomItem In SelectedCathegory.Items
            If Item.bIsActive Then nItemOn += 1
         Next
         Dim bActivate As Boolean = (nItemOn <= SelectedCathegory.Items.Count() - nItemOn)
         ' Aggiorno stato
         For Each Item As PartCustomItem In SelectedCathegory.Items
            Item.bIsActive = bActivate
            m_CsvPartList(Item.nType - 1).m_bActive = Item.bIsActive
         Next
         SelectedCathegory.IsSelected = False
      ElseIf TypeOf PartsTreeView.SelectedItem Is PartCustomItem Then
         Dim SelectedCustom As PartCustomItem = DirectCast(PartsTreeView.SelectedItem, PartCustomItem)
         Dim PartData As CsvPart = m_CsvPartList(SelectedCustom.nType - 1)
         Dim nPlusMinus As Integer = GetPlusMinus()
         If nPlusMinus <> 0 Then
            ' Posso sempre aggiungere pezzi in più
            If nPlusMinus > 0 Then
               PartData.m_nToNest += 1
               PartData.m_nAdd += 1
               Dim sCount As String = PartData.m_nToNest.ToString() & "/" & PartData.m_nCount.ToString()
               If PartData.m_nAdd > 0 Then sCount &= "+" & PartData.m_nAdd.ToString()
               SelectedCustom.sText1 = sCount
            ' Posso togliere solo pezzi aggiunti non ancora inseriti
            ElseIf PartData.m_nAdd > 0 And PartData.m_nToNest > 0 Then
               PartData.m_nToNest -= 1
               PartData.m_nAdd -= 1
               Dim sCount As String = PartData.m_nToNest.ToString() & "/" & PartData.m_nCount.ToString()
               If PartData.m_nAdd > 0 Then sCount &= "+" & PartData.m_nAdd.ToString()
               SelectedCustom.sText1 = sCount
            End If
         Else
            SelectedCustom.bIsActive = Not SelectedCustom.bIsActive
            PartData.m_bActive = SelectedCustom.bIsActive
         End If
         SelectedCustom.IsSelected = False
      End If
   End Sub

   Private Sub PlusBtn_Click(sender As Object, e As RoutedEventArgs) Handles PlusBtn.Click
      If MinusBtn.IsChecked Then MinusBtn.IsChecked = False
   End Sub

   Private Sub MinusBtn_Click(sender As Object, e As RoutedEventArgs) Handles MinusBtn.Click
      If PlusBtn.IsChecked Then PlusBtn.IsChecked = False
   End Sub

   Private Function GetPlusMinus() As Integer
      If PlusBtn.IsChecked Then
         Return 1
      ElseIf MinusBtn.IsChecked Then
         Return -1
      Else
         Return 0
      End If
   End Function

   Private Sub InsertBtn_Click(sender As Object, e As RoutedEventArgs) Handles InsertBtn.Click
      'm_CurrProjPage.ClearMessage()
      ' Recupero lo spessore della lastra corrente
      Dim dRawHeight As Double = GetRawHeight()
      If dRawHeight < EPS_SMALL Then Return
      ' Recupero il materiale della lastra corrente
      Dim sCurrMat As String = String.Empty
      If Not IsNothing(m_MainWindow.m_CurrentMachine.CurrMat) Then
         sCurrMat = m_MainWindow.m_CurrentMachine.CurrMat.sName
      End If
      ' Recupero la tolleranza sullo spessore
      Dim dToler As Double = GetPrivateProfileDouble(S_CSV, K_THICKTOLERANCE, 100 * EPS_SMALL, m_MainWindow.GetIniFile())
      dToler = Math.Max(dToler, 100 * EPS_SMALL)
      ' Creo la lista dei pezzi inseribili nella lastra corrente
      Dim InsPartList As New List(Of CsvPart)
      For i As Integer = 1 To m_CsvPartList.Count()
         Dim CurrPart As CsvPart = m_CsvPartList(i - 1)
         If CurrPart.m_bActive And
            (Math.Abs(CurrPart.m_dTh - dRawHeight) < dToler Or CurrPart.m_dTh < EPS_SMALL) And
            (String.IsNullOrWhiteSpace(CurrPart.m_sMaterial) Or String.IsNullOrWhiteSpace(sCurrMat) Or CurrPart.m_sMaterial = "***" Or sCurrMat = "***" Or String.Compare(CurrPart.m_sMaterial, sCurrMat, True) = 0) Then
            InsPartList.Add(CurrPart)
            'ElseIf CurrPart.m_bActive Then
            '   m_CurrProjPage.SetWarningMessage("Grezzo non compatibile")
         End If
      Next
      ' Lancio l'inserimento dei pezzi
      ExecInsert(InsPartList)
      ' Aggiorno visualizzazione
      EgtZoom(ZM.ALL)
      ' Aggiorno TreeView
      UpdateTreeView()
   End Sub

   Private Function ExecInsert(InsPartList As List(Of CsvPart)) As Boolean
      Dim bMaxDimOnX As Boolean = (GetPrivateProfileInt(S_CSV, K_MAXDIMONX, 1, m_MainWindow.GetIniFile()) <> 0)
      If bMaxDimOnX Then
         ' Ordino la lista dei pezzi secondo la dimensione minima decrescente (va su Y)
         InsPartList.Sort(Function(P, Q)
                             Dim dPMin As Double = Math.Min(P.m_dDimX, P.m_dDimY)
                             Dim dQMin As Double = Math.Min(Q.m_dDimX, Q.m_dDimY)
                             If Math.Abs(dPMin - dQMin) < EPS_SMALL Then
                                Return (P.m_nOriInd - Q.m_nOriInd)
                             Else
                                Return CInt(Math.Ceiling(dQMin - dPMin))
                             End If
                          End Function)
      Else
         ' Ordino la lista dei pezzi secondo le Y decrescenti
         InsPartList.Sort(Function(P, Q)
                             If Math.Abs(P.m_dDimY - Q.m_dDimY) < EPS_SMALL Then
                                Return (P.m_nOriInd - Q.m_nOriInd)
                             Else
                                Return CInt(Math.Ceiling(Q.m_dDimY - P.m_dDimY))
                             End If
                          End Function)
      End If
      ' Creo o svuoto gruppo temporaneo per i pezzi
      Dim nIpGrp As Integer = EgtGetFirstNameInGroup(GDB_ID.ROOT, "CSV")
      If nIpGrp = GDB_ID.NULL Then
         nIpGrp = EgtCreateGroup(GDB_ID.ROOT)
         If nIpGrp = GDB_ID.NULL Then Return False
         EgtSetName(nIpGrp, "CSV")
      Else
         EgtEmptyGroup(nIpGrp)
      End If
      EgtSetLevel(nIpGrp, GDB_LV.TEMP)
      EgtSetStatus(nIpGrp, GDB_ST.OFF)
      ' Carico lua per creare rettangoli
      Dim sLuaPath = m_sCompoDir & "\Rettangolo.lua"
      If Not EgtLuaExecFile(sLuaPath) Then Return False
      ' Inserisco nel gruppo un nuovo componente per ogni pezzo da inserire
      For i As Integer = 1 To InsPartList.Count()
         Dim CurrPart As CsvPart = InsPartList(i - 1)
         ' Se non è un rettangolo, vado oltre
         If Not CurrPart.m_bIsRect Then Continue For
         ' Definizione variabili
         Dim dDimX = CurrPart.m_dDimX
         Dim dDimY = CurrPart.m_dDimY
         Dim dAng = New Double() {CurrPart.m_dAng1,CurrPart.m_dAng2,CurrPart.m_dAng3,CurrPart.m_dAng4}
         Dim dHeel = New Double() {CurrPart.m_dHeel1,CurrPart.m_dHeel2,CurrPart.m_dHeel3,CurrPart.m_dHeel4}
         If bMaxDimOnX And dDimY > dDimX Then
            Dim dTemp As Double = dDimX
            dDimX = dDimY
            dDimY = dTemp
            dAng = New Double() {CurrPart.m_dAng2,CurrPart.m_dAng3,CurrPart.m_dAng4,CurrPart.m_dAng1}
            dHeel = New Double() {CurrPart.m_dHeel2,CurrPart.m_dHeel3,CurrPart.m_dHeel4,CurrPart.m_dHeel1}
         End If
         EgtLuaSetGlobNumVar("CMP.V1", dDimX)
         EgtLuaSetGlobNumVar("CMP.V2", dDimY)
         EgtLuaSetGlobStringVar("CMP.INFO", CurrPart.m_sName)
         ' Esecuzione componente
         If Not EgtLuaExecLine("CMP_Draw(false)") Then Continue For
         ' Recupero Id del nuovo componente
         Dim nId As Integer = EgtGetLastPart()
         If nId = GDB_ID.NULL Then Continue For
         CurrPart.m_nId = nId
         ' Muovo la regione in Z per evitare problemi in visualizzazione
         Dim nRegId As Integer = EgtGetFirstNameInGroup(nId, NAME_REGION)
         EgtMove(nRegId, New Vector3d(0, 0, DELTAZ_REG), GDB_RT.GLOB)
         ' Eventuale testo per indicare il sopra
         If Not bMaxDimOnX Then
            Dim dH As Double = Math.Min(0.1 * dDimY, 30)
            Dim nText As Integer = EgtCreateTextAdv(nRegId, New Point3d(dDimX / 2, dDimY - 0.6 * dH, 0), 0, "*TOP*", "", 500, False, dH, 1, 0, INS_POS.MC)
            EgtSetColor(nText, New Color3d( 0, 0, 0))
         End If
         ' Inserisco eventuali angoli di fianco
         Dim bSideAngs As Boolean = False
         Dim nOutLoopId As Integer = EgtGetFirstNameInGroup( nId, NAME_OUTLOOP)
         For nSide As Integer = 1 To 4
            Dim dSideAng As Double = dAng( nSide - 1)
            Dim dSideHeel As Double = dHeel( nSide - 1)
            If Math.Abs( dSideAng) > EPS_ANG_SMALL Then
               Dim nEntId As Integer = EgtGetFirstNameInGroup( nOutLoopId, "A" & nSide.ToString())
               If nEntId <> GDB_ID.NULL Then
                  bSideAngs = True
                  ' Assegno valori
                  EgtSetInfo(nEntId, INFO_SIDE_ANGLE, dSideAng)
                  EgtSetInfo(nEntId, INFO_ORIG_SIDE_ANGLE, dSideAng)
                  EgtSetInfo(nEntId, INFO_HEEL, dSideHeel)
               End If
            End If
         Next
         ' Creo layer per testi nesting
         If bSideAngs Then
            Dim TextLayId As Integer = EgtCreateGroup(nId)
            EgtSetName(TextLayId, SIDE_ANGLE_LAYER)
            EgtSetColor(TextLayId, New Color3d(0, 0, 128))
            ' Opero su geometria esterna pezzo
            SideAngle.WriteSideAngleOnLoop(nOutLoopId, TextLayId)
         End If
         ' Aggiusto per lavorazioni
         EgtAdjustFlatPart(nId)
         ' Se Csv completo, aggiungo info su CSV di origine
         If m_bFull Then
            EgtSetInfo(nId, INFO_CSV_PATH, CurrPart.m_sPath)
            EgtSetInfo(nId, INFO_CSV_PART, CurrPart.m_sName)
            EgtSetInfo(nId, INFO_CSV_ORD, CurrPart.m_sOrd)
            EgtSetInfo(nId, INFO_CSV_DIST, CurrPart.m_sDist)
            EgtSetInfo(nId, INFO_CSV_MAT, CurrPart.m_sMaterial)
         End If
         ' Imposto colore testi
         Utility.SetTextColor( nRegId)
         ' Lo sposto nel gruppo speciale
         EgtRelocate(nId, nIpGrp)


         ' assegno l'identificatico del pezzo, se esiste
         If Not String.IsNullOrEmpty(CurrPart.m_sRefGuid) Then
            ' GuidCode dovrebbe contenere 36 caratteri, il precode 5: tot = 41
            If CurrPart.m_sRefGuid.Count <= 36 Then
               Dim sPreGuid As String = CreatePreGuidCode(CurrPart.m_nId)
               CurrPart.m_sRefGuid = sPreGuid & CurrPart.m_sRefGuid
            End If
            EgtSetInfo(CurrPart.m_nId, INFO_REFGROUP, CurrPart.m_sRefGuid)
         End If
         Dim nRegLayId As Integer = EgtGetFirstNameInGroup(CurrPart.m_nId, NAME_REGION)
         ' Imposto il colore del pezzo inserito nel progetto
         EgtSetColor(nRegLayId, CurrPart.m_cColor)
         Dim EntId As Integer = EgtGetFirstInGroup(nRegLayId)
         While EntId <> GDB_ID.NULL
            If EgtGetType(EntId) = GDB_TY.SRF_FRGN Then EgtSetColor(EntId, CurrPart.m_cColor)
            EntId = EgtGetNext(EntId)
         End While

      Next
      EgtLuaResetGlobVar("CMP")
      EgtLuaResetGlobVar("CMP_Draw")

      ' Provo ad inserire i pezzi
      Dim dNewArea As Double = 0
      For i As Integer = 1 To InsPartList.Count()
         Dim CurrPart As CsvPart = InsPartList(i - 1)
         While CurrPart.m_nToNest > 0

            If m_bDirect Then
               If NestOnePart(CurrPart.m_nId) Then
                  dNewArea += GeomCalc.GetPartArea(CurrPart.m_nId)
                  CurrPart.m_nToNest -= 1
               Else
                  Exit While
               End If
            Else
               If ParkOnePart(CurrPart.m_nId) Then
                  dNewArea += GeomCalc.GetPartArea(CurrPart.m_nId)
                  CurrPart.m_nToNest -= 1
               Else
                  Exit While
               End If
            End If
         End While
      Next
      ' Aggiorno Aree totale e da lavorare dei pezzi
      m_CurrProjPage.UpdateTotalArea( dNewArea)
      m_CurrProjPage.UpdateToProduceArea()
      m_MainWindow.m_CurrentProjectPageUC.ShowAreas()

      Return True
   End Function

   Private Function NestOnePart(nId As Integer) As Boolean
      ' Inserisco una copia del pezzo nel grezzo
      Dim nId2 As Integer = EgtCopyGlob(nId, GDB_ID.ROOT)
      If Not m_MainWindow.m_CadCutPageUC.m_NestPage.InsertOnePart(nId2) Then
         EgtErase(nId2)
         Return False
      Else
         Return True
      End If
   End Function

   Private Function ParkOnePart(nId As Integer) As Boolean
      ' Inserisco in parcheggio una copia del pezzo
      Dim nId2 As Integer = EgtCopyGlob(nId, GDB_ID.ROOT)
      If Not m_MainWindow.m_CadCutPageUC.m_NestPage.StoreOnePart(nId2, True) Then
         EgtErase(nId2)
         Return False
      Else
         Return True
      End If
   End Function

   Private Sub RemoveBtn_Click(sender As Object, e As RoutedEventArgs) Handles RemoveBtn.Click
      ' Elenco eventuali altre liste Csv riferite dai pezzi
      Dim bOther As Boolean = False
      Dim sOtherCsv As String = String.Empty
      ' Rimuovo i pezzi selezionati della lista CSV corrente e ne aggiorno i contatori
      Dim dEraseArea As Double = 0
      Dim nId As Integer = EgtGetFirstSelectedObj()
      While nId <> GDB_ID.NULL
         Dim nNextId As Integer = EgtGetNextSelectedObj()
         Dim dPartArea = GeomCalc.GetPartArea( nId)
         If RemoveOnePart(nId) Then
            dEraseArea += dPartArea
         Else
            bOther = True
            Dim sCsvPath As String = String.Empty
            If EgtGetInfo(nId, INFO_CSV_PATH, sCsvPath) Then
               Dim sCsvName As String = Path.GetFileNameWithoutExtension(sCsvPath)
               If sOtherCsv.IndexOf(sCsvName) = -1 Then
                  sOtherCsv = sOtherCsv & sCsvName & ", "
               End If
            End If
         End If
         nId = nNextId
      End While
      ' Aggiorno Aree totale e da lavorare dei pezzi
      m_CurrProjPage.UpdateTotalArea( - dEraseArea)
      m_CurrProjPage.UpdateToProduceArea()
      m_MainWindow.m_CurrentProjectPageUC.ShowAreas()
      ' Aggiorno visualizzazione
      EgtDraw()
      ' Aggiorno TreeView
      UpdateTreeView()
      ' Eventuale messaggi di pezzi liberi o da altre liste
      If bOther Then
         ' Pezzi non rimossi perché liberi
         Dim sOut As String = EgtMsg(MSG_EGTMSGBOX + 13)
         If Not String.IsNullOrWhiteSpace(sOtherCsv) Then
            ' o di altre liste Csv
            sOut &= EgtMsg(MSG_EGTMSGBOX + 14) & " (" & sOtherCsv.TrimEnd(", ".ToCharArray()) & ")"
         End If
         Dim WarnMsg As New EgtMsgBox(m_MainWindow, "", sOut, EgtMsgBox.Buttons.OK, EgtMsgBox.Icons.NULL, 0, 1)
      End If
   End Sub

   Private Function RemoveOnePart(nId As Integer) As Boolean
      ' Recupero identificativi da Info
      Dim sCsvPath As String = String.Empty
      EgtGetInfo(nId, INFO_CSV_PATH, sCsvPath)
      Dim sName As String = String.Empty
      EgtGetInfo(nId, INFO_CSV_PART, sName)
      ' Verifico che il pezzo appartenga a questo Csv
      If SearchCurrCSV(sCsvPath) Then
         ' Cerco il pezzo nella lista dei pezzi
         For i As Integer = 1 To m_CsvPartList.Count()
            Dim CurrPart As CsvPart = m_CsvPartList(i - 1)
            If String.Compare(sName, CurrPart.m_sName, True) = 0 And String.Compare(sCsvPath, CurrPart.m_sPath, True) = 0 Then
               ' Se nel grezzo
               If EgtGetParent(nId) = m_nRawId Then
                  ' Rimuovo le lavorazioni
                  EraseMachinings(nId)
                  ' Rimuovo dal grezzo
                  EgtRemovePartFromRawPart(nId)
               End If
               ' recupero il Guid del pezzo corrente (potrebbe essere stato modificato a causa di rotazioni quando il pezzo è passato in parcheggio)
               Dim sCurrRefGuid As String = String.Empty
               EgtGetInfo(nId, INFO_REFGROUP, sCurrRefGuid)
               ' Cancello il pezzo
               EgtErase(nId)
               ' aggiorno il layer che indica il numero di pezzi in parcheggio (se sRefGroup<>"")
               m_MainWindow.m_CadCutPageUC.m_NestPage.CountPartInFamily(sCurrRefGuid)
               ' Aggiorno il contatore
               CurrPart.m_nToNest += 1
               ' ricreo la lista delle famiglie di pezzi presenti in parcheggio
               m_MainWindow.m_CadCutPageUC.m_NestPage.GetFamilyGroupInPark()
               ' Esco
               Return True
            End If
         Next
      End If
      ' creo la lista delle famiglie di pezzi presenti in parcheggio
      m_MainWindow.m_CadCutPageUC.m_NestPage.GetFamilyGroupInPark()
      ' Pezzo non appartenente al Csv corrente
      Return False
   End Function

   Private Function SearchCurrCSV(ByVal sCSVFile As String) As Boolean
      For i As Integer = 1 To m_CsvPartList.Count()
         Dim CurrPart As CsvPart = m_CsvPartList(i - 1)
         If String.Compare(sCSVFile, CurrPart.m_sPath, True) = 0 Then
            Return True
         End If
      Next
      Return False
   End Function

   Friend Sub SaveCsvPartList()
      ' Se Csv semplificato non va salvata
      If Not m_bFull Then Return
      ' Se non c'è nulla di attivo, non faccio alcunché
      If String.IsNullOrEmpty(m_sCsvPath) Then
         EgtOutLog("CSV List missing")
         Return
      End If
      ' Path del file
      Dim sFile As String = Path.ChangeExtension(m_sFilePath, ".epl")
      ' Scrittura dei file
      If WriteCsvMergePartList(m_CsvPartList) Then
         ' Scrittura dei file Merge
         If WriteCsvPartList(sFile, m_sCsvPath, m_CsvPartList) Then
            WritePrivateProfileString(S_CSV, K_CSVLASTFILE, sFile, m_MainWindow.GetIniFile())
         End If
      End If
   End Sub

   ' salvo il sottoelenco dei pezzi
   Friend Sub MySaveCsvPartList(ByVal CurrPartList As List(Of CsvPart))
      ' Se Csv semplificato non va salvata
      If Not m_bFull Then Return
      Dim sCurrPath As String = String.Empty
      ' recupero dalla lista il nome del file corrente
      For Each Item As CsvPart In CurrPartList
         sCurrPath = Item.m_sPath
      Next
      ' se non trov il nome del file assocciato all'elenco di pezzi esco
      If String.IsNullOrEmpty(sCurrPath) Then
         EgtOutLog("CSV Curr list missing")
         Return
      End If
      ' Path del file
      Dim sFile As String = Path.ChangeExtension(sCurrPath, ".epl")
      ' Scrittura del file
      WriteCsvPartList(sFile, sCurrPath, CurrPartList)
   End Sub

   Friend Sub UpdateCsvPartList()
      ' Se Csv semplificato non va aggiornata
      If Not m_bFull Then Return
      ' Leggo lista pezzi corrente
      Dim sCsvFile As String = String.Empty
      GetPrivateProfileString(S_CSV, K_CSVLASTFILE, "", sCsvFile, m_MainWindow.GetIniFile())
      If Not String.IsNullOrEmpty(sCsvFile) Then
         LoadCsvPartList(sCsvFile)
      End If
      ' Visualizzazione lista
      ShowTreeView()
   End Sub

End Class
