module Control.Access.RoleBased.Internal.Role where

------------------------------------------------------------------------------
import           Control.Monad.ST
import           Data.Hashable
import           Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as M
import           Data.String
import           Data.Text (Text)
import qualified Data.Vector as V
import qualified Data.Vector.Algorithms.Merge as VA


------------------------------------------------------------------------------
data RoleValue = RoleBool Bool
               | RoleText Text
               | RoleInt Int
               | RoleDouble Double
  deriving (Ord, Eq, Show)


------------------------------------------------------------------------------
instance IsString RoleValue where
    fromString = RoleText . fromString


------------------------------------------------------------------------------
instance Hashable RoleValue where
    hashWithSalt salt (RoleBool e)   = hashWithSalt salt e `hashWithSalt` (7 :: Int)
    hashWithSalt salt (RoleText t)   = hashWithSalt salt t `hashWithSalt` (196613 :: Int)
    hashWithSalt salt (RoleInt i)    = hashWithSalt salt i `hashWithSalt` (12582917 :: Int)
    hashWithSalt salt (RoleDouble d) =
        hashWithSalt salt d `hashWithSalt` (1610612741 :: Int)


------------------------------------------------------------------------------
data Role = Role {
      _roleName :: Text
    , _roleData :: HashMap Text RoleValue
    }
  deriving (Eq, Show)


------------------------------------------------------------------------------
instance IsString Role where
    fromString s = Role (fromString s) M.empty


------------------------------------------------------------------------------
toSortedList :: (Ord k, Ord v) => HashMap k v -> [(k,v)]
toSortedList m = runST $ do
    v <- V.unsafeThaw $ V.fromList $ M.toList m
    VA.sort v
    v' <- V.unsafeFreeze v
    return $ V.toList v'


------------------------------------------------------------------------------
instance Hashable Role where
    hashWithSalt salt (Role nm dat) =
        h $ hashWithSalt salt nm
      where
        h s = hashWithSalt s $ toSortedList dat


------------------------------------------------------------------------------
data RoleValueMeta = RoleBoolMeta
                   | RoleTextMeta
                   | RoleEnumMeta [Text]
                   | RoleIntMeta
                   | RoleDoubleMeta


------------------------------------------------------------------------------
data RoleDataDefinition = RoleDataDefinition {
      _roleDataName        :: Text
    , _roleValueMeta       :: RoleValueMeta
    , _roleDataDescription :: Text
    }


------------------------------------------------------------------------------
data RoleMetadata = RoleMetadata {
      _roleMetadataName :: Text
    , _roleDescription  :: Text
    , _roleDataDefs     :: [RoleDataDefinition]
    }