Imports System.Collections.ObjectModel
Imports EgtWPFLib5
Imports EgtUILib
Imports EgtBEAMWALL.Core
Imports System.Windows.Threading
Imports EgtBEAMWALL.DataLayer.DatabaseModels
Imports EgtBEAMWALL.Core.MachLog

Public Class MachineLogPageVM
   Inherits VMBase

   Private m_Lock_LogList As New Object

   Private m_MachineLog_Timer As New DispatcherTimer

   Private Enum DayTypes As Integer
      TODAY = 0
      YESTERDAY = 1
      PERIOD = 2
   End Enum

   Private m_colMachineLog_Type As EgtDataGridColumn
   Public ReadOnly Property colMachineLog_Type As EgtDataGridColumn
      Get
         Return m_colMachineLog_Type
      End Get
   End Property
   Private m_colMachineLog_Description As EgtDataGridColumn
   Public ReadOnly Property colMachineLog_Description As EgtDataGridColumn
      Get
         Return m_colMachineLog_Description
      End Get
   End Property
   Private m_colMachineLog_SupervisorId As EgtDataGridColumn
   Public ReadOnly Property colMachineLog_SupervisorId As EgtDataGridColumn
      Get
         Return m_colMachineLog_SupervisorId
      End Get
   End Property

   Private m_MachineLogColumns As New ObservableCollection(Of EgtDataGridColumn)
   Public Property MachineLogColumns As ObservableCollection(Of EgtDataGridColumn)
      Get
         Return m_MachineLogColumns
      End Get
      Set(value As ObservableCollection(Of EgtDataGridColumn))
         m_MachineLogColumns = value
      End Set
   End Property

   Private m_MachineLogList_View As CollectionView = Nothing
   Private m_MachineLogList As New ObservableCollection(Of LogEvent)
   Public Property MachineLogList As ObservableCollection(Of LogEvent)
      Get
         Return m_MachineLogList
      End Get
      Set(value As ObservableCollection(Of LogEvent))
         m_MachineLogList = value
      End Set
   End Property

   Private m_MachLogTypeList As New List(Of MachLogType)({New MachLogType(MachLogTypes.PART_STATUS, "PartStatus", True),
                                                          New MachLogType(MachLogTypes.MACHGROUP_STATUS, "MachGroupStatus", True),
                                                          New MachLogType(MachLogTypes.MACHINE_MODE, "MachineMode", True),
                                                          New MachLogType(MachLogTypes.ALARM, "Alarm", True)})
   Public Property MachLogTypeList As List(Of MachLogType)
      Get
         Return m_MachLogTypeList
      End Get
      Set(value As List(Of MachLogType))
         m_MachLogTypeList = value
      End Set
   End Property

   Private m_PartEventTypeList As New List(Of String)({"", EgtMsg(62527), EgtMsg(62528)})
   Public ReadOnly Property PartEventTypeList As List(Of String)
      Get
         Return m_PartEventTypeList
      End Get
   End Property

   Private m_SelPartEventType As Integer
   Public Property SelPartEventType As Integer
      Get
         Return m_SelPartEventType
      End Get
      Set(value As Integer)
         m_SelPartEventType = value
         WriteMainPrivateProfileString(S_MACHINELOGFILTER, K_PARTEVENTTYPE, m_SelPartEventType.ToString())
         m_MachineLogList_View.Refresh()
      End Set
   End Property

   Private m_EntityTypeList As New List(Of String)({"", EgtMsg(62525), EgtMsg(62526)})
   Public ReadOnly Property EntityTypeList As List(Of String)
      Get
         Return m_EntityTypeList
      End Get
   End Property

   Private m_SelEntityType As Integer
   Public Property SelEntityType As Integer
      Get
         Return m_SelEntityType
      End Get
      Set(value As Integer)
         m_SelEntityType = value
         WriteMainPrivateProfileString(S_MACHINELOGFILTER, K_ENTITYTYPE, m_SelEntityType.ToString())
         m_MachineLogList_View.Refresh()
      End Set
   End Property

   Private m_DayTypeList As New List(Of String)({EgtMsg(62529), EgtMsg(62530), EgtMsg(62531)})
   Public ReadOnly Property DayTypeList As List(Of String)
      Get
         Return m_DayTypeList
      End Get
   End Property

   Private m_SelDayType As DayTypes = DayTypes.TODAY
   Public Property SelDayType As Integer
      Get
         Return m_SelDayType
      End Get
      Set(value As Integer)
         Dim PrevSelDayType As DayTypes = m_SelDayType
         m_SelDayType = value
         WriteMainPrivateProfileString(S_MACHINELOGFILTER, K_DAYTYPE, Convert.ToInt32(m_SelDayType))
         m_Date_Visibility = If(m_SelDayType = DayTypes.PERIOD, Visibility.Visible, Visibility.Collapsed)
         If m_SelDayType = DayTypes.PERIOD Then
            m_dtStartDate = If(PrevSelDayType = DayTypes.TODAY, DateTime.Today, DateTime.Today - TimeSpan.FromDays(1))
            m_dtEndDate = If(PrevSelDayType = DayTypes.TODAY, DateTime.Today, DateTime.Today - TimeSpan.FromDays(1))
            NotifyPropertyChanged(NameOf(dtStartDate))
            NotifyPropertyChanged(NameOf(dtEndDate))
         End If
         NotifyPropertyChanged(NameOf(Date_Visibility))
         ' aggiorno lista da Db
         UpdateMachineLogList(True)
      End Set
   End Property

   Private m_dtStartDate As DateTime = DateTime.Today
   Public Property dtStartDate As DateTime
      Get
         Return m_dtStartDate
      End Get
      Set(value As DateTime)
         m_dtStartDate = value
         Dim lStartDate As Long = m_dtStartDate.ToFileTimeUtc()
         WriteMainPrivateProfileString(S_MACHINELOGFILTER, K_STARTDATE, lStartDate.ToString())
         ' aggiorno lista da Db
         UpdateMachineLogList(True)
      End Set
   End Property

   Private m_dtEndDate As DateTime = DateTime.Today
   Public Property dtEndDate As DateTime
      Get
         Return m_dtEndDate
      End Get
      Set(value As DateTime)
         m_dtEndDate = value
         Dim lEndDate As Long = m_dtEndDate.ToFileTimeUtc()
         WriteMainPrivateProfileString(S_MACHINELOGFILTER, K_ENDDATE, lEndDate.ToString())
         ' aggiorno lista da Db
         UpdateMachineLogList(True)
      End Set
   End Property

   Private m_Date_Visibility As Visibility = Visibility.Collapsed
   Public ReadOnly Property Date_Visibility As Visibility
      Get
         Return m_Date_Visibility
      End Get
   End Property

   ' Definizione comandi
   Private m_cmdRefresh As ICommand

