{-# 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