{-# 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(..)
, readLookupable
, readPercent
, findBy
, swing
, composition
) where

import Control.Category (Category, (<<<), (>>>))
import qualified Control.Category as Cat (id)
import Data.Char (isSpace)
import qualified Data.Foldable as F (Foldable, foldr)
import Data.Maybe
import Data.Text (Text)
import qualified Data.Text as T

-- | 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 consistent 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 :: forall (cat :: * -> * -> *) (f :: * -> *) a.
(Category cat, Foldable f) =>
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 a b. (a -> b -> b) -> b -> f a -> b
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 a. 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 :: forall (cat :: * -> * -> *) (f :: * -> *) a.
(Category cat, Foldable f) =>
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 a b. (a -> b -> b) -> b -> f a -> b
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 a. 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 :: forall a b c d. (((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) => Text -> Maybe r
tryToRead :: forall r. Read r => Text -> Maybe r
tryToRead = (ReadS r
forall a. Read a => ReadS a
reads ReadS r -> (Text -> String) -> Text -> [(r, String)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
T.unpack) (Text -> [(r, String)])
-> ([(r, String)] -> Maybe r) -> Text -> 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 a b. (a -> b) -> Maybe a -> Maybe b
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 String
s = [ (Int
i,String
s') | (Int
i   , String
r ) <- ReadS Int
forall a. Read a => ReadS a
reads String
s
                         , (String
"%" , 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 :: [(Text, a)]

-- | Very similar to a simple 'lookup' in the 'lookupTable', but with a lexer.
readLookupable :: (Lookupable a) => Text -> Maybe a
readLookupable :: forall a. Lookupable a => Text -> Maybe a
readLookupable Text
s =
  Text -> [(Text, a)] -> Maybe a
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup ((Char -> Bool) -> Text -> Text
T.takeWhile (Bool -> Bool
not (Bool -> Bool) -> (Char -> Bool) -> Char -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Bool
isSpace) (Text -> Text) -> Text -> Text
forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> Text -> Text
T.dropWhile Char -> Bool
isSpace Text
s) [(Text, a)]
forall a. Lookupable a => [(Text, a)]
lookupTable

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 :: forall a b c z. (a -> b -> c -> z) -> (a, b, c) -> z
uncurry3 a -> b -> c -> z
fun (a
a,b
b,c
c          ) = a -> b -> c -> z
fun a
a b
b c
c
uncurry4 :: forall a b c d z. (a -> b -> c -> d -> z) -> (a, b, c, d) -> z
uncurry4 a -> b -> c -> d -> z
fun (a
a,b
b,c
c,d
d        ) = a -> b -> c -> d -> z
fun a
a b
b c
c d
d
uncurry5 :: forall a b c d e z.
(a -> b -> c -> d -> e -> z) -> (a, b, c, d, e) -> z
uncurry5 a -> b -> c -> d -> e -> z
fun (a
a,b
b,c
c,d
d,e
e      ) = a -> b -> c -> d -> e -> z
fun a
a b
b c
c d
d e
e
uncurry6 :: forall a b c d e f z.
(a -> b -> c -> d -> e -> f -> z) -> (a, b, c, d, e, f) -> z
uncurry6 a -> b -> c -> d -> e -> f -> z
fun (a
a,b
b,c
c,d
d,e
e,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 :: forall a b. (a, b) -> (b, a)
swap (a
a,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 :: forall a b. (a -> Maybe b) -> [a] -> Maybe b
findBy a -> Maybe b
_               []   = Maybe b
forall a. Maybe a
Nothing
findBy a -> Maybe b
f ((a -> Maybe b
f -> Just b
x):[a]
_ ) = b -> Maybe b
forall a. a -> Maybe a
Just b
x
findBy a -> Maybe b
f (            a
_:[a]
xs) = (a -> Maybe b) -> [a] -> Maybe b
forall a b. (a -> Maybe b) -> [a] -> Maybe b
findBy a -> Maybe b
f [a]
xs