module Text.Webrexp.UnionNode( PartialGraph( .. ), UnionNode ( .. ), parseUnion ) where
import Control.Applicative
import Network.HTTP
import System.Directory
import Text.Webrexp.GraphWalker
import Text.Webrexp.IOMock
import Text.Webrexp.Remote.MimeTypes
import Text.Webrexp.ResourcePath
import qualified Text.Webrexp.ProjectByteString as B
class (GraphWalker a rezPath) => PartialGraph a rezPath where
isResourceParseable :: a -> rezPath -> ParseableType -> Bool
parseResource :: (IOMockable m, Monad m)
=> Loggers m -> rezPath -> ParseableType -> B.ByteString
-> m (Maybe a)
data UnionNode a b = UnionLeft a | UnionRight b
deriving Eq
instance ( PartialGraph a rezPath
, PartialGraph b rezPath
, GraphWalker (UnionNode a b) rezPath)
=> PartialGraph (UnionNode a b) rezPath where
isResourceParseable _ datapath parser =
isResourceParseable (undefined :: a) datapath parser ||
isResourceParseable (undefined :: b) datapath parser
parseResource loggers datapath parser binData =
case ( isResourceParseable (undefined :: a) datapath parser
, isResourceParseable (undefined :: b) datapath parser) of
(True, _) -> parseResource loggers datapath parser binData >>= (\a -> return $ UnionLeft <$> a)
(_ , _) -> parseResource loggers datapath parser binData >>= (\a -> return $ UnionRight <$> a)
instance (PartialGraph a ResourcePath, PartialGraph b ResourcePath)
=> GraphWalker (UnionNode a b) ResourcePath where
attribOf att (UnionLeft a) = attribOf att a
attribOf att (UnionRight a) = attribOf att a
nameOf (UnionLeft a) = nameOf a
nameOf (UnionRight a) = nameOf a
rawAccess = accessResourcePath
childrenOf (UnionLeft a) =
childrenOf a >>= \c -> return $ UnionLeft <$> c
childrenOf (UnionRight a) =
childrenOf a >>= \c -> return $ UnionRight <$> c
valueOf (UnionLeft a) = valueOf a
valueOf (UnionRight a) = valueOf a
indirectLinks (UnionLeft a) = indirectLinks a
indirectLinks (UnionRight a) = indirectLinks a
accessGraph = loadData
isHistoryMutable (UnionLeft a) = isHistoryMutable a
isHistoryMutable (UnionRight a) = isHistoryMutable a
deepValueOf (UnionLeft a) = deepValueOf a
deepValueOf (UnionRight a) = deepValueOf a
parseUnion :: forall a b m.
( IOMockable m, Functor m, Monad m
, PartialGraph a ResourcePath
, PartialGraph b ResourcePath )
=> Loggers m -> Maybe ParseableType -> ResourcePath -> B.ByteString
-> m (AccessResult (UnionNode a b) ResourcePath)
parseUnion _ Nothing datapath binaryData =
return $ DataBlob datapath binaryData
parseUnion loggers (Just parser) datapath binaryData =
let binaryContent = DataBlob datapath binaryData
in case ( isResourceParseable (undefined :: a) datapath parser
, isResourceParseable (undefined :: b) datapath parser ) of
(True, _) ->
maybe binaryContent
(Result datapath . UnionLeft) <$> parseResource loggers datapath parser binaryData
( _, True) -> maybe binaryContent
(Result datapath . UnionRight)
<$> parseResource loggers datapath parser binaryData
_ -> return binaryContent
loadData :: ( IOMockable m, Functor m, Monad m
, PartialGraph a ResourcePath
, PartialGraph b ResourcePath )
=> Loggers m -> ResourcePath
-> m (AccessResult (UnionNode a b) ResourcePath)
loadData loggers@(logger, _errLog, verbose) datapath@(Local s) = do
logger $ "Opening file : '" ++ s ++ "'"
realFile <- performIO $ doesFileExist s
case realFile of
Just True -> performIO (B.readFile s) >>=
maybe (return AccessError)
(\file -> do
let kind = getParseKind s
verbose $ "Found kind " ++ show kind ++ " for (" ++ s ++ ")"
parseUnion loggers kind datapath file)
_ -> do
verbose $ "Unable to open file : " ++ s
return AccessError
loadData loggers@(logger, _, verbose) (Remote uri) = do
logger $ "Downloading URL : '" ++ show uri ++ "'"
(u, rsp) <- downloadBinary loggers uri
let contentType = retrieveHeaders HdrContentType rsp
binaryData = rspBody rsp
case contentType of
[] -> return $ DataBlob (Remote u) binaryData
(hdr:_) -> do
verbose $ "Downloaded (" ++ show u ++ ") ["
++ hdrValue hdr ++ "] "
parseUnion loggers
(getParserForMimeType $ hdrValue hdr)
(Remote u) binaryData