    {-# LANGUAGE PatternGuards     #-}
    {-# LANGUAGE OverloadedStrings #-}
    {- |
       Module      : Text.Pandoc.Reader.Odt
       Copyright   : Copyright (C) 2015 Martin Linnemann
       License     : GNU GPL, version 2 or above

       Maintainer  : Martin Linnemann <theCodingMarlin@googlemail.com>
       Stability   : alpha
       Portability : portable

    Entry point to the odt reader.
    -}

    module Text.Pandoc.Readers.Odt ( readOdt ) where

    import Codec.Archive.Zip
    import qualified Text.XML.Light as XML

    import qualified Data.ByteString.Lazy as B

    import System.FilePath

    import Control.Monad.Except (throwError)

    import Text.Pandoc.Class.PandocMonad (PandocMonad)
    import qualified Text.Pandoc.Class.PandocMonad as P
    import Text.Pandoc.Definition
    import Text.Pandoc.Error
    import Text.Pandoc.MediaBag
    import Text.Pandoc.Options
    import qualified Text.Pandoc.UTF8 as UTF8

    import Text.Pandoc.Readers.Odt.ContentReader
    import Text.Pandoc.Readers.Odt.StyleReader

    import Text.Pandoc.Readers.Odt.Generic.Fallible
    import Text.Pandoc.Readers.Odt.Generic.XMLConverter
    import Text.Pandoc.Shared (filteredFilesFromArchive)

    readOdt :: PandocMonad m
            => ReaderOptions
            -> B.ByteString
            -> m Pandoc
    readOdt :: ReaderOptions -> ByteString -> m Pandoc
    readOdt opts :: ReaderOptions
    opts bytes :: ByteString
    bytes = case ReaderOptions
    -> ByteString -> Either PandocError (Pandoc, MediaBag)
    readOdt' ReaderOptions
    opts ByteString
    bytes of
      Right (doc :: Pandoc
    doc, mb :: MediaBag
    mb) -> do
        MediaBag -> m ()
    forall (m :: * -> *). PandocMonad m => MediaBag -> m ()
    P.setMediaBag MediaBag
    mb
        Pandoc -> m Pandoc
    forall (m :: * -> *) a. Monad m => a -> m a
    return Pandoc
    doc
      Left e :: PandocError
    e -> PandocError -> m Pandoc
    forall e (m :: * -> *) a. MonadError e m => e -> m a
    throwError PandocError
    e

    --
    readOdt' :: ReaderOptions
             -> B.ByteString
             -> Either PandocError (Pandoc, MediaBag)
    readOdt' :: ReaderOptions
    -> ByteString -> Either PandocError (Pandoc, MediaBag)
    readOdt' _ bytes :: ByteString
    bytes = ByteString -> Either PandocError (Pandoc, MediaBag)
    bytesToOdt ByteString
    bytes-- of
    --                    Right (pandoc, mediaBag) -> Right (pandoc , mediaBag)
    --                    Left  err                -> Left err

    --
    bytesToOdt :: B.ByteString -> Either PandocError (Pandoc, MediaBag)
    bytesToOdt :: ByteString -> Either PandocError (Pandoc, MediaBag)
    bytesToOdt bytes :: ByteString
    bytes = case ByteString -> Either String Archive
    toArchiveOrFail ByteString
    bytes of
      Right archive :: Archive
    archive -> Archive -> Either PandocError (Pandoc, MediaBag)
    archiveToOdt Archive
    archive
      Left _        -> PandocError -> Either PandocError (Pandoc, MediaBag)
    forall a b. a -> Either a b
    Left (PandocError -> Either PandocError (Pandoc, MediaBag))
    -> PandocError -> Either PandocError (Pandoc, MediaBag)
    forall a b. (a -> b) -> a -> b
    $ Text -> PandocError
    PandocParseError "Couldn't parse odt file."

    --
    archiveToOdt :: Archive -> Either PandocError (Pandoc, MediaBag)
    archiveToOdt :: Archive -> Either PandocError (Pandoc, MediaBag)
    archiveToOdt archive :: Archive
    archive
      | Just contentEntry :: Entry
    contentEntry      <- String -> Archive -> Maybe Entry
    findEntryByPath "content.xml" Archive
    archive
      , Just stylesEntry :: Entry
    stylesEntry       <- String -> Archive -> Maybe Entry
    findEntryByPath "styles.xml"  Archive
    archive
      , Just contentElem :: Element
    contentElem       <- Entry -> Maybe Element
    entryToXmlElem Entry
    contentEntry
      , Just stylesElem :: Element
    stylesElem        <- Entry -> Maybe Element
    entryToXmlElem Entry
    stylesEntry
      , Right styles :: Styles
    styles           <- Either () Styles -> Either () Styles -> Either () Styles
    forall a b.
    (Monoid a, Monoid b) =>
    Either a b -> Either a b -> Either a b
    chooseMax (Element -> Either () Styles
    readStylesAt Element
    stylesElem )
                                            (Element -> Either () Styles
    readStylesAt Element
    contentElem)
      , [(String, ByteString)]
    media                  <- Archive -> (String -> Bool) -> [(String, ByteString)]
    filteredFilesFromArchive Archive
    archive String -> Bool
    filePathIsOdtMedia
      , ReaderState
    startState             <- Styles -> [(String, ByteString)] -> ReaderState
    readerState Styles
    styles [(String, ByteString)]
    media
      , Right pandocWithMedia :: (Pandoc, MediaBag)
    pandocWithMedia  <- FallibleXMLConverter Namespace ReaderState () (Pandoc, MediaBag)
    -> ReaderState -> Element -> Either () (Pandoc, MediaBag)
    forall nsID extraState success.
    NameSpaceID nsID =>
    FallibleXMLConverter nsID extraState () success
    -> extraState -> Element -> Fallible success
    runConverter' FallibleXMLConverter Namespace ReaderState () (Pandoc, MediaBag)
    forall _x. OdtReader _x (Pandoc, MediaBag)
    read_body
                                                ReaderState
    startState
                                                Element
    contentElem

      = (Pandoc, MediaBag) -> Either PandocError (Pandoc, MediaBag)
    forall a b. b -> Either a b
    Right (Pandoc, MediaBag)
    pandocWithMedia

      | Bool
    otherwise
        -- Not very detailed, but I don't think more information would be helpful
      = PandocError -> Either PandocError (Pandoc, MediaBag)
    forall a b. a -> Either a b
    Left (PandocError -> Either PandocError (Pandoc, MediaBag))
    -> PandocError -> Either PandocError (Pandoc, MediaBag)
    forall a b. (a -> b) -> a -> b
    $ Text -> PandocError
    PandocParseError "Couldn't parse odt file."
        where
          filePathIsOdtMedia :: FilePath -> Bool
          filePathIsOdtMedia :: String -> Bool
    filePathIsOdtMedia fp :: String
    fp =
            let (dir :: String
    dir, name :: String
    name) = String -> (String, String)
    splitFileName String
    fp
            in  (String
    dir String -> String -> Bool
    forall a. Eq a => a -> a -> Bool
    == "Pictures/") Bool -> Bool -> Bool
    || (String
    dir String -> String -> Bool
    forall a. Eq a => a -> a -> Bool
    /= "./" Bool -> Bool -> Bool
    && String
    name String -> String -> Bool
    forall a. Eq a => a -> a -> Bool
    == "content.xml")

    --
    entryToXmlElem :: Entry -> Maybe XML.Element
    entryToXmlElem :: Entry -> Maybe Element
    entryToXmlElem = String -> Maybe Element
    forall s. XmlSource s => s -> Maybe Element
    XML.parseXMLDoc (String -> Maybe Element)
    -> (Entry -> String) -> Entry -> Maybe Element
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ByteString -> String
    UTF8.toStringLazy (ByteString -> String) -> (Entry -> ByteString) -> Entry -> String
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Entry -> ByteString
    fromEntry