content: {-# LANGUAGE DeriveDataTypeable        #-}
  {-# LANGUAGE FlexibleContexts          #-}
  {-# LANGUAGE FlexibleInstances         #-}
  {-# LANGUAGE MultiParamTypeClasses     #-}
  {-# LANGUAGE NoMonomorphismRestriction #-}
  {-# LANGUAGE OverloadedStrings         #-}
  {-# LANGUAGE RecordWildCards           #-}
  {-# LANGUAGE ScopedTypeVariables       #-}
  {-# LANGUAGE TypeFamilies              #-}
  -----------------------------------------------------------------------------
  -- |
  -- Module      :  Aws.DynamoDb.Commands.BatchGetItem
  -- Copyright   :  Soostone Inc
  -- License     :  BSD3
  --
  -- Maintainer  :  Justin Dawson <jtdawso@gmail.com>
  -- Stability   :  experimental
  --
  -- @http:\/\/docs.aws.amazon.com\/amazondynamodb\/latest\/APIReference\/API_BatchGetItem.html@
  ----------------------------------------------------------------------------
  
  module Aws.DynamoDb.Commands.BatchGetItem where
  
  -------------------------------------------------------------------------------
  import           Control.Applicative
  import           Data.Aeson
  import           Data.Default
  import qualified Data.HashMap.Strict as HM
  import qualified Data.Text           as T
  import           Prelude
  -------------------------------------------------------------------------------
  import           Aws.Core
  import           Aws.DynamoDb.Core
  import           Aws.DynamoDb.Commands.GetItem
  -------------------------------------------------------------------------------
  
  
  data GetRequestItem = GetRequestItem{
           griProjExpr :: Maybe T.Text
         , griConsistent ::Bool
         , griKeys :: [PrimaryKey]  
       } deriving (Eq,Show,Read,Ord)
  
  data BatchGetItem = BatchGetItem {
        bgRequests :: [(T.Text,GetRequestItem)]
      -- ^ Get Requests for a specified table
      , bgRetCons :: ReturnConsumption
      } deriving (Eq,Show,Read,Ord)
  
  -------------------------------------------------------------------------------
  
  -- | Construct a RequestItem .
  batchGetRequestItem :: Maybe T.Text
                 -- ^ Projection Expression
                 -> Bool
                 -- ^ Consistent Read
                 -> [PrimaryKey]
                 -- ^ Items to be deleted
                 -> GetRequestItem
  batchGetRequestItem expr consistent keys = GetRequestItem expr consistent keys
  
  toBatchGet :: [GetItem] -> BatchGetItem
  toBatchGet gs = BatchGetItem (convert gs) def
  
    where
      groupItems :: [GetItem]-> HM.HashMap T.Text [GetItem] -> HM.HashMap T.Text [GetItem]
      groupItems [] hm = hm
      groupItems (x:xs) hm = let key = giTableName x
                               in groupItems xs (HM.insert key (x : (HM.lookupDefault [] key hm)) hm)
      
      convert :: [GetItem] -> [(T.Text,GetRequestItem)] 
      convert gs' = let l = HM.toList $ groupItems gs' HM.empty
                      -- Uses one GetItem to specify ProjectionExpression
                      -- and ConsistentRead for the entire batch
                      in map (\(table,items@(i:_)) ->(table,GetRequestItem 
                                                      (T.intercalate "," <$> giAttrs i)
                                                      (giConsistent i)
                                                      (map giKey items)) ) l
  
  -- | Construct a BatchGetItem
  batchGetItem :: [(T.Text, GetRequestItem)]
                 -> BatchGetItem
  batchGetItem reqs = BatchGetItem reqs def
  
  
  instance ToJSON GetRequestItem where
     toJSON GetRequestItem{..} =
         (object $ maybe [] (return . ("ProjectionExpression" .=)) griProjExpr ++
                   ["ConsistentRead" .= griConsistent
                   , "Keys" .= griKeys])
           
  
  instance ToJSON BatchGetItem where
      toJSON BatchGetItem{..} =
          object $
            [ "RequestItems" .= HM.fromList bgRequests
            , "ReturnConsumedCapacity" .= bgRetCons
            ]
  
  instance FromJSON GetRequestItem where
      parseJSON (Object p) = do
                   GetRequestItem <$> p .:? "ProjectionExpression"
                                  <*> p .: "ConsistentRead"
                                  <*> p .: "Keys"
      parseJSON _ = fail "unable to parse GetRequestItem"
      
           
  data BatchGetItemResponse = BatchGetItemResponse {
        bgResponses :: [(T.Text, [Item])]
      , bgUnprocessed    :: Maybe [(T.Text,GetRequestItem)]
      -- ^ Unprocessed Requests on failure
      , bgConsumed :: Maybe ConsumedCapacity
      -- ^ Amount of capacity consumed
      } deriving (Eq,Show,Read,Ord)
  
  
  
  instance Transaction BatchGetItem BatchGetItemResponse
  
  
  instance SignQuery BatchGetItem where
      type ServiceConfiguration BatchGetItem = DdbConfiguration
      signQuery gi = ddbSignQuery "BatchGetItem" gi
  
  
  instance FromJSON BatchGetItemResponse where
      parseJSON (Object v) = BatchGetItemResponse
          <$> (HM.toList <$> (v .: "Responses"))
          <*> v .:? "UnprocessedItems"
          <*> v .:? "ConsumedCapacity"
  
      parseJSON _ = fail "BatchGetItemResponse must be an object."
  
  instance ResponseConsumer r BatchGetItemResponse where
      type ResponseMetadata BatchGetItemResponse = DdbResponse
      responseConsumer _ _ ref resp = ddbResponseConsumer ref resp
  
  instance AsMemoryResponse BatchGetItemResponse where
      type MemoryResponse BatchGetItemResponse = BatchGetItemResponse
      loadToMemory = return
  
  
  