#Region "Messages"

   Public ReadOnly Property EventDateTime_Msg As String
      Get
         Return EgtMsg(62512)
      End Get
   End Property

   Public ReadOnly Property EventType_Msg As String
      Get
         Return EgtMsg(62513)
      End Get
   End Property

   Public ReadOnly Property EventValue_Msg As String
      Get
         Return EgtMsg(62514)
      End Get
   End Property

   Public ReadOnly Property SupervisorId_Msg As String
      Get
         Return EgtMsg(62515)
      End Get
   End Property

   Public ReadOnly Property ProdId_Msg As String
      Get
         Return EgtMsg(62516)
      End Get
   End Property

   Public ReadOnly Property MachGroupId_Msg As String
      Get
         Return EgtMsg(62517)
      End Get
   End Property

   Public ReadOnly Property PartId_Msg As String
      Get
         Return EgtMsg(62518)
      End Get
   End Property

   Public ReadOnly Property Status_Msg As String
      Get
         Return EgtMsg(62519)
      End Get
   End Property

   Public ReadOnly Property Entity_Msg As String
      Get
         Return EgtMsg(62520)
      End Get
   End Property

   Public ReadOnly Property Event_Msg As String
      Get
         Return EgtMsg(62521)
      End Get
   End Property

   Public ReadOnly Property Date_Msg As String
      Get
         Return EgtMsg(62522)
      End Get
   End Property

   Public ReadOnly Property From_Msg As String
      Get
         Return EgtMsg(62523)
      End Get
   End Property

   Public ReadOnly Property To_Msg As String
      Get
         Return EgtMsg(62524)
      End Get
   End Property

#End Region    ' Messages

