-- |Type for individual executed trades from the API.
module Cryptsy.API.Public.Types.Trade
	( module Cryptsy.API.Public.Types.Trade
	, module Cryptsy.API.Public.Types.Num
	, module Cryptsy.API.Public.Types.Time
	)
where

-- base
import Control.Applicative ((<$>), (<*>))

-- text
import Data.Text (Text, pack)

-- aeson
import Data.Aeson (FromJSON(..), Value, withObject, (.:))
import Data.Aeson.Types (Parser)

-- this package
import Cryptsy.API.Public.Types.Num
import Cryptsy.API.Public.Types.Time

-- |generalized trade
data GTrade dt p q t = Trade
	{ tradeId :: Text
	, tradeTime :: dt
	, tradePrice :: p
	, tradeQuantity :: q
	, tradeTotal :: t
	} deriving Show

-- |standard trade
type Trade = GTrade CryptsyTime CryptsyNum CryptsyNum CryptsyNum

instance (FromJSON dt, FromJSON p, FromJSON q, FromJSON t) =>
	FromJSON (GTrade dt p q t)
 where
	parseJSON = parseTrade parseJSON parseJSON parseJSON parseJSON

-- |Combine component parsers into JSON Object parser.
parseTrade :: (Value -> Parser dt) -- ^ date/time parser
           -> (Value -> Parser p)  -- ^ price parser
           -> (Value -> Parser q)  -- ^ quantity parser
           -> (Value -> Parser t)  -- ^ total parser
           -> Value -> Parser (GTrade dt p q t)
parseTrade parseDatetime parsePrice parseQuantity parseTotal =
	withObject "Trade" $ \o -> Trade         <$>
	 o .: pack "id"                          <*>
	(o .: pack "time"     >>= parseDatetime) <*>
	(o .: pack "price"    >>= parsePrice   ) <*>
	(o .: pack "quantity" >>= parseQuantity) <*>
	(o .: pack "total"    >>= parseTotal   )
{-# INLINABLE parseTrade #-}