/* ****************************************************************************
*
* deleteIndividualContextEntityAttribute - 
*
* DELETE /v1/contextEntities/{entityId::id}/attributes/{attributeName}
* DELETE /ngsi10/contextEntities/{entityId::id}/attributes/{attributeName}
*
* Payload In:  None
* Payload Out: StatusCode
*
* URI parameters:
*   - 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.
*   [ attributesFormat=object: makes no sense for this operation as StatusCode is returned ]
*   
* 0. Take care of URI params
* 1. Fill in UpdateContextRequest from URL-path components
* 2. Call postUpdateContext standard service routine
* 3. Translate UpdateContextResponse to StatusCode
* 4. Cleanup and return result
*/
std::string deleteIndividualContextEntityAttribute
(
  ConnectionInfo*            ciP,
  int                        components,
  std::vector<std::string>&  compV,
  ParseData*                 parseDataP
)
{
  std::string  answer;
  std::string  entityId      = compV[2];
  std::string  entityType    = ciP->uriParam[URI_PARAM_ENTITY_TYPE];
  std::string  attributeName = compV[4];
  StatusCode   response;


  // 1. Fill in UpdateContextRequest from URL-path components
  parseDataP->upcr.res.fill(entityId, entityType, "false", attributeName, "", "DELETE");


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


  // 3. Translate UpdateContextResponse to StatusCode
  response.fill(parseDataP->upcrs.res);


  // 4. Cleanup and return result
  TIMED_RENDER(answer = response.render("", false, false));

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

  return answer;
}
/* ****************************************************************************
*
* putAttributeValueInstance - 
*
* PUT /v1/contextEntities/{entity::id}/attributes/{attribute::name}/{metaID}
* PUT /ngsi10/contextEntities/{entity::id}/attributes/{attribute::name}/{metaID}
*
* Payload In:  UpdateContextAttributeRequest
* Payload Out: StatusCode
*
* URI parameters
*   - entity::type=TYPE
*   - note that '!exist=entity::type' and 'exist=entity::type' are not supported by convenience operations
*     that don't use the standard operation QueryContext as there is no Restriction otherwise.
*     Here, entity::type can be empty though, and it is, unless the URI parameter 'entity::type=TYPE' is used.
*
* 01. Check validity of path components VS payload
* 02. Fill in UpdateContextRequest
* 03. Call postUpdateContext
* 04. Fill in StatusCode from UpdateContextResponse
* 05. Render result
* 06. Cleanup and return result
*/
std::string putAttributeValueInstance
(
  ConnectionInfo*            ciP,
  int                        components,
  std::vector<std::string>&  compV,
  ParseData*                 parseDataP
)
{
  std::string  entityId      = compV[2];
  std::string  attributeName = compV[4];
  std::string  metaID        = compV[5];
  std::string  entityType    = ciP->uriParam[URI_PARAM_ENTITY_TYPE];
  std::string  answer;
  StatusCode   response;


  // 01. Check validity of path components VS payload
  Metadata* mP = parseDataP->upcar.res.metadataVector.lookupByName("ID");

  if ((mP != NULL) && (mP->value != metaID))
  {
    std::string details = "unmatching metadata ID value URI/payload: /" + metaID + "/ vs /" + mP->value + "/";
    
    response.fill(SccBadRequest, details);
    answer = response.render(ciP->outFormat, "", false, false);
    parseDataP->upcar.res.release();

    return answer;
  }


  // 02. Fill in UpdateContextRequest
  parseDataP->upcr.res.fill(&parseDataP->upcar.res, entityId, entityType, attributeName, metaID, "UPDATE");


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


  // 04. Fill in StatusCode from UpdateContextResponse
  response.fill(parseDataP->upcrs.res);


  // 05. Render result
  answer = response.render(ciP->outFormat, "", false, false);


  // 06. Cleanup and return result
  response.release();
  parseDataP->upcar.res.release();
  parseDataP->upcr.res.release();
  parseDataP->upcrs.res.release();

  return answer;
}
/* ****************************************************************************
*
* deleteAttributeValueInstanceWithTypeAndId - 
*
* DELETE /v1/contextEntities/type/{entity::type}/id/{entity::id}/attributes/{attribute::name}/{metaID}
* DELETE /ngsi10/contextEntities/type/{entity::type}/id/{entity::id}/attributes/{attribute::name}/{metaID}
*
* Mapped Standard Operation: UpdateContextRequest/DELETE
*
* URI params:
*   - 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.
*
* 01. URI parameters
* 02. Check validity of URI params
* 03. Fill in UpdateContextRequest
* 04. Call postUpdateContext standard service routine
* 05. Translate UpdateContextResponse to StatusCode
* 06. Cleanup and return result
*/
std::string deleteAttributeValueInstanceWithTypeAndId
(
  ConnectionInfo*            ciP,
  int                        components,
  std::vector<std::string>&  compV,
  ParseData*                 parseDataP
)
{
  StatusCode              response;
  std::string             answer;
  std::string             entityTypeFromUriParam;
  std::string             entityTypeFromPath = compV[3];
  std::string             entityId           = compV[5];
  std::string             attributeName      = compV[7];
  std::string             metaId             = compV[8];


  // 01. URI parameters
  entityTypeFromUriParam    = ciP->uriParam[URI_PARAM_ENTITY_TYPE];


  // 02. Check validity of URI params
  if ((entityTypeFromUriParam != "") && (entityTypeFromUriParam != entityTypeFromPath))
  {
    LM_W(("Bad Input non-matching entity::types in URL"));

    response.fill(SccBadRequest, "non-matching entity::types in URL");

    answer = response.render(ciP->outFormat, "", false, false);

    return answer;
  }


  // 03. Fill in UpdateContextRequest
  parseDataP->upcr.res.fill(entityId, entityTypeFromPath, "false", attributeName, metaId, "DELETE");


  // 04. Call postUpdateContext standard service routine
  answer = postUpdateContext(ciP, components, compV, parseDataP);


  // 05. Translate UpdateContextResponse to StatusCode
  response.fill(parseDataP->upcrs.res);


  // 06. Cleanup and return result
  answer = response.render(ciP->outFormat, "", false, false);
  response.release();
  parseDataP->upcr.res.release();

  return answer;
}
/* ****************************************************************************
*
* deleteIndividualContextEntity - 
*/
std::string deleteIndividualContextEntity(ConnectionInfo* ciP, int components, std::vector<std::string>& compV, ParseData* parseDataP)
{
  std::string  answer;
  std::string  entityId = "unknown entityId";
  StatusCode   response;

  if (compV.size() > 2)
     entityId = compV[2];

  LM_T(LmtConvenience, ("CONVENIENCE: got a 'DELETE' request for entityId '%s'", entityId.c_str()));
  ciP->httpStatusCode = mapDeleteIndividualContextEntity(entityId, &response, ciP);
  answer = response.render(ciP->outFormat, "", false, false);
  response.release();

  return answer;
}
/* ****************************************************************************
*
* deleteAttributeValueInstance - 
*
* DELETE /v1/contextEntities/{entity::id}/attributes/{attribute::name}/{metaID}
* DELETE /ngsi10/contextEntities/{entity::id}/attributes/{attribute::name}/{metaID}
*
* Payload In:  None
* Payload Out: StatusCode
*
* Mapped Standard Operation: UpdateContextRequest/DELETE
*
* URI params:
*   - 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.
*
* 01. URI parameters
* 02. Fill in UpdateContextRequest
* 03. Call postUpdateContext standard service routine
* 04. Translate UpdateContextResponse to StatusCode
* 05. Cleanup and return result
*
*/
std::string deleteAttributeValueInstance
(
  ConnectionInfo*            ciP,
  int                        components,
  std::vector<std::string>&  compV,
  ParseData*                 parseDataP
)
{
  StatusCode              response;
  std::string             answer;
  std::string             entityId      = compV[2];
  std::string             attributeName = compV[4];
  std::string             metaId        = compV[5];
  std::string             entityType;

  // 01. URI parameters
  entityType    = ciP->uriParam[URI_PARAM_ENTITY_TYPE];

  // 02. Fill in UpdateContextRequest
  parseDataP->upcr.res.fill(entityId, entityType, "false", attributeName, metaId, "DELETE");

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


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


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

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

  return answer;
}
/* ****************************************************************************
*
* deleteIndividualContextEntity - 
*
* Corresponding Standard Operation: UpdateContext/DELETE
*
* DELETE /v1/contextEntities/{entityId::id}
*
* Payload In:  None
* Payload Out: StatusCode
*
* URI parameters:
*   - 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. URI params
* 01. Fill in UpdateContextRequest from URL-data + URI params
* 02. Call postUpdateContext standard service routine
* 03. Translate UpdateContextResponse to StatusCode
* 04. If not found, put entity info in details
* 05. Cleanup and return result
*/
std::string deleteIndividualContextEntity
(
  ConnectionInfo*            ciP,
  int                        components,
  std::vector<std::string>&  compV,
  ParseData*                 parseDataP
)
{
  std::string  answer;
  std::string  entityId   = compV[2];
  std::string  entityType = ciP->uriParam[URI_PARAM_ENTITY_TYPE];
  StatusCode   response;

  // 01. Fill in UpdateContextRequest fromURL-data + URI params
  parseDataP->upcr.res.fill(entityId, entityType, "false", "", "", "DELETE");

  // 02. Call postUpdateContext standard service routine
  answer = postUpdateContext(ciP, components, compV, parseDataP);

  // 03. Translate UpdateContextResponse to StatusCode
  response.fill(parseDataP->upcrs.res);

  // 04. If not found, put entity info in details
  if ((response.code == SccContextElementNotFound) && (response.details == ""))
  {
    response.details = entityId;
  }

  // 05. Cleanup and return result
  TIMED_RENDER(answer = response.render(ciP->outFormat, "", false, false));

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

  return answer;
}
/* ****************************************************************************
*
* deleteAllEntitiesWithTypeAndId - 
*
* DELETE /v1/contextEntities/type/{entity::type}/id/{entity::id}
*
* Payload In:  None
* Payload Out: StatusCode
*
* URI parameters:
*   - entity::type=TYPE (must coincide with type in URL-path)
*   - !exist=entity::type  (if set - error -- entity::type cannot be empty)
*   - exist=entity::type   (not supported - ok if present, ok if not present ...)
*
* 01. Get values from URL (+ entityId::type, exist, !exist)
* 02. Check validity of URI params
* 03. Fill in UpdateContextRequest
* 04. Call Standard Operation
* 05. Fill in response from UpdateContextResponse
* 06. Cleanup and return result
*/
std::string deleteAllEntitiesWithTypeAndId
(
  ConnectionInfo*            ciP,
  int                        components,
  std::vector<std::string>&  compV,
  ParseData*                 parseDataP
)
{
  std::string     entityType            = compV[3];
  std::string     entityId              = compV[5];
  EntityTypeInfo  typeInfo              = EntityTypeEmptyOrNotEmpty;
  std::string     typeNameFromUriParam  = ciP->uriParam[URI_PARAM_ENTITY_TYPE];
  std::string     answer;
  StatusCode      response;

  // 01. Get values from URL (+ entityId::type, exist, !exist)
  if (ciP->uriParam[URI_PARAM_NOT_EXIST] == URI_PARAM_ENTITY_TYPE)
  {
    typeInfo = EntityTypeEmpty;
  }
  else if (ciP->uriParam[URI_PARAM_EXIST] == URI_PARAM_ENTITY_TYPE)
  {
    typeInfo = EntityTypeNotEmpty;
  }


  // 02. Check validity of URI params
  if (typeInfo == EntityTypeEmpty)
  {
    alarmMgr.badInput(clientIp, "entity::type cannot be empty for this request");

    response.fill(SccBadRequest, "entity::type cannot be empty for this request");

    TIMED_RENDER(answer = response.render("", false, false));

    return answer;
  }
  else if ((typeNameFromUriParam != entityType) && (typeNameFromUriParam != ""))
  {
    alarmMgr.badInput(clientIp, "non-matching entity::types in URL");

    response.fill(SccBadRequest, "non-matching entity::types in URL");

    TIMED_RENDER(answer = response.render("", false, false));

    return answer;
  }


  // 03. Fill in UpdateContextRequest
  parseDataP->upcr.res.fill(entityId, entityType, "", "", "", "DELETE");


  // 04. Call Standard Operation
  postUpdateContext(ciP, components, compV, parseDataP);


  // 05. Fill in response from UpdateContextResponse
  response.fill(parseDataP->upcrs.res);


  // 06. Cleanup and return result
  TIMED_RENDER(answer = response.render("", false, false));

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

  return answer;
}
/* ****************************************************************************
*
* postAttributeValueInstanceWithTypeAndId - 
*
* POST /v1/contextEntities/type/{entity::type}/id/{entity::id}/attributes/{attribute::name}/{metaID}
* POST /ngsi10/contextEntities/type/{entity::type}/id/{entity::id}/attributes/{attribute::name}/{metaID}
*
* Payload In:  UpdateContextAttributeRequest
* Payload Out: StatusCode
*
* Mapped Standard Operation: UpdateContextRequest/APPEND
*
* URI parameters
*   - 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. Get values from URI path
* 01. Get values URI parameters
* 02. Check validity of URI params VS URI path components
* 03. Check validity of path components VS payload
* 04. Fill in UpdateContextRequest
* 05. Call postUpdateContext
* 06. Fill in StatusCode from UpdateContextResponse
* 07. Render result
* 08. Cleanup and return result
*/
std::string postAttributeValueInstanceWithTypeAndId
(
  ConnectionInfo*            ciP,
  int                        components,
  std::vector<std::string>&  compV,
  ParseData*                 parseDataP
)
{
  std::string     entityType              = compV[3];
  std::string     entityId                = compV[5];
  std::string     attributeName           = compV[7];
  std::string     metaID                  = compV[8];
  std::string     entityTypeFromUriParam;
  StatusCode      response;
  std::string     answer;


  // 01. Get values URI parameters
  entityTypeFromUriParam  = ciP->uriParam[URI_PARAM_ENTITY_TYPE];


  // 02. Check validity of URI params VS URI path components
  if ((entityTypeFromUriParam != "") && (entityTypeFromUriParam != entityType))
  {
    LM_W(("Bad Input non-matching entity::types in URL"));
    response.fill(SccBadRequest, "non-matching entity::types in URL");
    answer = response.render(ciP->outFormat, "", false, false);

    parseDataP->upcar.res.release();
    return answer;
  }


  // 03. Check validity of path components VS payload
  Metadata* mP = parseDataP->upcar.res.metadataVector.lookupByName("ID");

  if ((mP != NULL) && (mP->value != metaID))
  {
    std::string details = "unmatching metadata ID value URI/payload: /" + metaID + "/ vs /" + mP->value + "/";
    
    response.fill(SccBadRequest, details);
    answer = response.render(ciP->outFormat, "", false, false);
    parseDataP->upcar.res.release();

    return answer;
  }


  // 04. Fill in UpdateContextRequest
  parseDataP->upcr.res.fill(&parseDataP->upcar.res, entityId, entityType, attributeName, metaID, "APPEND");


  // 05. Call postUpdateContext
  postUpdateContext(ciP, components, compV, parseDataP);


  // 06. Fill in StatusCode from UpdateContextResponse
  response.fill(parseDataP->upcrs.res);


  // 07. Render result
  answer = response.render(ciP->outFormat, "", false, false);


  // 08. Cleanup and return result
  response.release();
  parseDataP->upcar.res.release();
  parseDataP->upcr.res.release();
  parseDataP->upcrs.res.release();

  return answer;
}