#Region "CONSTRUCTORS"

   Sub New()
      ' imposto riferimento in Map
      Map.SetRefMachineLogPageVM(Me)
      ' carico le colonne della datagrid
      GetPrivateProfileColumns(S_MACHINELOG, MachineLogColumns)
      m_MachineLogList_View = CollectionViewSource.GetDefaultView(m_MachineLogList)
      m_MachineLogList_View.Filter = AddressOf MachineLogFilter
      ' recupero riferimento a colonna StartCut
      m_colMachineLog_Type = m_MachineLogColumns.FirstOrDefault(Function(x) x.Name = COL_TYPE)
      m_colMachineLog_Description = m_MachineLogColumns.FirstOrDefault(Function(x) x.Name = COL_DESCRIPTION)
      m_colMachineLog_SupervisorId = m_MachineLogColumns.FirstOrDefault(Function(x) x.Name = COL_SUPERVISORID)
      ' imposto valori filtri da ini
      m_SelPartEventType = GetMainPrivateProfileInt(S_MACHINELOGFILTER, K_PARTEVENTTYPE, 2)
      m_SelEntityType = GetMainPrivateProfileInt(S_MACHINELOGFILTER, K_ENTITYTYPE, 1)
      m_SelDayType = GetMainPrivateProfileInt(S_MACHINELOGFILTER, K_DAYTYPE, 0)
      Select Case m_SelDayType
         Case DayTypes.TODAY
            m_dtStartDate = DateTime.Today
            m_dtEndDate = DateTime.Today
         Case DayTypes.YESTERDAY
            m_dtStartDate = DateTime.Today - TimeSpan.FromDays(1)
            m_dtEndDate = DateTime.Today - TimeSpan.FromDays(1)
         Case DayTypes.PERIOD
            Dim sStartDate As String = "0"
            Dim lStartDate As Long = 0
            GetMainPrivateProfileString(S_MACHINELOGFILTER, K_STARTDATE, 0, sStartDate)
            Long.TryParse(sStartDate, lStartDate)
            m_dtStartDate = If(lStartDate > 0, DateTime.FromFileTimeUtc(lStartDate), DateTime.Today)
            Dim sEndDate As String = "0"
            Dim lEndDate As Long = 0
            GetMainPrivateProfileString(S_MACHINELOGFILTER, K_ENDDATE, 0, sEndDate)
            Long.TryParse(sEndDate, lEndDate)
            m_dtEndDate = If(lEndDate > 0, DateTime.FromFileTimeUtc(lEndDate), DateTime.Today)
            m_Date_Visibility = Visibility.Visible
      End Select
      m_MachineLog_Timer.Interval = TimeSpan.FromMilliseconds(100)
      AddHandler m_MachineLog_Timer.Tick, AddressOf MachineLog_Timer_Tick
      m_MachineLog_Timer.Start()
   End Sub

#End Region    ' CONSTRUCTORS

