#include "BatchAction.h"
#include "ActionManager.h"
#include "action/ActionResponse.h"
#include "AggreGateException.h"

BatchAction::BatchAction(ActionManagerPtr actionManager)
{
    this->actionManager = actionManager;
}

void BatchAction::init(ActionContextPtr actionContext, InitialRequestPtr initialParameters)
{
    UNUSED(initialParameters);
    this->actionContext = actionContext;
}

ActionCommandPtr BatchAction::service(ActionResponsePtr actionRequest)
{
    BatchContextPtr batchContext = actionContext->getBatchContext();
    if(batchContext == 0)
    {
        // It's incorrect to use BatchAction without BatchContext
        throw AggreGateException("Null pointer in BatchAction::service");
    }
    do {
        ActionCommandPtr actionCommand;
        if(currentActionId == 0)
        {
            BatchEntryPtr batchEntry = getNextEntry(batchContext);
            if(batchEntry == 0)
            {
                return ActionCommandPtr();
            }
            ActionContextPtr entryContext = batchEntry->getActionContext();
            entryContext->getRequestedIds().clear();
            currentActionId = actionManager->initAction(entryContext, batchEntry->getInitialRequest(), ActionExecutionModePtr(new ActionExecutionMode(ActionExecutionMode::BATCH())));
            actionCommand = actionManager->service(currentActionId, ActionResponsePtr());
        } else {
            actionCommand = actionManager->service(currentActionId, actionRequest);
        }
        if(actionCommand != 0)
        {
             actionCommand->setBatchEntry(true);
             return actionCommand;
        }
        else
        {  //todo
            currentActionId = ActionIdentifierPtr();
            batchContext->markAsPerfomed(batchContext->getCurrentEntry());
        }
    } while (true);
}

BatchEntryPtr BatchAction::getNextEntry(BatchContextPtr batchContext)
{
    std::list<BatchEntryPtr> entries = batchContext->getEntries();
    std::list<BatchEntryPtr>::const_iterator BatchEntryIt;

    for (BatchEntryIt = entries.begin(); BatchEntryIt!= entries.end(); ++BatchEntryIt)
    {
        BatchEntryPtr batchEntry = *BatchEntryIt;
        if(!batchEntry->isFulfilled())
        {
            batchContext->setCurrentEntry(batchEntry);
            return batchEntry;
        }
    }

    return BatchEntryPtr();
}

ActionResultPtr BatchAction::destroy()
{
    if(currentActionId != 0)
    {
        actionManager->destroyAction(currentActionId);
    }
    actionManager = ActionManagerPtr();
    actionContext = ActionContextPtr();
    currentActionId = ActionIdentifierPtr();
    return ActionResultPtr();
}



