module Components.ObjectHandlers.ObjectsHandler where

import Data.Maybe
import qualified Control.Exception as E
import Model.ServerExceptions
import Model.ServerObjectTypes


{-
parsing frontend query to server query
- A valid argument is any string that is provided to reference database objects
-}
readServerObject :: String -> [(String,[String])] -> ServerObject
readServerObject str [] = E.throw InvalidObjectException
readServerObject str ((a,b):t) = if (elem str b)==True then (a :: ServerObject) else readServerObject str t
{-
checking server type attributes
-}
-- EFFECT: returns exclusive list of valid fields that are found in the database table for each Server object 
-- this is used to check queries against valid subfields
isValidServerObjectScalarField :: ServerObject -> String -> [(String,[(String,String)])] -> Bool
isValidServerObjectScalarField _ _ [] = E.throw InvalidObjectException
isValidServerObjectScalarField sobj name ((a,b):t)
    | sobj==a&&(elem name $ getScalarNames b)==True = True
    | sobj==a = False
    | otherwise = isValidServerObjectScalarField sobj name t
getScalarNames :: [(String,String)] -> [String]
getScalarNames lst = [a | (a,b) <- lst]
-- you can create as many relationships as you want with your server...
isValidServerObjectNestedObjectField :: ServerObject -> String -> [(String,[String])] -> Bool
isValidServerObjectNestedObjectField _ _ [] = E.throw InvalidObjectException
isValidServerObjectNestedObjectField sobj name ((a,b):t)
    | sobj==a&&(elem name b)==True = True
    | sobj==a = False
    | otherwise = isValidServerObjectNestedObjectField sobj name t
-- split server object to sql query
-- EFFECTS: returns the database table references for the server object.
translateServerObjectToDBName :: ServerObject -> [(String,[String])] -> [String]
translateServerObjectToDBName _ [] = E.throw InvalidObjectException
translateServerObjectToDBName sobj ((a,b):t)
    | sobj==a = b
    | otherwise = translateServerObjectToDBName sobj t
-- TODO: list all server objects and their associated entities
-- EFFECT: with serverobject and serverobject attribute, we want the identity table, identity field, reference table, reference field, and triple elements if present of identity-to-reference-tables-order intermediate table, to-intermediate field, and from-itermediate field
-- You can define direct relationships (around only one link) or indirect (but you'll code the database query by yourself...)
getDBObjectRelationships :: String -> String -> [(String,String,[String])] -> [String]
getDBObjectRelationships _ _ [] = E.throw RelationshipConfigurationException
getDBObjectRelationships from to ((a,b,c):t)
    | from==a&&to==b = c
    | otherwise = getDBObjectRelationships from to t


getScalarName :: ScalarType -> String
getScalarName (ScalarType alias name trans arg) = name
getScalarArgument :: ScalarType -> String
getScalarArgument (ScalarType alias name trans arg) = if arg==Nothing then (E.throw NullArgumentException) else (fromJust arg)
getTransformation :: ScalarType -> (Transformation,Argument)
getTransformation (ScalarType alias name trans arg) = (trans,arg)
getObjectName :: NestedObject -> String
getObjectName (NestedObject alias name sobj ss sf) = name
getObjectAlias :: NestedObject -> Alias
getObjectAlias (NestedObject alias name sobj ss sf) = alias
getServerObject :: NestedObject -> ServerObject
getServerObject (NestedObject alias name sobj ss sf) = sobj
getObjectSubSelection :: NestedObject -> SubSelection
getObjectSubSelection (NestedObject alias name sobj ss sf) = ss
withSubSelection :: NestedObject -> Bool
withSubSelection (NestedObject alias name sobj ss sf) = (ss/=Nothing)
getSubSelectionField :: NestedObject -> String
getSubSelectionField (NestedObject alias name sobj ss sf) = getScalarName $ fromJust ss
getSubSelectionArgument :: NestedObject -> String
getSubSelectionArgument (NestedObject alias name sobj ss sf) = getScalarArgument $ fromJust ss
getSubFields :: NestedObject -> SubFields
getSubFields (NestedObject alias name sobj ss sf) = sf
isSameObjectReference :: NestedObject -> NestedObject -> Bool
isSameObjectReference (NestedObject alias1 name1 sobj1 ss1 sfs1) (NestedObject alias2 name2 sobj2 ss2 sfs2) = alias1==alias2&&name1==name2&&sobj1==sobj2
isSameObjectSubSelection :: NestedObject -> NestedObject -> Bool
isSameObjectSubSelection (NestedObject alias1 name1 sobj1 ss1 sfs1) (NestedObject alias2 name2 sobj2 ss2 sfs2) = ss1==ss2