content: {-# LANGUAGE TemplateHaskell #-}
  {-# OPTIONS_GHC -Wno-orphans #-}
  module Spec where
  
  import Data.Aeson
  import Data.Aeson.TH
  import Data.Char
  import Data.Monoid
  import Data.Text (Text)
  import Data.Vector (Vector)
  import qualified Data.Vector as V
  import Data.HashMap.Strict (HashMap)
  import qualified Data.HashMap.Strict as HM
  import Data.Set (Set)
  import qualified Data.Set as S
  
  import Types
  
  -- this is incredibly ad hoc.
  instance FromJSON Type where
    parseJSON = withText "C type" $ \str ->
      case runCParser (const True) "" str parseType of
        Left err -> fail $ show err
        Right val -> return val
  
  data GdnativeApis = GdnativeApis
    { core :: !GdnativeApi
    , extensions :: !(Vector GdnativeApi)
    } deriving (Show, Eq)
  
  data Ver = Ver { major :: !Int, minor :: !Int}
    deriving (Show, Eq)
  
  data GdnativeApi = GdnativeApi
    { apiType :: !Text
    , apiVersion :: !Ver
    , apiNext :: !(Maybe GdnativeApi)
    , apiApi :: !(Vector GdnativeApiEntry)
    } deriving (Show, Eq)
  
  data GdnativeApiEntry = GdnativeApiEntry
    { name :: !Text
    , return_type :: !Type
    , arguments :: !(Vector (Type, Text))
    } deriving (Show, Eq)
  
  deriveFromJSON defaultOptions ''Ver
  deriveFromJSON defaultOptions ''GdnativeApiEntry
  deriveFromJSON defaultOptions { fieldLabelModifier = map toLower . drop 3 } ''GdnativeApi
  deriveFromJSON defaultOptions ''GdnativeApis
  
  
  collectTypes :: GdnativeApis -> Set Type
  collectTypes apis = collectFromApi (core apis) <> mconcat (V.toList $ fmap collectFromApi $ extensions apis)
    where
      collectFromApi api = mconcat $ V.toList $ fmap collectFromEntry (apiApi api)
      collectFromEntry entry = S.singleton (return_type entry) <> (S.fromList $ V.toList $ fmap fst $ arguments entry)
  
  collectNames :: GdnativeApis -> Set Text
  collectNames apis = collectFromApi (core apis) <> mconcat (V.toList $ fmap collectFromApi $ extensions apis)
    where
      collectFromApi api = mconcat $ V.toList $ fmap collectFromEntry (apiApi api)
      collectFromEntry entry = S.fromList $ V.toList $ fmap snd $ arguments entry
  