module Bookhound.Format.Operations.Finder (Finder(..)) where


import Bookhound.Parser            (runParser)
import Bookhound.ParserCombinators (IsMatch (..), (<|>), (|*))
import Bookhound.Parsers.Char      (dot)
import Bookhound.Parsers.Number    (unsignedInt)
import Bookhound.Parsers.String    (withinSquareBrackets)

import Bookhound.Format.SyntaxTrees.Json  (JsonExpression (..))
import Bookhound.Format.SyntaxTrees.Toml  (TomlExpression (..))
import Bookhound.Format.SyntaxTrees.Yaml  (YamlExpression (..))


import Data.Either (fromRight)
import Data.Maybe  (listToMaybe)

import qualified Data.Map  as Map
import           Data.Text (pack)



class Finder a where

  toList :: a -> [(String, a)]
  findAll :: ((String, a) -> Bool) -> a -> [a]
  find :: ((String, a) -> Bool) -> a -> Maybe a
  findByKeys :: [String] -> a -> Maybe a
  findByPath :: String -> a -> Maybe a


  findAll (String, a) -> Bool
f = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. (a, b) -> b
snd forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (a -> Bool) -> [a] -> [a]
filter (String, a) -> Bool
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Finder a => a -> [(String, a)]
toList
  find (String, a) -> Bool
f = forall a. [a] -> Maybe a
listToMaybe forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Finder a => ((String, a) -> Bool) -> a -> [a]
findAll (String, a) -> Bool
f

  findByKeys []       a
expr = forall a. a -> Maybe a
Just a
expr
  findByKeys (String
x : [String]
xs) a
expr = forall {a}. Finder a => String -> a -> Maybe a
findByKey String
x a
expr forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall a. Finder a => [String] -> a -> Maybe a
findByKeys [String]
xs  where

    findByKey :: String -> a -> Maybe a
findByKey String
key = forall a. Finder a => ((String, a) -> Bool) -> a -> Maybe a
find (\(String
str, a
_) -> String
str forall a. Eq a => a -> a -> Bool
== String
key)

  findByPath String
path = forall a. Finder a => [String] -> a -> Maybe a
findByKeys [String]
pathSeq where

    pathSeq :: [String]
pathSeq = forall b a. b -> Either a b -> b
fromRight [] forall a b. (a -> b) -> a -> b
$ forall a. Parser a -> Input -> Either ParseError a
runParser Parser [String]
parsePath forall a b. (a -> b) -> a -> b
$ String -> Input
pack String
path
    parsePath :: Parser [String]
parsePath = forall a. IsMatch a => a -> Parser a
is Char
'$' forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> ((Parser String
index forall a. Parser a -> Parser a -> Parser a
<|> Parser String
key) |*)

    index :: Parser String
index = forall a. Show a => a -> String
show forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall b. Parser b -> Parser b
withinSquareBrackets Parser Integer
unsignedInt
    key :: Parser String
key   = Parser Char
dot forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Parser String
word
    word :: Parser String
word  = (forall a. IsMatch a => [a] -> Parser a
noneOf [Char
'.', Char
'['] |*)



instance Finder JsonExpression where
  toList :: JsonExpression -> [(String, JsonExpression)]
toList = \case
    nil :: JsonExpression
nil@JsonExpression
JsNull       -> [(String
"", JsonExpression
nil)]
    n :: JsonExpression
n@(JsNumber Double
_)   -> [(String
"", JsonExpression
n)]
    bool :: JsonExpression
bool@(JsBool Bool
_)  -> [(String
"", JsonExpression
bool)]
    str :: JsonExpression
str@(JsString String
_) -> [(String
"", JsonExpression
str)]
    JsArray [JsonExpression]
arr      -> forall a b. [a] -> [b] -> [(a, b)]
zip (forall a. Show a => a -> String
show forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Int
0 .. forall (t :: * -> *) a. Foldable t => t a -> Int
length [JsonExpression]
arr forall a. Num a => a -> a -> a
- Int
1]) [JsonExpression]
arr
    JsObject Map String JsonExpression
obj     -> forall k a. Map k a -> [(k, a)]
Map.toList Map String JsonExpression
obj


instance Finder YamlExpression where
  toList :: YamlExpression -> [(String, YamlExpression)]
toList = \case
    nil :: YamlExpression
nil@YamlExpression
YamlNull              -> [(String
"", YamlExpression
nil)]
    n :: YamlExpression
n@(YamlInteger Integer
_)         -> [(String
"", YamlExpression
n)]
    n :: YamlExpression
n@(YamlFloat Double
_)           -> [(String
"", YamlExpression
n)]
    bool :: YamlExpression
bool@(YamlBool Bool
_)         -> [(String
"", YamlExpression
bool)]
    str :: YamlExpression
str@(YamlString String
_)        -> [(String
"", YamlExpression
str)]
    date :: YamlExpression
date@(YamlDate Day
_)         -> [(String
"", YamlExpression
date)]
    time :: YamlExpression
time@(YamlTime TimeOfDay
_)         -> [(String
"", YamlExpression
time)]
    dateTime :: YamlExpression
dateTime@(YamlDateTime ZonedTime
_) -> [(String
"", YamlExpression
dateTime)]
    YamlList CollectionType
_ [YamlExpression]
arr            -> forall a b. [a] -> [b] -> [(a, b)]
zip (forall a. Show a => a -> String
show forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Int
0 .. forall (t :: * -> *) a. Foldable t => t a -> Int
length [YamlExpression]
arr forall a. Num a => a -> a -> a
- Int
1]) [YamlExpression]
arr
    YamlMap CollectionType
_ Map String YamlExpression
obj             -> forall k a. Map k a -> [(k, a)]
Map.toList Map String YamlExpression
obj


instance Finder TomlExpression where
  toList :: TomlExpression -> [(String, TomlExpression)]
toList = \case
    nil :: TomlExpression
nil@TomlExpression
TomlNull              -> [(String
"", TomlExpression
nil)]
    n :: TomlExpression
n@(TomlInteger Integer
_)         -> [(String
"", TomlExpression
n)]
    n :: TomlExpression
n@(TomlFloat Double
_)           -> [(String
"", TomlExpression
n)]
    bool :: TomlExpression
bool@(TomlBool Bool
_)         -> [(String
"", TomlExpression
bool)]
    str :: TomlExpression
str@(TomlString String
_)        -> [(String
"", TomlExpression
str)]
    date :: TomlExpression
date@(TomlDate Day
_)         -> [(String
"", TomlExpression
date)]
    time :: TomlExpression
time@(TomlTime TimeOfDay
_)         -> [(String
"", TomlExpression
time)]
    dateTime :: TomlExpression
dateTime@(TomlDateTime ZonedTime
_) -> [(String
"", TomlExpression
dateTime)]
    TomlArray [TomlExpression]
arr             -> forall a b. [a] -> [b] -> [(a, b)]
zip (forall a. Show a => a -> String
show forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Int
0 .. forall (t :: * -> *) a. Foldable t => t a -> Int
length [TomlExpression]
arr forall a. Num a => a -> a -> a
- Int
1]) [TomlExpression]
arr
    TomlTable TableType
_ Map String TomlExpression
obj           -> forall k a. Map k a -> [(k, a)]
Map.toList Map String TomlExpression
obj