Index: ActiviteitenOpvolging/ActiviteitenOpvolging/enums/ActivityStateEnum.vb =================================================================== diff -u -r1666 -r1671 --- ActiviteitenOpvolging/ActiviteitenOpvolging/enums/ActivityStateEnum.vb (.../ActivityStateEnum.vb) (revision 1666) +++ ActiviteitenOpvolging/ActiviteitenOpvolging/enums/ActivityStateEnum.vb (.../ActivityStateEnum.vb) (revision 1671) @@ -6,3 +6,30 @@ AllFinished Zero End Enum + +Public Module ActivityStateEnumMapper + ''' + ''' Gets the corresponding enum value from the ActivityStateEnum with a string value. + ''' + ''' The string value + ''' + Public Function GetEnumValueFromString(activityStateValue As String) As ActivityStateEnum + Select Case activityStateValue.ToLower() + Case "defaulted" + Return ActivityStateEnum.Defaulted + Case "pauzed" + Return ActivityStateEnum.Pauzed + Case "started" + Return ActivityStateEnum.Started + Case "finished" + Return ActivityStateEnum.Finished + Case "allfinished" + Return ActivityStateEnum.AllFinished + Case "zero" + Return ActivityStateEnum.Zero + Case Else + Throw New Exception($"The activity state value is unknown for getting a corresponding enum value: '{activityStateValue}'.") + End Select + End Function + +End Module Index: ActiviteitenOpvolging/ActiviteitenOpvolging/configs/ConfigsLoader.vb =================================================================== diff -u -r1669 -r1671 --- ActiviteitenOpvolging/ActiviteitenOpvolging/configs/ConfigsLoader.vb (.../ConfigsLoader.vb) (revision 1669) +++ ActiviteitenOpvolging/ActiviteitenOpvolging/configs/ConfigsLoader.vb (.../ConfigsLoader.vb) (revision 1671) @@ -1,10 +1,12 @@ Imports System.IO Imports System.Security.Policy +Imports System.Text.RegularExpressions Namespace configs Public Module ConfigsLoader Const MaxNumberOfGrids As Integer = 4 Const MaxNumberOfUsers As Integer = 4 + Const MaxIntervalSeconds As Integer = 3600 'Max of 6 hours Sub New() Try @@ -14,32 +16,15 @@ LoadDynamicConfigLines(configsTextMapper.GetAllValues(Path.Combine(My.Application.Info.DirectoryPath, "DynamicConfigs.txt"))) ValidateDynamicConfigs() 'Load the general configs. - Dim generalConfigLines = configsTextMapper.GetAllValues("c:\users\test.txt") + LoadGeneralConfigLines(configsTextMapper.GetAllValues(Path.Combine(My.Application.Info.DirectoryPath, "GeneralConfigs.txt"))) + ValidateGeneralConfigs() Catch ex As Exception 'Show error message, it's just easier to handle it here. MessageBox.Show(ex.Message, "An error occured...", MessageBoxButtons.OK, MessageBoxIcon.Error) Application.Exit() End Try End Sub -#Region "General config properties" - Property RefreshIntervalMiliseconds As Integer - Property RefreshTimeStart As DateTime - Property RefreshTimeEnd As DateTime - Property CacheWebserviceUrl As Url -#Region "Colors" - - Property AgColorBatch As Color - Property AgColorProductGroup As Color - Property AgColorTo As Color - - Property ColorsDueOut As New Dictionary(Of DueOutStateEnum, Color) - Property ActivityColors As New Dictionary(Of ActivityStateEnum, Color) - Property ActivityColorsReadonly As New Dictionary(Of ActivityStateEnum, Color) - Property UserColors As New List(Of Integer) -#End Region -#End Region - #Region "Help functions" ''' ''' Extract the identification of the config from the line. Example => 'identification'=600 @@ -68,6 +53,20 @@ Throw New Exception($"Invalid configuration entry. Can't extract the value for the config (the part after the '='): '{configLine}'.") End Try End Function + + ''' + ''' Get the color corresponding to the hexadecimal string code. In seperate function for error handling. + ''' + ''' + ''' + Private Function GetColorFromHexStringValue(hexadecimalColorCode As String) As Color + Try + 'Convert to color and return. + Return ColorTranslator.FromHtml(hexadecimalColorCode) + Catch ex As Exception + Throw New ConfigurationException($"The value '{hexadecimalColorCode}' cannot be converted to a color.") + End Try + End Function #End Region #Region "Dynamic configs" @@ -96,9 +95,12 @@ ''' Private Sub LoadDynamicConfigLines(dynamicConfigLines As IReadOnlyCollection(Of String)) Try + 'Loop through each line. For Each line In dynamicConfigLines + 'Get key and value of a config entry. Dim identifier = ExtractConfigIdentifier(line) Dim value = ExtractConfigValue(line) + If identifier.Equals("AppName") Then _AppName = value ElseIf identifier.Equals("AppID") Then @@ -116,7 +118,7 @@ End If Next Catch ex As InvalidCastException - Throw New ConfigurationException($"One of the values is an invalid type.{vbNewLine}{ex.Message}") + Throw New ConfigurationException($"One of the dynamic config values has an invalid type.{vbNewLine}{ex.Message}") End Try End Sub @@ -158,5 +160,221 @@ End If End Sub #End Region + +#Region "General configs" +#Region "Properties" + Public ReadOnly Property RefreshIntervalSeconds As Integer + Public ReadOnly Property RefreshTimeStart As TimeSpan + Public ReadOnly Property RefreshTimeEnd As TimeSpan + Public ReadOnly Property CacheWebserviceUrl As Url +#Region "Colors" + Public ReadOnly Property AgColorBatch As Color + Public ReadOnly Property AgColorProductGroup As Color + Public ReadOnly Property AgColorTo As Color + Private ReadOnly Property _colorsDueOut As New Dictionary(Of DueOutStateEnum, Color) + Public ReadOnly Property ColorsDueOut As Dictionary(Of DueOutStateEnum, Color) + Get + Return New Dictionary(Of DueOutStateEnum, Color)(_colorsDueOut) + End Get + End Property + Private ReadOnly Property _colorsActivities As New Dictionary(Of ActivityStateEnum, Color) + Public ReadOnly Property ColorsActivities As Dictionary(Of ActivityStateEnum, Color) + Get + Return New Dictionary(Of ActivityStateEnum, Color)(_colorsActivities) + End Get + End Property + Private ReadOnly Property _colorsActivityReadOnly As New Dictionary(Of ActivityStateEnum, Color) + Public ReadOnly Property ColorsActivitiesReadOnly As Dictionary(Of ActivityStateEnum, Color) + Get + Return New Dictionary(Of ActivityStateEnum, Color)(_colorsActivityReadOnly) + End Get + End Property + Private ReadOnly _colorsUsers As New List(Of Color) + Public ReadOnly Property ColorsUsers As List(Of Color) + Get + Return New List(Of Color)(_colorsUsers) + End Get + End Property +#End Region +#End Region + ''' + ''' Loads in all the general configs. + ''' + ''' + Private Sub LoadGeneralConfigLines(generalConfigLines As IReadOnlyCollection(Of String)) + Try + 'Loop through each line. + For Each line In generalConfigLines + 'Get key and value of a config entry. + Dim identifier = ExtractConfigIdentifier(line) + Dim value = ExtractConfigValue(line) + + If identifier.Equals("RefreshFrequence") Then + _RefreshIntervalSeconds = value + ElseIf identifier.Equals("RefreshTimeStart") Then + _RefreshTimeStart = TimeSpan.FromHours(value) + ElseIf identifier.Equals("RefreshTimeEnd") Then + _RefreshTimeEnd = TimeSpan.FromHours(value) + ElseIf identifier.Equals("CacheWebserviceURL") Then + _CacheWebserviceUrl = New Url(value) + ElseIf identifier.Equals("AgColorBatch") Then + _AgColorBatch = GetColorFromHexStringValue(value) + ElseIf identifier.Equals("AgColorProductGroup") Then + _AgColorProductGroup = GetColorFromHexStringValue(value) + ElseIf identifier.Equals("AgColorTo") Then + _AgColorTo = GetColorFromHexStringValue(value) + ElseIf identifier.Contains("AgColorDueOut") Then + AddColorDueOut(identifier, value) + ElseIf identifier.Contains("AgColorActivityReadOnly") Then + AddColorActivity(identifier, value, True) + ElseIf identifier.Contains("AgColorActivity") Then + AddColorActivity(identifier, value, False) + ElseIf identifier.Contains("ColorUser") Then + _colorsUsers.Add(GetColorFromHexStringValue(value)) + Else + Throw New Exception($"Unknown configuration: '{line}'.") + End If + Next + Catch ex As InvalidCastException + Throw New ConfigurationException($"One of the general config values has an invalid type.{vbNewLine}{ex.Message}") + Catch ex As Exception + Throw New ConfigurationException($"One of the general config values is invalid.{vbNewLine}{ex.Message}") + End Try + End Sub + + ''' + ''' Add a color for a due out state to the dictionary. + ''' + ''' The identifier of the state + ''' The hexadecimal string value of the color + Private Sub AddColorDueOut(identifier As String, value As String) + Try + 'Extract the state name. + 'Invoke the Match method, all text after AgColorDueOut. + Dim m As Match = Regex.Match(identifier, "AgColorDueOut(.*)") + + If Not m.Success Then + 'No results. + Throw New ConfigurationException($"Could not get the state for assigning a color for DueOut. Identifier is '{identifier}'.") + End If + + 'If successful, extract the state name. + dim stateName = m.Groups(1).Value + + 'Convert string value to enum value. + Dim enumValue = DueOutStateEnumMapper.GetEnumValueFromString(stateName) + + 'Add to library, key is the enum value, value is the color. + _colorsDueOut.Add(enumValue, GetColorFromHexStringValue(value)) + Catch ex As Exception + Throw New ConfigurationException($"ColorDueOut with name: '{identifier}' and value '{value}' is invalid.{vbNewLine}{ex.Message}") + End Try + End Sub + + ''' + ''' Add a color for a due out state to the dictionary. + ''' + ''' The identifier of the state + ''' The hexadecimal string value of the color + ''' Whether or not the activity is readonly + Private Sub AddColorActivity(identifier As String, value As String, isReadOnly As Boolean) + Try + 'Extract the state name. + 'Invoke the Match method, all text after AgColorDueOut. + Dim m As Match = Regex.Match(identifier, If(isReadOnly,"AgColorActivityReadOnly(.*)", "AgColorActivity(.*)")) + + If Not m.Success Then + 'No results. + Throw New ConfigurationException($"Could not get the state for assigning a color for DueOut. Identifier is '{identifier}'.") + End If + + 'If successful, extract the state name. + dim stateName = m.Groups(1).Value + + 'Convert string value to enum value. + Dim enumValue = ActivityStateEnumMapper.GetEnumValueFromString(stateName) + + 'Add to library, key is the enum value, value is the color. + If isReadOnly Then + 'It's readonly. + _colorsActivityReadOnly.Add(enumValue, GetColorFromHexStringValue(value)) + Else + 'It's not. + _colorsActivities.Add(enumValue, GetColorFromHexStringValue(value)) + End If + Catch ex As Exception + Throw New ConfigurationException($"Color activity with name: '{identifier}' and value '{value}' is invalid.{vbNewLine}{ex.Message}") + End Try + End Sub + + ''' + ''' Validate that all the required fields are present. + ''' + Private Sub ValidateGeneralConfigs() + 'Refresh interval. + If RefreshIntervalSeconds <= 0 Then + Throw New ConfigurationException("The refresh interval is too low.") + ElseIf RefreshIntervalSeconds > MaxIntervalSeconds Then + Throw New ConfigurationException($"Refresh interval is above the maximum of {MaxIntervalSeconds} seconds.") + End If + + 'Refresh time start. + If RefreshTimeStart = TimeSpan.Zero Then + Throw New ConfigurationException("Refresh time start is not defined.") + End If + + 'Refresh time end. + If RefreshTimeEnd = TimeSpan.Zero Then + Throw New ConfigurationException("Refresh time end is not defined.") + End If + + 'Caché webservice URL. + If CacheWebserviceUrl Is Nothing Then + Throw New ConfigurationException("The Caché webservice URL is not defined.") + End If + + 'Ag color batch. + If AgColorBatch = Color.Empty Then + Throw New ConfigurationException("The Ag color batch is not defined.") + End If + + 'Ag color production group. + If AgColorProductGroup = Color.Empty Then + Throw New ConfigurationException("The Ag color production group is not defined.") + End If + + 'Caché webservice URL. + If AgColorTo = Color.Empty Then + Throw New ConfigurationException("The Ag color to is not defined.") + End If + + 'Colors due out. + If _colorsDueOut.Keys.Count <> [Enum].GetValues(GetType(DueOutStateEnum)).Length Then + 'Amount of enum values and entries in the dictionary differ. + Throw New ConfigurationException($"The amount of colors defined for the different states of DueOut differs from the amount of states. + There are {[Enum].GetValues(GetType(DueOutStateEnum)).Length} total states and {_colorsDueOut.Keys.Count} colors are defined.") + End If + + 'Colors activities. + If _colorsActivities.Keys.Count <> [Enum].GetValues(GetType(ActivityStateEnum)).Length Then + 'Amount of enum values and entries in the dictionary differ. + Throw New ConfigurationException($"The amount of colors defined for the different states of activities differs from the amount of states. + There are {[Enum].GetValues(GetType(ActivityStateEnum)).Length} total states and {_colorsActivities.Keys.Count} colors are defined.") + End If + + 'Colors activities readonly. + If _colorsActivityReadOnly.Keys.Count <> ([Enum].GetValues(GetType(ActivityStateEnum)).Length - 2) Then + 'Amount of enum values and entries in the dictionary differ. ReadOnly doesn't have a color value for the 2 special activities. + Throw New ConfigurationException($"The amount of colors defined for the different states of readonly activities differs from the amount of states. + There are {[Enum].GetValues(GetType(ActivityStateEnum)).Length} total states and {_colorsActivityReadOnly.Keys.Count} colors are defined.") + End If + + 'Colors users. + If _colorsUsers.Count <> MaxNumberOfUsers Then + Throw New ConfigurationException($"The colors for the users are not defined or differ from the required amount of {MaxNumberOfUsers}.") + End If + End Sub + +#End Region End Module End Namespace \ No newline at end of file Index: ActiviteitenOpvolging/ActiviteitenOpvolging/enums/DueOutStateEnum.vb =================================================================== diff -u -r1666 -r1671 --- ActiviteitenOpvolging/ActiviteitenOpvolging/enums/DueOutStateEnum.vb (.../DueOutStateEnum.vb) (revision 1666) +++ ActiviteitenOpvolging/ActiviteitenOpvolging/enums/DueOutStateEnum.vb (.../DueOutStateEnum.vb) (revision 1671) @@ -4,3 +4,26 @@ Almost Start End Enum + +Public Module DueOutStateEnumMapper + ''' + ''' Gets the corresponding enum value from the DueOutStateEnum with a string value. + ''' + ''' The string value + ''' + Public Function GetEnumValueFromString(stateValue As String) As DueOutStateEnum + Select Case stateValue.ToLower() + Case "defaulted" + Return DueOutStateEnum.Defaulted + Case "before" + Return DueOutStateEnum.Before + Case "almost" + Return DueOutStateEnum.Almost + Case "start" + Return DueOutStateEnum.Start + Case Else + Throw New Exception($"The due out state value is unknown for getting a corresponding enum value: '{stateValue}'.") + End Select + End Function + +End Module \ No newline at end of file