Imports System.Security.Principal
Imports C1.Web.Api.DataEngine.Models

Public Class ViewPermission
    Private Shared ReadOnly _all As New Lazy(Of IDictionary(Of String, ViewPermission))(AddressOf InitAll)

    Public Sub New(viewName__1 As String)
        ViewName = viewName__1
        Roles = New HashSet(Of String)(StringComparer.OrdinalIgnoreCase)
        FieldPermissions = New Dictionary(Of String, HashSet(Of String))(StringComparer.OrdinalIgnoreCase)
    End Sub

    Public Property ViewName() As String

    Public Property FieldPermissions() As IDictionary(Of String, HashSet(Of String))

    Public Property Roles() As HashSet(Of String)

    Public Shared ReadOnly Property All() As IDictionary(Of String, ViewPermission)
        Get
            Return _all.Value
        End Get
    End Property

    Friend Shared Function VerifyFields(viewName As String, raw As IEnumerable(Of Field), principal As IPrincipal) As IEnumerable(Of Field)
        If principal Is Nothing OrElse raw Is Nothing Then
            Return Nothing
        End If

        Dim permission As ViewPermission
        If Not All.TryGetValue(viewName, permission) Then
            Return Nothing
        End If

        Dim resultFields = New List(Of Field)()
        For Each field As Field In raw
            Dim roles As HashSet(Of String)
            If Not permission.FieldPermissions.TryGetValue(field.Header, roles) Then
                roles = permission.Roles
            End If

            If roles.Any(Function(r) principal.IsInRole(r)) Then
                resultFields.Add(field)
            End If
        Next

        Return resultFields.AsReadOnly()
    End Function

    Private Shared Function InitAll() As IDictionary(Of String, ViewPermission)
        Dim all = New Dictionary(Of String, ViewPermission)(StringComparer.OrdinalIgnoreCase)
        Dim db = New SalesEntities()
        Dim aspNetRoles = New Dictionary(Of String, String)()
        For Each role As AspNetRole In db.AspNetRoles
            aspNetRoles.Add(role.Id, role.Name)
        Next

        For Each permission As RolePermission In db.RolePermissions
            Dim names = permission.ViewFieldName.Split("."c)
            Dim viewName = names(0)
            Dim viewPermission As ViewPermission
            If Not all.TryGetValue(viewName, viewPermission) Then
                viewPermission = New ViewPermission(viewName)
                all(viewName) = viewPermission
            End If

            Dim roles As HashSet(Of String)
            If names.Length > 1 Then
                roles = New HashSet(Of String)(StringComparer.OrdinalIgnoreCase)
                viewPermission.FieldPermissions(names(1)) = roles
            Else
                roles = viewPermission.Roles
                roles.Clear()
            End If

            Dim pRoles = permission.Roles.Split(","c).[Select](Function(p) aspNetRoles(p))
            For Each r As String In pRoles
                roles.Add(r)
            Next
        Next

        Return all
    End Function
End Class