#Region "METHODS"

   Private Function MachineLogFilter(CurrEvent As Object) As Boolean
      Dim CurrLogEvent As LogEvent = DirectCast(CurrEvent, LogEvent)
      Dim bOk As Boolean = True
      ' se livello utente inferiore a 5, mostro solo eventi pezzo e machgroup
      If Map.refMainWindowVM.MainWindowM.nUserLevel < 5 Then
         If CurrLogEvent.EventType <> LogEvent.MachLogTypes.PART_STATUS AndAlso CurrLogEvent.EventType <> LogEvent.MachLogTypes.MACHGROUP_STATUS Then
            Return False
         End If
      End If
      Select Case m_SelEntityType
         Case 0   ' ""
            bOk = bOk And True
         Case 1   ' "Pezzo"
            bOk = bOk And CurrLogEvent.EventType = LogEvent.MachLogTypes.PART_STATUS
         Case 2   ' "Barra"
            bOk = bOk And CurrLogEvent.EventType = LogEvent.MachLogTypes.MACHGROUP_STATUS
      End Select
      If CurrLogEvent.EventType = LogEvent.MachLogTypes.PART_STATUS OrElse CurrLogEvent.EventType = LogEvent.MachLogTypes.MACHGROUP_STATUS Then
         Select Case m_SelPartEventType
            Case 0   ' ""
               bOk = bOk And True
            Case 1   ' "Inizio"
               bOk = bOk And CurrLogEvent.nStatus = 1
            Case 2   ' "Fine"
               bOk = bOk And CurrLogEvent.nStatus = 2
         End Select
      End If
      Return bOk
   End Function

   Friend Sub LoadMachineLogList()
      If Map.refMainWindowVM.MainWindowM.nUserLevel < 5 Then
         m_colMachineLog_Type.ColumnVisibility = Visibility.Collapsed
         m_colMachineLog_Description.ColumnVisibility = Visibility.Collapsed
         m_colMachineLog_SupervisorId.ColumnVisibility = Visibility.Collapsed
      End If
      UpdateMachineLogList(True)
      m_MachineLogList_View = CollectionViewSource.GetDefaultView(m_MachineLogList)
      m_MachineLogList_View.Filter = AddressOf MachineLogFilter
   End Sub

   ' indice di aggiornamento della lista rispetto a Db
   Private m_nUpdateIndex As Integer
   ' indice di ricaricamento completo della lista dal Db
   Private m_nRefreshIndex As Integer
   ' indice dell'ultimo update/refresh
   Private m_nLastLogUpdate As Integer

   Friend Sub UpdateMachineLogList(bRefresh As Boolean)
      Dim nMaxIndex As Integer = Math.Max(m_nUpdateIndex, m_nRefreshIndex)
      If bRefresh Then
         m_nRefreshIndex = nMaxIndex + 1
      Else
         m_nUpdateIndex = nMaxIndex + 1
      End If
   End Sub

   Private Sub MachineLog_Timer_Tick(sender As Object, e As EventArgs)
      SyncLock m_Lock_LogList
         Dim nRefresh As Integer = m_nRefreshIndex
         Dim nUpdate As Integer = m_nUpdateIndex
         If nRefresh > m_nLastLogUpdate Then
            m_nLastLogUpdate = nRefresh
            UpdateFromDb(True)
         ElseIf nUpdate > m_nLastLogUpdate Then
            m_nLastLogUpdate = nUpdate
            UpdateFromDb(False)
         End If
      End SyncLock
   End Sub

   Friend Sub UpdateFromDb(bRefresh As Boolean)
      'm_MachineLogList = New ObservableCollection(Of LogEvent)(DbControllers.m_LogMachineController.GetCoreDesc(DateTime.Now - TimeSpan.FromDays(300), DateTime.Now).Select(Of LogEvent)(Function(x) New LogEvent(x)).ToList())
      Dim DbList As List(Of LogEvent)
      Select Case m_SelDayType
         Case DayTypes.PERIOD
            DbList = DbControllers.m_LogMachineController.GetCoreDesc(m_dtStartDate, m_dtEndDate + TimeSpan.FromDays(1)).Select(Of LogEvent)(Function(x) New LogEvent(x)).ToList()
         Case DayTypes.YESTERDAY
            DbList = DbControllers.m_LogMachineController.GetCoreDesc(DateTime.Today - TimeSpan.FromDays(1), DateTime.Today).Select(Of LogEvent)(Function(x) New LogEvent(x)).ToList()
         Case Else      ' DayTypes.TODAY
            DbList = DbControllers.m_LogMachineController.GetCoreDesc(DateTime.Today, DateTime.Today + TimeSpan.FromDays(1)).Select(Of LogEvent)(Function(x) New LogEvent(x)).ToList()
      End Select
      If bRefresh OrElse m_MachineLogList.Count < 1 Then
         m_MachineLogList = New ObservableCollection(Of LogEvent)(DbList)
      Else
         ' cerco in lista Db ultimo elemento della mia lista
         Dim LastItem As LogEvent = m_MachineLogList(0)
         Dim CommonItem As LogEvent = DbList.FirstOrDefault(Function(x) x.EventDateTime = LastItem.EventDateTime AndAlso x.EventType = LastItem.EventType AndAlso x.SupervisorId = LastItem.SupervisorId AndAlso x.Value = LastItem.Value)
         Dim nCommonItemIndex As Integer
         If Not IsNothing(CommonItem) Then
            nCommonItemIndex = DbList.IndexOf(CommonItem)
         End If
         ' aggiorno i successivi
         If nCommonItemIndex >= 0 Then
            For Index = nCommonItemIndex - 1 To 0 Step -1
               m_MachineLogList.Insert(0, DbList(Index))
            Next
         End If
      End If
      NotifyPropertyChanged(NameOf(MachineLogList))
      m_MachineLogList_View = CollectionViewSource.GetDefaultView(m_MachineLogList)
      m_MachineLogList_View.Filter = AddressOf MachineLogFilter
   End Sub

#End Region    ' METHODS

#Region "COMMANDS"

#Region "Refresh"

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

   ''' <summary>
   ''' Execute the Open.  This method is invoked by the OpenCommand.
   ''' </summary>
   Friend Sub Refresh()
      UpdateMachineLogList(False)
   End Sub

#End Region ' Refresh

#End Region    ' COMMANDS

End Class

Public Class MachLogType
   Inherits VMBase

   Private m_nId As Integer
   Public ReadOnly Property nId As Integer
      Get
         Return m_nId
      End Get
   End Property

   Private m_sName As String
   Public ReadOnly Property sName As String
      Get
         Return m_sName
      End Get
   End Property

   Private m_bOn As Boolean = False
   Public Property bOn As Boolean
      Get
         Return m_bOn
      End Get
      Set(value As Boolean)
         m_bOn = value
      End Set
   End Property

   Sub New(nId As Integer, sName As String, bOn As Boolean)
      m_nId = nId
      m_sName = sName
      m_bOn = bOn
   End Sub

End Class