/* ****************************************************************************
*
* check_json - 
*/
TEST(AppendContextElementResponse, check_json)
{
  AppendContextElementResponse  acer;
  ContextAttributeResponse      car;
  ContextAttribute              ca("", "TYPE", "VALUE"); // empty name, thus provoking error
  std::string                   out;
  const char*                   outfile1 = "ngsi10.appendContextElementRequest.check1.postponed.json";
  const char*                   outfile2 = "ngsi10.appendContextElementRequest.check2.postponed.json";
  ConnectionInfo                ci;

  utInit();

  // 1. predetected error
  ci.outMimeType = JSON;
  out = acer.check(&ci, IndividualContextEntity, "", "PRE ERR", 0);
  EXPECT_EQ("OK", testDataFromFile(expectedBuf, sizeof(expectedBuf), outfile1)) << "Error getting test data from '" << outfile1 << "'";
  EXPECT_STREQ(expectedBuf, out.c_str());

  // 2. bad contextAttributeResponseVector
  car.contextAttributeVector.push_back(&ca);
  acer.contextAttributeResponseVector.push_back(&car);
  out = acer.check(&ci, IndividualContextEntity, "", "", 0);
  EXPECT_EQ("OK", testDataFromFile(expectedBuf, sizeof(expectedBuf), outfile2)) << "Error getting test data from '" << outfile2 << "'";
  EXPECT_STREQ(expectedBuf, out.c_str());

  // 3. OK
  ca.name = "NAME";
  out = acer.check(&ci, IndividualContextEntity, "", "", 0);
  EXPECT_EQ("OK", out);

  utExit();
}  
/* ****************************************************************************
*
* render_json - 
*/
TEST(AppendContextElementResponse, render_json)
{
  AppendContextElementResponse  acer;
  ContextAttributeResponse      car;
  std::string                   out;
  const char*                   outfile1 = "ngsi10.appendContextElementResponse.empty.valid.json";
  const char*                   outfile2 = "ngsi10.appendContextElementResponse.badRequest.valid.json";
  ConnectionInfo                ci;

  utInit();

  // 1. empty acer
  ci.outMimeType = JSON;
  out = acer.render(&ci, AppendContextElement, "");
  EXPECT_EQ("OK", testDataFromFile(expectedBuf, sizeof(expectedBuf), outfile1)) << "Error getting test data from '" << outfile1 << "'";
  EXPECT_STREQ(expectedBuf, out.c_str());

  // 2. errorCode 'active'
  acer.errorCode.fill(SccBadRequest, "very bad request");
  out = acer.render(&ci, AppendContextElement, "");
  EXPECT_EQ("OK", testDataFromFile(expectedBuf, sizeof(expectedBuf), outfile2)) << "Error getting test data from '" << outfile2 << "'";
  EXPECT_STREQ(expectedBuf, out.c_str());

  utExit();
}   
/* ****************************************************************************
*
* check - 
*
* FIXME P3: once (if ever) AttributeDomainName::check stops to always return "OK", put back this piece of code 
*           in its place:
-
*   else if ((res = attributeDomainName.check(AppendContextElement, format, indent, predetectedError, counter)) != "OK")
*   {
*     response.errorCode.fill(SccBadRequest, res):
*   }
*
*/
std::string AppendContextElementRequest::check
(
  ConnectionInfo*  ciP,
  RequestType      requestType,
  std::string      indent,
  std::string      predetectedError,     // Predetected Error, normally during parsing
  int              counter
)
{
  AppendContextElementResponse  response;
  std::string                   res;
  Format                        fmt = ciP->outFormat;

  if (predetectedError != "")
  {
    response.errorCode.fill(SccBadRequest, predetectedError);
  }
  else if ((res = contextAttributeVector.check(ciP, AppendContextElement, fmt, indent, predetectedError, counter)) != "OK")
  {
    response.errorCode.fill(SccBadRequest, res);
  }
  else if ((res = domainMetadataVector.check(ciP, AppendContextElement, fmt, indent, predetectedError, counter)) != "OK")
  {
    response.errorCode.fill(SccBadRequest, res);
  }
  else
  {
    return "OK";
  }

  return response.render(ciP, requestType, indent);
}
/* ****************************************************************************
*
* release - 
*/
TEST(AppendContextElementResponse, release)
{
  AppendContextElementResponse  acer;
  ContextAttributeResponse*     carP = new ContextAttributeResponse();
  ContextAttribute*             caP  = new ContextAttribute("NAME", "TYPE", "VALUE");

  utInit();

  carP->contextAttributeVector.push_back(caP);
  acer.contextAttributeResponseVector.push_back(carP);

  EXPECT_EQ(1, carP->contextAttributeVector.size());
  EXPECT_EQ(1, acer.contextAttributeResponseVector.size());
  acer.release();
  EXPECT_EQ(0, acer.contextAttributeResponseVector.size());

  utExit();
}
/* ****************************************************************************
*
* postIndividualContextEntityAttributes - 
*/
std::string postIndividualContextEntityAttributes
(
  ConnectionInfo*            ciP,
  int                        components,
  std::vector<std::string>&  compV,
  ParseData*                 parseDataP
)
{
  std::string                   answer;
  std::string                   entityId = compV[2];
  AppendContextElementResponse* responseP = new AppendContextElementResponse();

  LM_T(LmtConvenience, ("CONVENIENCE: got a 'POST' request for entityId '%s'", entityId.c_str()));

  ciP->httpStatusCode = mapPostIndividualContextEntityAttributes(entityId, &parseDataP->acer.res, responseP, ciP);
  answer = responseP->render(ciP, IndividualContextEntityAttributes, "");
  responseP->release();
  delete responseP;

  return answer;
}
/* ****************************************************************************
*
* postIndividualContextEntity -
*
* Corresponding Standard Operation: UpdateContext/APPEND
*
* NOTE
*   This function is used for two different URLs:
*     o /v1/contextEntities
*     o /v1/contextEntities/{entityId::id}
*
* In the longer URL (with entityId::id), the payload (AppendContextElementRequest) cannot contain any
* entityId data (id, type, isPattern).
* In the first case, the entityId data of the payload is mandatory.
* entityId::type can be empty, as always, but entityId::id MUST be filled in.
*
* POST /v1/contextEntities
* POST /ngsi10/contextEntities
* POST /v1/contextEntities/{entityId::id}
* POST /ngsi10/contextEntities/{entityId::id}
*
* Payload In:  AppendContextElementRequest
* Payload Out: AppendContextElementResponse
*
* URI parameters:
*   - attributesFormat=object
*   - entity::type=TYPE
*   - note that '!exist=entity::type' and 'exist=entity::type' are not supported by convenience operations
*     that use the standard operation UpdateContext as there is no restriction within UpdateContext.
*
* 00. Take care of URI params
* 01. Check that total input in consistent and correct
* 02. Fill in UpdateContextRequest from AppendContextElementRequest + URL-data + URI params
* 03. Call postUpdateContext standard service routine
* 04. Translate UpdateContextResponse to AppendContextElementResponse
* 05. Cleanup and return result
*/
std::string postIndividualContextEntity
(
  ConnectionInfo*            ciP,
  int                        components,
  std::vector<std::string>&  compV,
  ParseData*                 parseDataP
)
{
  AppendContextElementRequest*  reqP                  = &parseDataP->acer.res;
  AppendContextElementResponse  response;
  std::string                   entityIdFromPayload   = reqP->entity.id;
  std::string                   entityIdFromURL       = ((compV.size() == 3) || (compV.size() == 4))? compV[2] : "";
  std::string                   entityId;
  std::string                   entityTypeFromPayload = reqP->entity.type;
  std::string                   entityTypeFromURL     = ciP->uriParam[URI_PARAM_ENTITY_TYPE];
  std::string                   entityType;
  std::string                   answer;
  std::string                   out;


  //
  // 01. Check that total input in consistent and correct
  //

  // 01.01. entityId::id
  if ((entityIdFromPayload != "") && (entityIdFromURL != "") && (entityIdFromPayload != entityIdFromURL))
  {
    std::string error = "entityId::id differs in URL and payload";

    alarmMgr.badInput(clientIp, error);
    response.errorCode.fill(SccBadRequest, error);

    TIMED_RENDER(out = response.render(ciP, IndividualContextEntity, ""));
    return out;
  }  
  entityId = (entityIdFromPayload != "")? entityIdFromPayload : entityIdFromURL;

  // 01.02. entityId::type
  if ((entityTypeFromPayload != "") && (entityTypeFromURL != "") && (entityTypeFromPayload != entityTypeFromURL))
  {
    std::string error = "entityId::type differs in URL and payload";

    alarmMgr.badInput(clientIp, error);
    response.errorCode.fill(SccBadRequest, error);

    TIMED_RENDER(out = response.render(ciP, IndividualContextEntity, ""));
    return out;
  }
  entityType = (entityTypeFromPayload != "")? entityTypeFromPayload :entityTypeFromURL;


  // 01.03. entityId::isPattern
  if (reqP->entity.isPattern == "true")
  {
    std::string error = "entityId::isPattern set to true in contextUpdate convenience operation";

    alarmMgr.badInput(clientIp, error);
    response.errorCode.fill(SccBadRequest, error);

    TIMED_RENDER(out = response.render(ciP, IndividualContextEntity, ""));
    return out;
  }

  // 01.04. Entity::id must be present, somewhere ...
  if (entityId == "")
  {
    std::string error = "invalid request: mandatory entityId::id missing";

    alarmMgr.badInput(clientIp, error);
    response.errorCode.fill(SccBadRequest, error);

    TIMED_RENDER(out = response.render(ciP, IndividualContextEntity, ""));
    return out;
  }

  // Now, forward Entity to response
  response.entity.fill(entityId, entityType, "false");


  //
  // 02. Fill in UpdateContextRequest from AppendContextElementRequest + URL-data + URI params
  //
  parseDataP->upcr.res.fill(&parseDataP->acer.res, entityId, entityType);


  // 03. Call postUpdateContext standard service routine
  postUpdateContext(ciP, components, compV, parseDataP);


  // 04. Translate UpdateContextResponse to AppendContextElementResponse
  response.fill(&parseDataP->upcrs.res);

  // 05. Cleanup and return result
  TIMED_RENDER(answer = response.render(ciP, IndividualContextEntity, ""));

  response.release();
  parseDataP->upcr.res.release();

  return answer;
}