/* ****************************************************************************
*
* ContextAttributeVector::fill - 
*/
void ContextAttributeVector::fill(ContextAttributeVector& caV)
{
  for (unsigned int ix = 0; ix < caV.size(); ++ix)
  {
    ContextAttribute* caP = new ContextAttribute(caV.get(ix));

    push_back(caP);
  }
}
/* ****************************************************************************
*
* equalContextAttributeVector -
*/
static bool equalContextAttributeVector(ContextAttributeVector caExpectedV, ContextAttributeVector caArgV) {

    /* Check vector size */
    if (caExpectedV.size() != caArgV.size()) {
        LM_M(("different sizes: expected %d, actual %d", caExpectedV.size(), caArgV.size()));
        return false;
    }

    /* Check that every attribute in 'caExpectedV' is in 'caArgV'. Order doesn't matter */
    for (unsigned int ix = 0; ix < caArgV.size(); ++ix) {
        bool attributeMatch = false;
        for (unsigned int jx = 0; jx < caExpectedV.size(); ++jx) {
            ContextAttribute* caArg = caArgV.get(ix);
            ContextAttribute* caExpected = caExpectedV.get(jx);
            LM_M(("%d == %d?", ix, jx));
            if (equalContextAttribute(caExpected, caArg)) {
                LM_M(("attribute matches in ContextAttributeVector comparison, check next one..."));
                attributeMatch = true;
                break; /* loop in jx */
            }
        }
        if (!attributeMatch) {
            LM_M(("after looking everyone, attribute doesn't match in ContextAttributeVector comparison"));
            return false;
        }
    }

    LM_M(("ContextAttributeVector comparison ok"));
    return true;

}
/* ****************************************************************************
*
* render - 
*/
TEST(ContextAttributeVector, render)
{
  ContextAttributeVector  cav;
  ContextAttribute        ca("Name", "Type", "Value");
  std::string             out;
  const char*             outfile = "ngsi.contextAttributeList.render.middle.xml";
  ConnectionInfo          ci(XML);

  utInit();

  out = cav.render(&ci, UpdateContextAttribute, "");
  EXPECT_STREQ("", out.c_str());

  cav.push_back(&ca);
  out = cav.render(&ci, UpdateContextAttribute, "");
  EXPECT_EQ("OK", testDataFromFile(expectedBuf, sizeof(expectedBuf), outfile)) << "Error getting test data from '" << outfile << "'";
  EXPECT_STREQ(expectedBuf, out.c_str());

  // Just to exercise the code ...
  cav.present("");

  utExit();
}
/* ****************************************************************************
*
* getAttributeValueInstance - 
*
* GET /ngsi10/contextEntities/{entityID}/attributes/{attributeName}/{valueID}
*/
std::string getAttributeValueInstance
(
  ConnectionInfo*            ciP,
  int                        components,
  std::vector<std::string>&  compV,
  ParseData*                 parseDataP
)
{
  QueryContextRequest      request;
  QueryContextResponse     response;
  std::string              entityId      = compV[2];
  std::string              attributeName = compV[4];
  std::string              valueID       = compV[5];
  EntityId*                eP            = new EntityId(entityId, "", "false");
  StatusCode               sc;
  ContextAttributeResponse car;

  request.entityIdVector.push_back(eP);
  request.attributeList.push_back(attributeName);

  ciP->httpStatusCode = mongoQueryContext(&request, &response, ciP->tenant, ciP->servicePathV, ciP->uriParam);

  if (response.contextElementResponseVector.size() == 0)
  {
     car.statusCode.fill(SccContextElementNotFound,
                         std::string("Entity-Attribute pair: /") + entityId + "-" + attributeName + "/");
  }
  else
  {
    ContextElementResponse* cerP = response.contextElementResponseVector.get(0);
    ContextAttributeVector cav = cerP->contextElement.contextAttributeVector;

    // FIXME P4: as long as mongoQueryContext() signature is based on NGSI standard operations and that
    // standard queryContext doesn't allow specify metadata for attributes (note that it uses xs:string,
    // not full fledge attribute types), we cannot pass the ID to mongoBackend so we need to do the for loop
    // to grep the right attribute among all the ones returned by mongoQueryContext. However, this involves
    // a suboptimal query at mongoBackend, which could be improved passing it the ID as a new parameter to
    // mongoQueryContext() (although breaking the design principle about mongo*() functions follow the NGSI
    // standard). To think about it.
    for (unsigned int i = 0; i < cav.size(); i++)
    {
      if (cav.get(i)->getId() == valueID)
      {
        car.contextAttributeVector.push_back(cav.get(i));
      }
    }

    if (cav.size() > 0 && car.contextAttributeVector.size() == 0)
    {
      car.statusCode.fill(SccContextElementNotFound,
                          std::string("Attribute-ValueID pair: /") + attributeName + "-" + valueID + "/");
    }
    else
    {
      car.statusCode.fill(&cerP->statusCode);
    }
  }

  request.release();

  return car.render(ciP, AttributeValueInstance, "");
}