Imports System.Collections.ObjectModel
Imports System.ComponentModel
Imports System.IO
Imports EgtUILib
Imports EgtWPFLib5
Imports EgtBEAMWALL.Core

Public Class SetUpVM
   Inherits VMBase

#Region "FIELDS & PROPERTIES"

   Private Const INVALIDPOS As String = ""

   Public Event SetUp_IsModified()

   Private m_Title As String
   Public ReadOnly Property Title As String
      Get
         Return EgtMsg(6451)
      End Get
   End Property

   ' Lista degli utensili
   Private m_ToolsList As New ObservableCollection(Of FamilyToolItem)
   Public Property ToolsList As ObservableCollection(Of FamilyToolItem)
      Get
         Return m_ToolsList
      End Get
      Set(value As ObservableCollection(Of FamilyToolItem))
         m_ToolsList = value
      End Set
   End Property

   ' Lista dei gruppi di posizioni
   Private m_PositionGroupList As New ObservableCollection(Of PositionGroup)
   Public Property PositionGroupList As ObservableCollection(Of PositionGroup)
      Get
         Return m_PositionGroupList
      End Get
      Set(value As ObservableCollection(Of PositionGroup))
         m_PositionGroupList = value
      End Set
   End Property

   Private m_LastIndexRead As Integer = 0

   Private m_IsEnabledApplyBtn As Boolean
   Public ReadOnly Property IsEnabledApplyBtn As Boolean
      Get
         Return m_IsEnabledApplyBtn
      End Get
   End Property

   ' Immagine del porta utensili
   Public ReadOnly Property SetUpImage As String
      Get
         ' Cerco png
         Dim sImagePath As String = CurrentMachine.sMachSetupDir & "\SetupImage.png"
         If File.Exists(sImagePath) Then Return sImagePath
         ' Cerco jpeg
         sImagePath = CurrentMachine.sMachSetupDir & "\SetupImage.jpg"
         If File.Exists(sImagePath) Then Return sImagePath
         ' Cerco bmp
         sImagePath = CurrentMachine.sMachSetupDir & "\SetupImage.bmp"
         If File.Exists(sImagePath) Then Return sImagePath
         ' Non trovato alcunché
         Return String.Empty
      End Get
   End Property

#Region "Messages"

   Public ReadOnly Property TitleMsg As String
      Get
         Return EgtMsg(6451)
      End Get
   End Property

   Public ReadOnly Property ApplyMsg As String
      Get
         Return EgtMsg(6452)
      End Get
   End Property
   Public ReadOnly Property ArchiveMsg As String
      Get
         Return EgtMsg(6453)
      End Get
   End Property
   Public ReadOnly Property RetrievesMsg As String
      Get
         Return EgtMsg(6454)
      End Get
   End Property
   Public ReadOnly Property AutomaticMsg As String
      Get
         Return EgtMsg(6455)
      End Get
   End Property

#End Region

   ' Definizione comandi
   Private m_cmdApply As ICommand
   Private m_cmdArchive As ICommand
   Private m_cmdRetrieves As ICommand
   Private m_cmdAutomatic As ICommand
   Private m_cmdToolDoubleClick As ICommand

#End Region    ' FIELDS & PROPERTIES

#Region "CONSTRUCTOR"

   Sub New()
      ' rendo accessibile la lista posizioni a famiglie ed utensili per poterle attivare e disattivare
      ' (probabilmente da cambiare passandogli il riferimento alla creazione dell'utensile per non avere parametro shared)
      FamilyToolItem.m_PositionGroupList = m_PositionGroupList
      ToolItem.m_PositionGroupList = m_PositionGroupList
      ' rendo accessibile le liste utensili e posizioni alle uscite
      ExitToolAssociation.sh_ToolsList = m_ToolsList
      ExitToolAssociation.sh_PositionGroupList = m_PositionGroupList
      ' imposto il delegate che segnala una modifica al Db
      ExitToolAssociation.m_delIsModifiedSetUp = AddressOf SetUp_IsModifiedManager
   End Sub

#End Region    ' CONSTRUCTOR

