{-# LANGUAGE UndecidableInstances #-}
-- |Type for order books returned from the API.
module Cryptsy.API.Public.Types.OrderBook
	( module Cryptsy.API.Public.Types.OrderBook
	, module Cryptsy.API.Public.Types.Num
	, module Cryptsy.API.Public.Types.Order
	)
where

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

-- base
import Control.Applicative ((<*>))
import Data.Functor ((<$>))
import Data.Traversable (mapM)
import Prelude hiding (mapM)

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

-- vector
import Data.Vector (Vector)

-- this package
import Cryptsy.API.Public.Types.Internal
import Cryptsy.API.Public.Types.Num
import Cryptsy.API.Public.Types.Order

-- |general order book
data GOrderBook p q t = OrderBook
	{ obMarketId :: Text
	, obLabel :: Text
	, obPrimaryName :: Text
	, obPrimaryCode :: Text
	, obSecondaryName :: Text
	, obSecondaryCode :: Text
	, obSellOrders :: Vector (GOrder p q t)
	, obBuyOrders :: Vector (GOrder p q t)
	} deriving Show

-- |default order book
type OrderBook = GOrderBook CryptsyNum CryptsyNum CryptsyNum

instance FromJSON (GOrder p q t) => FromJSON (GOrderBook p q t) where
	parseJSON = parseOrderBook parseJSON

-- |Build parser for orderbook from parser for a single order.
parseOrderBook :: (Value -> Parser (GOrder p q t))  -- ^ order parser
               -> Value -> Parser (GOrderBook p q t)
parseOrderBook parser =
	withObject "OrderBook" $ \o -> OrderBook        <$>
	 o .: pack "marketid"                           <*>
	 o .: pack "label"                              <*>
	 o .: pack "primaryname"                        <*>
	 o .: pack "primarycode"                        <*>
	 o .: pack "secondaryname"                      <*>
	 o .: pack "secondarycode"                      <*>
	(o .: pack "sellorders"    >>= parseSellOrders) <*>
	(o .: pack "buyorders"     >>= parseBuyOrders )
 where
	parseOrders = mapM parser
	parseSellOrders = withNullableArray "sellorders" parseOrders
	parseBuyOrders  = withNullableArray "buyorders"  parseOrders
{-# INLINABLE parseOrderBook #-}