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

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

    General utility functions for the odt reader.
    -}

    module Text.Pandoc.Readers.Odt.Generic.Utils
    ( uncurry3
    , uncurry4
    , uncurry5
    , uncurry6
    , swap
    , reverseComposition
    , tryToRead
    , Lookupable(..)
    , readLookupables
    , readLookupable
    , readPercent
    , findBy
    , swing
    , composition
    ) where

    import Control.Category (Category, (<<<), (>>>))
    import qualified Control.Category as Cat (id)
    import Control.Monad (msum)

    import qualified Data.Foldable as F (Foldable, foldr)
    import Data.Maybe

    -- | Equivalent to
    -- > foldr (.) id
    -- where '(.)' are 'id' are the ones from "Control.Category"
    -- and 'foldr' is the one from "Data.Foldable".
    -- The noun-form was chosen to be consistend with 'sum', 'product' etc
    -- based on the discussion at
    -- <https://groups.google.com/forum/#!topic/haskell-cafe/VkOZM1zaHOI>
    -- (that I was not part of)
    composition        :: (Category cat, F.Foldable f) => f (cat a a) -> cat a a
    composition :: f (cat a a) -> cat a a
    composition        = (cat a a -> cat a a -> cat a a)
    -> cat a a -> f (cat a a) -> cat a a
    forall (t :: * -> *) a b.
    Foldable t =>
    (a -> b -> b) -> b -> t a -> b
    F.foldr cat a a -> cat a a -> cat a a
    forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
    Category cat =>
    cat b c -> cat a b -> cat a c
    (<<<) cat a a
    forall k (cat :: k -> k -> *) (a :: k). Category cat => cat a a
    Cat.id

    -- | Equivalent to
    -- > foldr (flip (.)) id
    -- where '(.)' are 'id' are the ones from "Control.Category"
    -- and 'foldr' is the one from "Data.Foldable".
    -- A reversed version of 'composition'.
    reverseComposition :: (Category cat, F.Foldable f) => f (cat a a) -> cat a a
    reverseComposition :: f (cat a a) -> cat a a
    reverseComposition = (cat a a -> cat a a -> cat a a)
    -> cat a a -> f (cat a a) -> cat a a
    forall (t :: * -> *) a b.
    Foldable t =>
    (a -> b -> b) -> b -> t a -> b
    F.foldr cat a a -> cat a a -> cat a a
    forall k (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
    Category cat =>
    cat a b -> cat b c -> cat a c
    (>>>) cat a a
    forall k (cat :: k -> k -> *) (a :: k). Category cat => cat a a
    Cat.id

    -- | This function often makes it possible to switch values with the functions
    -- that are applied to them.
    --
    -- Examples:
    -- > swing map :: [a -> b] -> a -> [b]
    -- > swing any :: [a -> Bool] -> a -> Bool
    -- > swing foldr :: b -> a -> [a -> b -> b] -> b
    -- > swing scanr :: c -> a -> [a -> c -> c] -> c
    -- > swing zipWith :: [a -> b -> c] -> a -> [b] -> [c]
    -- > swing find :: [a -> Bool] -> a -> Maybe (a -> Bool)
    --
    -- Stolen from <https://wiki.haskell.org/Pointfree>
    swing :: (((a -> b) -> b) -> c -> d) -> c -> a -> d
    swing :: (((a -> b) -> b) -> c -> d) -> c -> a -> d
    swing = (a -> c -> d) -> c -> a -> d
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip((a -> c -> d) -> c -> a -> d)
    -> ((((a -> b) -> b) -> c -> d) -> a -> c -> d)
    -> (((a -> b) -> b) -> c -> d)
    -> c
    -> a
    -> d
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .((((a -> b) -> b) -> c -> d) -> (a -> (a -> b) -> b) -> a -> c -> d
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .((a -> b) -> a -> b) -> a -> (a -> b) -> b
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip (a -> b) -> a -> b
    forall a. a -> a
    id)
    -- swing f c a = f ($ a) c

    -- | Alternative to 'read'/'reads'. The former of these throws errors
    -- (nobody wants that) while the latter returns "to much" for simple purposes.
    -- This function instead applies 'reads' and returns the first match (if any)
    -- in a 'Maybe'.
    tryToRead :: (Read r) => String -> Maybe r
    tryToRead :: String -> Maybe r
    tryToRead = ReadS r
    forall a. Read a => ReadS a
    reads ReadS r -> ([(r, String)] -> Maybe r) -> String -> Maybe r
    forall k (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
    Category cat =>
    cat a b -> cat b c -> cat a c
    >>> [(r, String)] -> Maybe (r, String)
    forall a. [a] -> Maybe a
    listToMaybe ([(r, String)] -> Maybe (r, String))
    -> (Maybe (r, String) -> Maybe r) -> [(r, String)] -> Maybe r
    forall k (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
    Category cat =>
    cat a b -> cat b c -> cat a c
    >>> ((r, String) -> r) -> Maybe (r, String) -> Maybe r
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (r, String) -> r
    forall a b. (a, b) -> a
    fst

    -- | A version of 'reads' that requires a '%' sign after the number
    readPercent :: ReadS Int
    readPercent :: ReadS Int
    readPercent s :: String
    s = [ (Int
    i,String
    s') | (i :: Int
    i   , r :: String
    r ) <- ReadS Int
    forall a. Read a => ReadS a
    reads String
    s
                             , ("%" , s' :: String
    s') <- ReadS String
    lex   String
    r
                  ]

    -- | Data that can be looked up.
    -- This is mostly a utility to read data with kind *.
    class Lookupable a where
      lookupTable :: [(String, a)]

    -- | The idea is to use this function as if there was a declaration like
    --
    -- > instance (Lookupable a) => (Read a) where
    -- >   readsPrec _ = readLookupables
    -- .
    -- But including this code in this form would need UndecideableInstances.
    -- That is a bad idea. Luckily 'readLookupable' (without the s at the end)
    -- can be used directly in almost any case.
    readLookupables :: (Lookupable a) => String -> [(a,String)]
    readLookupables :: String -> [(a, String)]
    readLookupables s :: String
    s = [ (a
    a,String
    rest) | (word :: String
    word,rest :: String
    rest) <- ReadS String
    lex String
    s,
                                     a
    a <- Maybe a -> [a]
    forall a. Maybe a -> [a]
    maybeToList (String -> [(String, a)] -> Maybe a
    forall a b. Eq a => a -> [(a, b)] -> Maybe b
    lookup String
    word [(String, a)]
    forall a. Lookupable a => [(String, a)]
    lookupTable)
                        ]

    -- | Very similar to a simple 'lookup' in the 'lookupTable', but with a lexer.
    readLookupable :: (Lookupable a) => String -> Maybe a
    readLookupable :: String -> Maybe a
    readLookupable s :: String
    s = [Maybe a] -> Maybe a
    forall (t :: * -> *) (m :: * -> *) a.
    (Foldable t, MonadPlus m) =>
    t (m a) -> m a
    msum
                     ([Maybe a] -> Maybe a) -> [Maybe a] -> Maybe a
    forall a b. (a -> b) -> a -> b
    $ ((String, String) -> Maybe a) -> [(String, String)] -> [Maybe a]
    forall a b. (a -> b) -> [a] -> [b]
    map ((String -> [(String, a)] -> Maybe a
    forall a b. Eq a => a -> [(a, b)] -> Maybe b
    `lookup` [(String, a)]
    forall a. Lookupable a => [(String, a)]
    lookupTable)(String -> Maybe a)
    -> ((String, String) -> String) -> (String, String) -> Maybe a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .(String, String) -> String
    forall a b. (a, b) -> a
    fst)
                     ([(String, String)] -> [Maybe a])
    -> [(String, String)] -> [Maybe a]
    forall a b. (a -> b) -> a -> b
    $ ReadS String
    lex String
    s

    uncurry3 :: (a->b->c                -> z) -> (a,b,c          ) -> z
    uncurry4 :: (a->b->c->d             -> z) -> (a,b,c,d        ) -> z
    uncurry5 :: (a->b->c->d->e          -> z) -> (a,b,c,d,e      ) -> z
    uncurry6 :: (a->b->c->d->e->f       -> z) -> (a,b,c,d,e,f    ) -> z

    uncurry3 :: (a -> b -> c -> z) -> (a, b, c) -> z
    uncurry3 fun :: a -> b -> c -> z
    fun (a :: a
    a,b :: b
    b,c :: c
    c          ) = a -> b -> c -> z
    fun a
    a b
    b c
    c
    uncurry4 :: (a -> b -> c -> d -> z) -> (a, b, c, d) -> z
    uncurry4 fun :: a -> b -> c -> d -> z
    fun (a :: a
    a,b :: b
    b,c :: c
    c,d :: d
    d        ) = a -> b -> c -> d -> z
    fun a
    a b
    b c
    c d
    d
    uncurry5 :: (a -> b -> c -> d -> e -> z) -> (a, b, c, d, e) -> z
    uncurry5 fun :: a -> b -> c -> d -> e -> z
    fun (a :: a
    a,b :: b
    b,c :: c
    c,d :: d
    d,e :: e
    e      ) = a -> b -> c -> d -> e -> z
    fun a
    a b
    b c
    c d
    d e
    e
    uncurry6 :: (a -> b -> c -> d -> e -> f -> z) -> (a, b, c, d, e, f) -> z
    uncurry6 fun :: a -> b -> c -> d -> e -> f -> z
    fun (a :: a
    a,b :: b
    b,c :: c
    c,d :: d
    d,e :: e
    e,f :: f
    f    ) = a -> b -> c -> d -> e -> f -> z
    fun a
    a b
    b c
    c d
    d e
    e f
    f

    swap :: (a,b) -> (b,a)
    swap :: (a, b) -> (b, a)
    swap (a :: a
    a,b :: b
    b) = (b
    b,a
    a)

    -- | A version of "Data.List.find" that uses a converter to a Maybe instance.
    -- The returned value is the first which the converter returns in a 'Just'
    -- wrapper.
    findBy :: (a -> Maybe b) -> [a] -> Maybe b
    findBy :: (a -> Maybe b) -> [a] -> Maybe b
    findBy _               []   = Maybe b
    forall a. Maybe a
    Nothing
    findBy f :: a -> Maybe b
    f ((a -> Maybe b
    f -> Just x :: b
    x):_ ) = b -> Maybe b
    forall a. a -> Maybe a
    Just b
    x
    findBy f :: a -> Maybe b
    f (            _:xs :: [a]
    xs) = (a -> Maybe b) -> [a] -> Maybe b
    forall a b. (a -> Maybe b) -> [a] -> Maybe b
    findBy a -> Maybe b
    f [a]
    xs