#Region "METHODS"

   ''' <summary>
   ''' Funzione che inizializza il set up calcolando le posizioni disponibili sulla macchina 
   ''' </summary>
   Friend Function InitSetUp() As Boolean
      ' Cancello tutto
      m_ToolsList.Clear()
      m_PositionGroupList.Clear()
      ' genero l'attrezzaggio dalla configurazione Lua
      Dim Index As Integer = 1
      While CreateStdPosFromPosIndex(Index)
         Index += 1
      End While
      m_LastIndexRead = Index
      Return True
   End Function

   ''' <summary>
   ''' Funzione che carica il setup del gruppo di lavorazione corrente
   ''' </summary>
   Friend Function LoadCurrentSetUp() As Boolean
      ' resetto lista utensili e posizioni
      m_ToolsList.Clear()
      ClearAllPos()
      'ricarico lista utensili
      LoadMachineTools()
      ' recupero il gruppo del setup
      Dim nSetUpGroup As Integer = EgtGetCurrSetup()
      ' leggo l'attrezzaggio del progetto
      Dim sPosition As String = String.Empty
      Dim IniIndex As Integer = 1
      ' recupero stringa di ogni posizione e sposto gli utensili nelle posizioni
      While EgtGetInfo(nSetUpGroup, K_POS & IniIndex, sPosition)
         If IniIndex < m_LastIndexRead Then
            ReadPositionString(IniIndex, sPosition, True)
         Else
            EgtRemoveInfo(nSetUpGroup, K_POS & IniIndex)
         End If
         IniIndex += 1
      End While
      ' Se esiste almeno una famiglia di utensili, la seleziono
      If ToolsList.Count > 0 Then
         ToolsList(0).IsSelected = True
         ToolsList(0).NotifyPropertyChanged("IsSelected")
      End If
      Return True
   End Function

   ''' <summary>
   ''' Funzione che carica il setup da un file. bOriginal indice se deve sostituire il valore originale
   ''' </summary>
   Public Sub LoadSetupFromFile(sFileName As String, bOriginal As Boolean)
      ' Direttorio per attrezzaggi
      Dim sFilePath As String = CurrentMachine.sMachDir & "\SetUp\" & sFileName & ".stu"
      ' resetto lista utensili e posizioni
      m_ToolsList.Clear()
      ClearAllPos()
      'ricarico lista utensili
      LoadMachineTools()
      ' leggo l'attrezzaggio dal file scelto
      Dim sPosition As String = String.Empty
      Dim IniIndex As Integer = 1
      ' recupero stringa di ogni posizione
      While EgtUILib.GetPrivateProfileString(S_GENERAL, K_POS & IniIndex, String.Empty, sPosition, sFilePath) > 0
         ReadPositionString(IniIndex, sPosition, bOriginal)
         IniIndex += 1
      End While
      ' recupero utensile correntemente selezionato
      Dim SelTool As ToolItem = Nothing
      Dim bFounded As Boolean = False
      For Each Toolfamily In m_ToolsList
         For Each Tool In Toolfamily.Items
            If Tool.IsSelected Then
               SelTool = DirectCast(Tool, ToolItem)
               bFounded = True
               Exit For
            End If
         Next
         If bFounded Then Exit For
      Next
      ' verifico se disabilitare questa posizione in base all'utensile correntemente selezionato
      If IsNothing(SelTool) Then
         ' disabilito tutte le uscite tranne quelle occupate
         For GroupIndex = 0 To m_PositionGroupList.Count - 1
            For PosIndex = 0 To m_PositionGroupList(GroupIndex).PositionList.Count - 1
               m_PositionGroupList(GroupIndex).PositionList(PosIndex).SetNotValidPos()
            Next
         Next
      Else
         ' abilito e disabilito tutte le uscite in base all'utensile selezionato 
         For GroupIndex = 0 To m_PositionGroupList.Count - 1
            For PosIndex = 0 To m_PositionGroupList(GroupIndex).PositionList.Count - 1
               m_PositionGroupList(GroupIndex).PositionList(PosIndex).SetIsValidPosFromTool(SelTool.Uuid)
            Next
         Next
      End If
      ' Se esiste almeno una famiglia di utensili, la seleziono
      If ToolsList.Count > 0 Then
         ToolsList(0).IsSelected = True
         ToolsList(0).NotifyPropertyChanged("IsSelected")
      End If
   End Sub

   ''' <summary>
   ''' Funzione che carica la lista di utensili ed evidenzia quelli usati nel gruppo di lavorazione corrente ma non attrezzati
   ''' </summary>
   Friend Sub LoadMachineTools()
      ' Creo lista utensili utilizzati dal gruppo di lavorazione corrente
      Dim UsedToolList As New List(Of String)
      Dim Machining As Integer = EgtGetFirstOperation()
      While Machining <> GDB_ID.NULL
         If EgtGetOperationType(Machining) <> MCH_OY.DISP Then
            EgtSetCurrMachining(Machining)
            Dim Tuuid As String = String.Empty
            EgtGetMachiningParam(MCH_MP.TUUID, Tuuid)
            UsedToolList.Add(Tuuid)
         End If
         Machining = EgtGetNextOperation(Machining)
      End While
      ' Creo lista utensili per grafica
      Dim ActiveToolsFamilies() As ToolsFamily = MachineUtility.ReadToolFamilies(CurrentMachine.sMachIniFile)
      For Index = 0 To ActiveToolsFamilies.Count - 1
         Dim FamilyToolItem As New FamilyToolItem(ActiveToolsFamilies(Index).Name, ActiveToolsFamilies(Index).Id)
         m_ToolsList.Add(FamilyToolItem)
         Dim nType As Integer = 0
         Dim ToolName As String = String.Empty
         Dim bFound As Boolean = EgtTdbGetFirstTool(ActiveToolsFamilies(Index).Id, ToolName, nType)
         While bFound
            EgtTdbSetCurrTool(ToolName)
            Dim nValue As Integer = 0
            Dim sValue As String = String.Empty
            EgtTdbGetCurrToolParam(MCH_TP.EXIT_, nValue)
            Dim ExitPar As String = nValue.ToString()
            EgtTdbGetCurrToolParam(MCH_TP.HEAD, sValue)
            Dim Head As String = sValue
            EgtTdbGetCurrToolParam(MCH_TP.TCPOS, sValue)
            Dim TcPos As String = sValue
            EgtTdbGetCurrToolParam(MCH_TP.UUID, sValue)
            Dim Uuid As String = sValue
            Dim IsInCurrMachGroup As Boolean = If(UsedToolList.Contains(Uuid), True, False)
            FamilyToolItem.Items.Add(New ToolItem(ToolName, ExitPar, nType, Head, TcPos, Uuid, IsInCurrMachGroup))
            bFound = EgtTdbGetNextTool(ActiveToolsFamilies(Index).Id, ToolName, nType)
         End While
      Next
   End Sub

   ''' <summary>
   ''' Funzione che dato l'indice di una posizione, la crea secondo il modello standard presente nello script Lua
   ''' </summary>
   Private Function CreateStdPosFromPosIndex(Index As Integer) As Boolean
      Dim sTcPos As String = String.Empty
      Dim sHead As String = String.Empty
      Dim sGroup As String = String.Empty
      Dim nErr As Integer = 999
      EgtLuaSetGlobIntVar("STU.INDEX", Index)
      EgtLuaCallFunction("STU.GetTcPosHeadGroupFromPos")
      ' Leggo variabili
      EgtLuaGetGlobStringVar("STU.TCPOS", sTcPos)
      EgtLuaGetGlobStringVar("STU.HEAD", sHead)
      EgtLuaGetGlobStringVar("STU.GROUP", sGroup)
      EgtLuaGetGlobIntVar("STU.ERR", nErr)
      ' se l'indice del gruppo è valido
      Dim nGroup As Integer = If(Integer.TryParse(sGroup.Trim("G"c), nGroup), nGroup, 0)
      If VerifyIndexValidity(nGroup) Then
         m_PositionGroupList(nGroup - 1).PositionList.Add(New Position(sTcPos, sHead, EgtGetHeadExitCount(sHead)))
      End If
      Return (nErr = 0)
   End Function

   ''' <summary>
   ''' Funzione che mantiene le posizioni ma elimina tutti gli utensili attrezzati
   ''' </summary>
   Friend Sub ClearAllPos()
      For GroupIndex = 0 To m_PositionGroupList.Count - 1
         For PositionIndex = 0 To m_PositionGroupList(GroupIndex).PositionList.Count - 1
            For ExitIndex = 0 To m_PositionGroupList(GroupIndex).PositionList(PositionIndex).ExitToolAssociationList.Count - 1
               Dim TempExit As ExitToolAssociation = m_PositionGroupList(GroupIndex).PositionList(PositionIndex).ExitToolAssociationList(ExitIndex)
               ' e lo tolgo dalla posizione di attrezzaggio
               TempExit.SetTool(Nothing)
               TempExit.IsOccupied = False
            Next
         Next
      Next
   End Sub

   ''' <summary>
   ''' Funzione che verifica che l'indice del gruppo sia valido, esista, e nel caso non esistesse aggiunge i gruppi necessari
   ''' </summary>
   Private Function VerifyIndexValidity(nGroupIndex As Integer) As Boolean
      ' verifico che l'indice del gruppo sia valido
      If nGroupIndex >= 1 Then
         ' verifico che l'indice del gruppo sia compreso nel range di quelli esistenti
         If nGroupIndex <= m_PositionGroupList.Count Then
            Return True
            ' se l'indice è maggiore di quelli presenti nella lista dei gruppi
         Else
            ' aggiungo i gruppi che mancano fino all'indice del mio
            For GroupIndex = m_PositionGroupList.Count To nGroupIndex - 1
               m_PositionGroupList.Add(New PositionGroup)
            Next
            Return True
         End If
         ' altrimenti
      Else
         ' mi assicuro che esista il primo gruppo
         VerifyIndexValidity(1)
         Return False
      End If
   End Function

   ''' <summary>
   ''' Funzione che dati l'indice della posizione e la sua stringa di attrezzaggio, carica l'attrezzaggio descritto
   ''' </summary>
   Private Sub ReadPositionString(nIndex As Integer, sPosition As String, bOriginal As Boolean)
      Dim sTcPos As String = String.Empty
      Dim sHead As String = String.Empty
      Dim sExitList As New List(Of String)
      Dim sToolList As New List(Of String)
      Dim sToolNameList As New List(Of String)
      ' la spezzo sui ;
      Dim sItems() As String = sPosition.Split(";".ToCharArray)
      ' se c'è almeno un elemento sono sicuro che ci sia la T
      If sItems.Count() >= 1 Then
         Dim nGroup As Integer = 0
         sTcPos = sItems(0)
         ' recupero il suo gruppo
         If Not GetGroupFromTcPos(sTcPos, nGroup) Then
            ' se non lo trovo lo metto nel primo
            nGroup = 1
         End If
         If Not VerifyIndexValidity(nGroup) Then
            ' se mi viene passato un indice non valido, lo metto nel primo
            nGroup = 1
         End If
         ' se ci sono almeno due elementi sono sicuro che ci sia la H
         If sItems.Count >= 2 Then
            sHead = sItems(1)
            ' se ci sono almeno tre elementi sono sicuro che ci sia almeno un'uscita attrezzata
            If sItems.Count >= 3 Then
               ' separo le uscite divise dalla ,
               Dim sExitToolAssList() As String = sItems(2).Split(",".ToCharArray)
               sExitList.Clear()
               sToolList.Clear()
               sToolNameList.Clear()
               ' creo le liste di uscite e utensili attrezzati ricavati
               For AssIndex = 0 To sExitToolAssList.Count() - 1
                  Dim sExitToolAssItem() As String = sExitToolAssList(AssIndex).Split("/".ToCharArray)
                  If sExitToolAssItem.Count > 1 Then
                     sExitList.Add(sExitToolAssItem(0))
                     sToolList.Add(sExitToolAssItem(1))
                     sToolNameList.Add(sExitToolAssItem(2))
                  End If
               Next
               ' analizzo la lista di utensili attrezzati
               For ToolIndex = 0 To sToolList.Count - 1
                  If Not String.IsNullOrEmpty(sToolList(ToolIndex)) Then
                     Dim TempTool As ToolItem = Nothing
                     Dim TempFamilyIndex As Integer = -1
                     Dim TempToolIndex As Integer = -1
                     Dim bToolFound As Boolean = False
                     ' cerco l'utensile attrezzato nella lista utensili
                     For FamilyListIndex = 0 To m_ToolsList.Count - 1
                        For ToolListIndex = 0 To m_ToolsList(FamilyListIndex).Items.Count - 1
                           TempTool = DirectCast(m_ToolsList(FamilyListIndex).Items(ToolListIndex), ToolItem)
                           If TempTool.Uuid = sToolList(ToolIndex) Then
                              TempFamilyIndex = FamilyListIndex
                              TempToolIndex = ToolListIndex
                              bToolFound = True
                              Exit For
                           End If
                        Next
                        If bToolFound Then Exit For
                     Next
                     ' se lo trovo
                     If bToolFound Then
                        ' cerco la relativa uscita
                        Dim bFoundPos As Boolean = False
                        For PositionIndex = 0 To m_PositionGroupList(nGroup - 1).PositionList.Count - 1
                           Dim TempPosition As Position = m_PositionGroupList(nGroup - 1).PositionList(PositionIndex)
                           If TempPosition.TcPos = sTcPos Then
                              bFoundPos = True
                              ' verifico se la testa è diversa
                              If TempPosition.Head <> sHead Then
                                 ' altrimenti la sovrascrivo
                                 TempPosition.Head = sHead
                                 ' la metto anche come testa originale
                                 If bOriginal Then TempPosition.OrigHead = sHead
                                 ' e verifico il numero di uscite
                                 For ExitIndex = TempPosition.ExitToolAssociationList.Count + 1 To EgtGetHeadExitCount(sHead)
                                       TempPosition.ExitToolAssociationList.Add(New ExitToolAssociation(ExitIndex.ToString, TempPosition))
                                    Next
                                    For ExitIndex = TempPosition.ExitToolAssociationList.Count - 1 To EgtGetHeadExitCount(sHead) Step -1
                                       TempPosition.ExitToolAssociationList.RemoveAt(ExitIndex)
                                    Next
                                 End If
                                 For ExitIndex = 0 To TempPosition.ExitToolAssociationList.Count - 1
                                 Dim CurrExitToolAss As ExitToolAssociation = TempPosition.ExitToolAssociationList(ExitIndex)
                                 If CurrExitToolAss.ExitPar = sExitList(ToolIndex) Then
                                    ' vi metto l'utensile e segno l'uscita come occupata
                                    CurrExitToolAss.SetTool(TempTool)
                                    CurrExitToolAss.IsOccupied = True
                                    CurrExitToolAss.NotifyPropertyChanged("ToolTipMsg")
                                    ' lo metto anche come utensile originale
                                    If bOriginal Then CurrExitToolAss.OrigTool = TempTool
                                    Exit For
                                 End If
                              Next
                              Exit For
                           End If
                        Next
                        ' se posizione trovata, devo togliere l'utensile dalla lista utensili
                        If bFoundPos Then
                           m_ToolsList(TempFamilyIndex).Items.Remove(m_ToolsList(TempFamilyIndex).Items(TempToolIndex))
                        End If
                     ' altrimenti, se non l'ho trovato
                     Else
                        Dim sSearchedTool As String = String.Empty
                        EgtTdbGetToolFromUUID(sToolList(ToolIndex), sSearchedTool)
                        If String.IsNullOrWhiteSpace(sSearchedTool) Then sSearchedTool = sToolNameList(ToolIndex)
                        If Not String.IsNullOrWhiteSpace(sSearchedTool) Then
                           ' Impossibile trovare l'utensile xxx nel DB utensili
                           MessageBox.Show(EgtMsg(MSG_SETUPERRORS + 3) & " " & sSearchedTool & " " & EgtMsg(MSG_SETUPERRORS + 4), EgtMsg(MSG_SETUPERRORS + 2), MessageBoxButton.OK, MessageBoxImage.Error)
                        Else
                           ' Impossibile trovare l'utensile nel DB utensili
                           MessageBox.Show(EgtMsg(MSG_SETUPERRORS + 3) & " " & EgtMsg(MSG_SETUPERRORS + 4), EgtMsg(MSG_SETUPERRORS + 2), MessageBoxButton.OK, MessageBoxImage.Error)
                        End If
                     End If
                  End If
               Next
            End If
         End If
      End If
   End Sub

   ''' <summary>
   ''' Funzione che data una T restituisce il gruppo a cui appartiene
   ''' </summary>
   Private Function GetGroupFromTcPos(sTcPos As String, ByRef nGroup As Integer) As Boolean
      Dim sGroup As String = String.Empty
      Dim nErr As Integer = 999
      EgtLuaSetGlobStringVar("STU.TCPOS", sTcPos)
      EgtLuaCallFunction("STU.GetGroupFromTcPos")
      ' Leggo variabili
      EgtLuaGetGlobStringVar("STU.GROUP", sGroup)
      EgtLuaGetGlobIntVar("STU.ERR", nErr)
      If nErr = 0 Then
         nGroup = If(Integer.TryParse(sGroup.Trim("G"c), nGroup), nGroup, 0)
         Return True
      End If
      nGroup = 0
      Return False
   End Function

   ''' <summary>
   ''' Funzione che data una T ne restituisce la posizione
   ''' </summary>
   Private Function GetPositionFromTcPos(sTcPos As String, ByRef nPosIndex As Integer) As Boolean
      Dim sPosition As String = String.Empty
      Dim nErr As Integer = 999
      EgtLuaSetGlobStringVar("STU.TCPOS", sTcPos)
      EgtLuaCallFunction("STU.GetPosFromTcPos")
      ' Leggo variabili
      EgtLuaGetGlobStringVar("STU.POS", sPosition)
      EgtLuaGetGlobIntVar("STU.ERR", nErr)
      If nErr = 0 Then
         nPosIndex = If(Integer.TryParse(sPosition.Replace("Pos", ""), nPosIndex), nPosIndex, -1)
         Return (nPosIndex >= 0)
      End If
      nPosIndex = -1
      Return False
   End Function

   ''' <summary>
   ''' Funzione che verifica se ci sono state modifiche all'attrezzaggio corrente
   ''' </summary>
   Friend Function IsAppliedSetUp() As Boolean
      For GroupIndex = 0 To PositionGroupList.Count - 1
         For PositionIndex = 0 To PositionGroupList(GroupIndex).PositionList.Count - 1
            For ExitIndex = 0 To PositionGroupList(GroupIndex).PositionList(PositionIndex).ExitToolAssociationList.Count - 1
               Dim CurrExitToolAss As ExitToolAssociation = PositionGroupList(GroupIndex).PositionList(PositionIndex).ExitToolAssociationList(ExitIndex)
               If Not CurrExitToolAss.m_IsAppliedTool Or Not PositionGroupList(GroupIndex).PositionList(PositionIndex).m_IsAppliedHead Then
                  Return False
               End If
            Next
         Next
      Next
      Return True
   End Function

   Friend Function IsModifiedSetUp() As Boolean
      For GroupIndex = 0 To PositionGroupList.Count - 1
         For PositionIndex = 0 To PositionGroupList(GroupIndex).PositionList.Count - 1
            For ExitIndex = 0 To PositionGroupList(GroupIndex).PositionList(PositionIndex).ExitToolAssociationList.Count - 1
               Dim CurrExitToolAss As ExitToolAssociation = PositionGroupList(GroupIndex).PositionList(PositionIndex).ExitToolAssociationList(ExitIndex)
               If CurrExitToolAss.m_IsModifiedTool Or PositionGroupList(GroupIndex).PositionList(PositionIndex).m_IsModifiedHead Then
                  Return True
               End If
            Next
         Next
      Next
      Return False
   End Function

   Friend Function ResetModifiedSetUp() As Boolean
      For GroupIndex = 0 To PositionGroupList.Count - 1
         For PositionIndex = 0 To PositionGroupList(GroupIndex).PositionList.Count - 1
            For ExitIndex = 0 To PositionGroupList(GroupIndex).PositionList(PositionIndex).ExitToolAssociationList.Count - 1
               Dim CurrExitToolAss As ExitToolAssociation = PositionGroupList(GroupIndex).PositionList(PositionIndex).ExitToolAssociationList(ExitIndex)
               CurrExitToolAss.m_IsModifiedTool = False
               PositionGroupList(GroupIndex).PositionList(PositionIndex).m_IsModifiedHead = False
            Next
         Next
      Next
      Return False
   End Function

   ''' <summary>
   ''' Funzione che verifica se ci sono state modifiche all'attrezzaggio corrente e permette di attivare e disattivare il bottone applica
   ''' </summary>
   Private Sub SetUp_IsModifiedManager()
      If IsModifiedSetUp() Then
         RaiseEvent SetUp_IsModified()
      End If
   End Sub

   ''' <summary>
   ''' Execute the TreeViewDoubleClick.  This method is invoked by the TreeViewDoubleClickCommand.
   ''' </summary>
   Public Sub ToolDoubleClick(SelToolItem As ToolItem)
      If TypeOf SelToolItem Is ToolItem Then
         Dim SelTool As ToolItem = DirectCast(SelToolItem, ToolItem)
         Dim ErrorList As New List(Of String)
         AutoSetUpTool(SelTool, ErrorList)
         ' verifico se ci sono errori
         If ErrorList.Count > 0 Then
            ' li raccolgo tutti nello stesso messaggio
            Dim sError As String = EgtMsg(MSG_SETUPERRORS + 6) & Environment.NewLine
            For ErrorIndex = 0 To ErrorList.Count - 1
               sError &= "- " & ErrorList(ErrorIndex) & Environment.NewLine
            Next
            MessageBox.Show(sError, EgtMsg(MSG_SETUPERRORS + 2), MessageBoxButton.OK, MessageBoxImage.Exclamation)
         End If
      End If
   End Sub

   Private Function AutoSetUpTool(SelTool As ToolItem, ByRef ErrorList As List(Of String)) As Boolean
      ' cerco il TcPos dell'utensile selezionato nella lista di posizioni
      For GroupIndex = 0 To m_PositionGroupList.Count - 1
         For PositionIndex = 0 To m_PositionGroupList(GroupIndex).PositionList.Count - 1
            Dim CurrPosition As Position = m_PositionGroupList(GroupIndex).PositionList(PositionIndex)
            If CurrPosition.TcPos = SelTool.TcPos Then
               AutoSetUpToolFromPos(SelTool, CurrPosition, ErrorList)
            End If
         Next
      Next
      Return False
   End Function

   Private Function AutoSetUpToolFromPos(SelTool As ToolItem, Position As Position, ByRef ErrorList As List(Of String)) As Boolean
      Dim ExitToolAssociationList As ObservableCollection(Of ExitToolAssociation) = Position.ExitToolAssociationList
      EgtLuaSetGlobStringVar("STU.TUUID", SelTool.Uuid)
      EgtLuaSetGlobStringVar("STU.TCPOS", Position.TcPos)
      EgtLuaCallFunction("STU.GetValidHeadExitForPos")
      ' Leggo variabili
      Dim sHead As String = String.Empty
      EgtLuaGetGlobStringVar("STU.HEAD", sHead)
      Dim nExit As Integer = 0
      EgtLuaGetGlobIntVar("STU.EXIT", nExit)
      Dim nErr As Integer = 999
      EgtLuaGetGlobIntVar("STU.ERR", nErr)
      If nErr <> 0 Then
         Dim sToolName As String = String.Empty
         EgtTdbGetToolFromUUID(SelTool.Uuid, sToolName)
         EgtOutLog("Error in setup! Tool:" & sToolName & " TcPos: " & Position.TcPos)
         Return False
      End If
      ' verifico se la posizione è libera o c'è un utensile attrezzato
      Dim PosIsOccupied As Boolean = False
      For ExitIndex = 0 To ExitToolAssociationList.Count - 1
         If ExitToolAssociationList(ExitIndex).IsOccupied Then
            PosIsOccupied = True
            Exit For
         End If
      Next
      ' se la posizione non è valida, restituisco errore
      If sHead = INVALIDPOS Then
         EgtOutLog("SetUp warning: try to set " & SelTool.Name & " on " & Position.TcPos)
         MessageBox.Show(EgtMsg(MSG_SETUPERRORS + 5), EgtMsg(MSG_SETUPERRORS + 1), MessageBoxButton.OK, MessageBoxImage.Error)
         Return False
      ' altrimenti, se la posizione nell'attrezzaggio è vuota
      ElseIf Not PosIsOccupied Then
         ' verifico se la testa è la stessa
         If Not Position.Head = sHead Then
            ' altrimenti la sovrascrivo
            Position.Head = sHead
            ' e verifico il numero di uscite
            For ExitIndex = Position.ExitToolAssociationList.Count + 1 To EgtGetHeadExitCount(sHead)
               Position.ExitToolAssociationList.Add(New ExitToolAssociation(ExitIndex.ToString, Position))
            Next
            For ExitIndex = Position.ExitToolAssociationList.Count - 1 To EgtGetHeadExitCount(sHead) Step -1
               Position.ExitToolAssociationList.RemoveAt(ExitIndex)
            Next
         End If
         ' lo aggiungo alla posizione di attrezzaggio e lo tolgo dalla lista utensili
         SetToolInPos(SelTool, Position, nExit)
      ' altrimenti, se le teste coincidono
      ElseIf sHead = Position.Head Then
         ' se l'uscita restituita è libera
         If Not ExitToolAssociationList(nExit - 1).IsOccupied Then
            ' lo aggiungo alla posizione di attrezzaggio e lo tolgo dalla lista utensili
            SetToolInPos(SelTool, Position, nExit)
         ' altrimenti restituisco falso
         Else
            ErrorList.Add(SelTool.Name)
            'MessageBox.Show(EgtMsg(MSG_SETUPERRORS + 9) & " " & SelTool.Name & " " & EgtMsg(MSG_SETUPERRORS + 6), EgtMsg(MSG_SETUPERRORS + 2), MessageBoxButton.OK, MessageBoxImage.Exclamation)
            Return False
         End If
      ' altrimenti restituisco falso
      Else
         ErrorList.Add(SelTool.Name)
         'MessageBox.Show(EgtMsg(MSG_SETUPERRORS + 9) & " " & SelTool.Name & " " & EgtMsg(MSG_SETUPERRORS + 6), EgtMsg(MSG_SETUPERRORS + 2), MessageBoxButton.OK, MessageBoxImage.Exclamation)
         Return False
      End If
      Return True
   End Function

   Private Function SetToolInPos(SelTool As ToolItem, Position As Position, nExit As Integer) As Boolean
      Dim bOk As Boolean = False
      ' lo aggiungo alla posizione di attrezzaggio
      For ExitIndex = 0 To Position.ExitToolAssociationList.Count - 1
         If ExitIndex = nExit - 1 Then
            Position.ExitToolAssociationList(ExitIndex).Tool = SelTool
            Position.ExitToolAssociationList(ExitIndex).IsOccupied = True
            Position.ExitToolAssociationList(ExitIndex).NotifyPropertyChanged("ToolTipMsg")
            bOk = True
            Exit For
         End If
      Next
      If Not bOk Then Return False
      bOk = False
      ' e lo tolgo dalla lista utensili
      For Index = 0 To m_ToolsList.Count - 1
         If (SelTool.Type And m_ToolsList(Index).Type) > 0 Then
            m_ToolsList(Index).Items.Remove(SelTool)
            bOk = True
            Exit For
         End If
      Next
      Return bOk
   End Function

   ''' <summary>
   ''' Funzione che salva il setup corrente
   ''' </summary>
   Public Function Save(sFilePath As String) As Boolean
      ' verifica path
      If Not Directory.Exists(Path.GetDirectoryName(sFilePath)) Then Return False
      ' creo il file con il solo commento come prima linea
      File.WriteAllLines(sFilePath, {"; Commento per evitare BOM con UTF-8"}, Text.Encoding.UTF8)

      For GroupIndex = 0 To m_PositionGroupList.Count - 1
         For PositionIndex = 0 To m_PositionGroupList(GroupIndex).PositionList.Count - 1
            Dim CurrPosition As Position = m_PositionGroupList(GroupIndex).PositionList(PositionIndex)
            Dim sPosition As String = String.Empty
            sPosition = CurrPosition.TcPos
            Dim sExitToolAssociation As String = String.Empty
            For AssIndex = 0 To CurrPosition.ExitToolAssociationList.Count - 1
               sExitToolAssociation &= If(CurrPosition.ExitToolAssociationList(AssIndex).IsOccupied,
                                          CurrPosition.ExitToolAssociationList(AssIndex).ExitPar & "/" &
                                          CurrPosition.ExitToolAssociationList(AssIndex).Tool.Uuid & "/" &
                                          CurrPosition.ExitToolAssociationList(AssIndex).Tool.Name & ",", String.Empty)
            Next
            sExitToolAssociation = sExitToolAssociation.Trim(","c)
            If Not String.IsNullOrEmpty(sExitToolAssociation) Then
               sPosition &= ";" & CurrPosition.Head & ";" & sExitToolAssociation
            End If
            Dim nPosition As Integer
            If GetPositionFromTcPos(m_PositionGroupList(GroupIndex).PositionList(PositionIndex).TcPos, nPosition) Then
               EgtUILib.WritePrivateProfileString(S_GENERAL, K_POS & nPosition, sPosition, sFilePath)
            End If
         Next
      Next
      Return True
   End Function

   ''' <summary>
   ''' Funzione che applica il setup corrente al gruppo di lavoro corrente
   ''' </summary>
   Public Sub Apply()
      ' ricavo il gruppo in cui mettere l'attrezzaggio
      Dim nSetUpGroup As Integer = EgtGetCurrSetup()
      For GroupIndex = 0 To m_PositionGroupList.Count - 1
         For PositionIndex = 0 To m_PositionGroupList(GroupIndex).PositionList.Count - 1
            Dim CurrPosition As Position = m_PositionGroupList(GroupIndex).PositionList(PositionIndex)
            Dim sPosition As String = String.Empty
            sPosition = CurrPosition.TcPos
            CurrPosition.OrigHead = CurrPosition.Head
            Dim sExitToolAssociation As String = String.Empty
            For ExitIndex = 0 To CurrPosition.ExitToolAssociationList.Count - 1
               Dim CurrExitToolAss As ExitToolAssociation = CurrPosition.ExitToolAssociationList(ExitIndex)
               sExitToolAssociation &= If(CurrExitToolAss.IsOccupied,
                                          CurrExitToolAss.ExitPar & "/" &
                                          CurrExitToolAss.Tool.Uuid & "/" &
                                          CurrExitToolAss.Tool.Name & ",", String.Empty)
               CurrExitToolAss.OrigTool = CurrExitToolAss.Tool
            Next
            sExitToolAssociation = sExitToolAssociation.Trim(","c)
            If Not String.IsNullOrEmpty(sExitToolAssociation) Then
               sPosition &= ";" & CurrPosition.Head & ";" & sExitToolAssociation
            End If
            Dim nPosition As Integer
            If GetPositionFromTcPos(CurrPosition.TcPos, nPosition) Then
               EgtSetInfo(nSetUpGroup, K_POS & nPosition, sPosition)
            End If
         Next
      Next
      m_IsEnabledApplyBtn = False
      NotifyPropertyChanged("IsEnabledApplyBtn")
      ' aggiorno le librerie sottostanti
      EgtUpdateCurrSetup()
   End Sub

   ''' <summary>
   ''' Funzione che posiziona gli utensili nelle posizioni di setup predefinite
   ''' </summary>
   Public Sub Automatic()
      ' verifico il tipo di elemento selezionato
      Dim bIsToolItem As Boolean = False
      ' recupero utensile correntemente selezionato
      Dim SelTool As ToolItem = Nothing
      Dim bFounded As Boolean = False
      For Each Toolfamily In m_ToolsList
         For Each Tool In Toolfamily.Items
            If Tool.IsSelected Then
               SelTool = DirectCast(Tool, ToolItem)
               bIsToolItem = Not SelTool.IsInCurrMachGroup
               bFounded = True
               Exit For
            End If
         Next
         If bFounded Then Exit For
      Next

      Dim ErrorList As New List(Of String)
      ' analizzo la lista degli utensili alla ricerca di quelli usati nel progetto corrente
      For FamilyIndex = 0 To m_ToolsList.Count - 1
         ' verifico se nella famiglia c'è almeno un utensile usato nel progetto
         If m_ToolsList(FamilyIndex).HaveToolsInCurrMachGroup Then
            ' analizzo gli utensili all'interno della famiglia
            For ToolIndex = m_ToolsList(FamilyIndex).Items.Count - 1 To 0 Step -1
               Dim CurrTool As ToolItem = DirectCast(m_ToolsList(FamilyIndex).Items(ToolIndex), ToolItem)
               ' se l'utensile è utilizzato
               If CurrTool.IsInCurrMachGroup Then
                  ' lo attrezzo al suo posto predefinito
                  AutoSetUpTool(CurrTool, ErrorList)
               End If
            Next
         End If
      Next

      ' verifico se ci sono errori
      If ErrorList.Count > 0 Then
         ' li raccolgo tutti nello stesso messaggio
         Dim sError As String = EgtMsg(MSG_SETUPERRORS + 6) & Environment.NewLine
         For ErrorIndex = 0 To ErrorList.Count - 1
            sError &= "- " & ErrorList(ErrorIndex) & Environment.NewLine
         Next
         MessageBox.Show(sError, EgtMsg(MSG_SETUPERRORS + 2), MessageBoxButton.OK, MessageBoxImage.Exclamation)
      End If

      ' abilito e disabilito tutte le uscite in base all'utensile selezionato 
      For GroupIndex = 0 To m_PositionGroupList.Count - 1
         For PosIndex = 0 To m_PositionGroupList(GroupIndex).PositionList.Count - 1
            If bIsToolItem Then
               m_PositionGroupList(GroupIndex).PositionList(PosIndex).SetIsValidPosFromTool(SelTool.Uuid)
            Else
               m_PositionGroupList(GroupIndex).PositionList(PosIndex).SetNotValidPos()
            End If
         Next
      Next
   End Sub

#End Region    ' METHODS

End Class
