SimulatorResourceModel SimulatorResourceFactory::buildResourceModel(
    std::shared_ptr<RAML::Items> item)
{
    SimulatorResourceModel itemModel;
    for ( auto &propElement : item->getProperties())
    {
        if (!propElement.second)
            continue;

        std::string propName = propElement.second->getName();
        if ("p" == propName || "n" == propName || "id" == propName)
        {
            continue;
        }

        if ("array" == propElement.second->getType())
        {
            std::vector<SimulatorResourceModel> arrayResModel;
            for ( auto &propertyItem : propElement.second->getItems())
            {
                arrayResModel.push_back(buildResourceModel(propertyItem));
            }
            itemModel.add(propName, arrayResModel);
        }
        else
        {
            itemModel.add(buildAttribute(propElement.second));
        }
    }
    return itemModel;
}
        void handleVectorTypeDepth1(SimulatorResourceModel &resModel,
                                    const OC::OCRepresentation::AttributeItem &ocAttribute)
        {
            if (OC::AttributeType::Integer == ocAttribute.base_type())
            {
                resModel.add(ocAttribute.attrname(), ocAttribute.getValue<std::vector<int>>());
            }
            else if (OC::AttributeType::Double == ocAttribute.base_type())
            {
                resModel.add(ocAttribute.attrname(), ocAttribute.getValue<std::vector<double>>());
            }
            else if (OC::AttributeType::Boolean == ocAttribute.base_type())
            {
                resModel.add(ocAttribute.attrname(), ocAttribute.getValue<std::vector<bool>>());
            }
            else if (OC::AttributeType::String == ocAttribute.base_type())
            {
                resModel.add(ocAttribute.attrname(), ocAttribute.getValue<std::vector<std::string>>());
            }
            else if (OC::AttributeType::OCRepresentation == ocAttribute.base_type())
            {
                std::vector<OC::OCRepresentation> ocSubRepArray =
                    ocAttribute.getValue<std::vector<OC::OCRepresentation>>();

                std::vector<SimulatorResourceModel> subResModelArray(ocSubRepArray.size());
                for  (size_t i = 0; i < ocSubRepArray.size(); i++)
                {
                    handleRepresentationType(subResModelArray[i], ocSubRepArray[i]);
                }

                resModel.add<std::vector<SimulatorResourceModel>>(ocAttribute.attrname(), subResModelArray);
            }
        }
JNIEXPORT jint JNICALL
Java_org_oic_simulator_SimulatorResourceModel_size
(JNIEnv *env, jobject thiz)
{
    SimulatorResourceModel resourceModel;
    bool result = JSimulatorResourceModel::getResourceModel(env, thiz, resourceModel);
    if (!result)
    {
        throwSimulatorException(env, SIMULATOR_BAD_OBJECT, "Resource model not found!");
        return SIMULATOR_BAD_OBJECT;
    }

    return resourceModel.size();
}
        void handleVectorTypeDepth3(SimulatorResourceModel &resModel,
                                    const OC::OCRepresentation::AttributeItem &ocAttribute)
        {
            if (OC::AttributeType::Integer == ocAttribute.base_type())
            {
                resModel.add(ocAttribute.attrname(),
                             ocAttribute.getValue<std::vector<std::vector<std::vector<int>>>>());
            }
            else if (OC::AttributeType::Double == ocAttribute.base_type())
            {
                resModel.add(ocAttribute.attrname(),
                             ocAttribute.getValue<std::vector<std::vector<std::vector<double>>>>());
            }
            else if (OC::AttributeType::Boolean == ocAttribute.base_type())
            {
                resModel.add(ocAttribute.attrname(),
                             ocAttribute.getValue<std::vector<std::vector<std::vector<bool>>>>());
            }
            else if (OC::AttributeType::String == ocAttribute.base_type())
            {
                resModel.add(ocAttribute.attrname(),
                             ocAttribute.getValue<std::vector<std::vector<std::vector<std::string>>>>());
            }
            else if (OC::AttributeType::OCRepresentation == ocAttribute.base_type())
            {
                std::vector<std::vector<std::vector<OC::OCRepresentation>>> ocSubRepArray =
                    ocAttribute.getValue<std::vector<std::vector<std::vector<OC::OCRepresentation>>>>();

                std::vector<std::vector<std::vector<SimulatorResourceModel>>> subResModelArray(
                    ocSubRepArray.size());
                for  (size_t i = 0; i < ocSubRepArray.size(); i++)
                {
                    std::vector<std::vector<SimulatorResourceModel>> innerArray1(ocSubRepArray[i].size());
                    for  (size_t j = 0; j < ocSubRepArray[i].size(); j++)
                    {
                        std::vector<SimulatorResourceModel> innerArray2(ocSubRepArray[i][j].size());
                        for  (size_t k = 0; k < ocSubRepArray[i][j].size(); k++)
                        {
                            handleRepresentationType(innerArray2[k], ocSubRepArray[i][j][k]);
                        }
                        innerArray1[j] = innerArray2;
                    }
                    subResModelArray[i] = innerArray1;
                }

                resModel.add<std::vector<std::vector<std::vector<SimulatorResourceModel>>>>(
                    ocAttribute.attrname(), subResModelArray);
            }
        }
        OC::OCRepresentation build(const SimulatorResourceModel &model)
        {
            OC::OCRepresentation ocRep;
            for (auto &element : model.getAttributeValues())
            {
                ValueConverter visitor(ocRep, element.first);
                boost::apply_visitor(visitor, element.second);
            }

            return std::move(ocRep);
        }
                void operator ()(const SimulatorResourceModel &value)
                {
                    OC::OCRepresentation ocRep;
                    for (auto &element : value.getAttributeValues())
                    {
                        ValueConverter visitor(ocRep, element.first);
                        boost::apply_visitor(visitor, element.second);
                    }

                    m_rep.setValue(m_name, ocRep);
                }
JNIEXPORT jobject JNICALL
Java_org_oic_simulator_SimulatorResourceModel_getAttribute
(JNIEnv *env, jobject thiz, jstring jAttrName)
{
    if (!jAttrName)
    {
        throwInvalidArgsException(env, SIMULATOR_INVALID_PARAM, "Invalid attribute name!");
        return nullptr;
    }

    const char *attrName = env->GetStringUTFChars(jAttrName, NULL);
    if (!attrName)
    {
        throwSimulatorException(env, SIMULATOR_ERROR, "String error!");
        return nullptr;
    }

    SimulatorResourceModel resourceModel;
    bool result = JSimulatorResourceModel::getResourceModel(env, thiz, resourceModel);
    if (!result)
    {
        env->ReleaseStringUTFChars(jAttrName, attrName);
        throwSimulatorException(env, SIMULATOR_BAD_OBJECT, "Resource model not found!");
        return nullptr;
    }

    SimulatorResourceModel::Attribute attribute;
    bool found = resourceModel.getAttribute(attrName, attribute);
    if (!found)
    {
        env->ReleaseStringUTFChars(jAttrName, attrName);
        throwInvalidArgsException(env, SIMULATOR_INVALID_PARAM, "Attribute does not exist!");
        return nullptr;
    }

    env->ReleaseStringUTFChars(jAttrName, attrName);

    // Create a object of ResourceAttribute java class
    JResourceAttributeConverter converter(attribute);
    return converter.toJava(env);
}
JNIEXPORT jobject JNICALL
Java_org_oic_simulator_SimulatorResourceModel_getAttributes
(JNIEnv *env, jobject thiz)
{
    SimulatorResourceModel resourceModel;
    bool result = JSimulatorResourceModel::getResourceModel(env, thiz, resourceModel);
    if (!result)
    {
        throwSimulatorException(env, SIMULATOR_BAD_OBJECT, "Resource model not found!");
        return nullptr;
    }

    map<string, SimulatorResourceModel::Attribute> attributesMap = resourceModel.getAttributes();

    // Create Java HashMap object
    jobject jHashMap = NULL;
    jHashMap = createHashMap(env);
    if (!jHashMap)
    {
        throwSimulatorException(env, SIMULATOR_ERROR, "Java map creation failed!");
        return nullptr;
    }

    for (auto & attributeEntry : attributesMap)
    {
        SimulatorResourceModel::Attribute attribute(attributeEntry.second);

        // Create a object of ResourceAttribute java class
        JResourceAttributeConverter converter(attribute);
        jobject jAttribute = converter.toJava(env);

        // Add an entry with attribute.first and javaSimualatorResourceAttribute to the HashMap
        jstring jAttrName = env->NewStringUTF((attributeEntry.first).c_str());
        addEntryToHashMap(env, jHashMap, static_cast<jobject>(jAttrName), jAttribute);
        env->DeleteLocalRef(jAttrName);
    }

    return jHashMap;
}
                std::string operator ()(const SimulatorResourceModel &value)
                {
                    std::ostringstream out;
                    out << "{ ";
                    for (auto &element : value.getAttributeValues())
                    {
                        out << "\"" << element.first << "\" : ";

                        ValueVisitor visitor;
                        out << boost::apply_visitor(visitor, element.second);

                        out << ", ";
                    }
                    out << "}";
                    return out.str();
                }
jobject simulatorResourceModelToJava(JNIEnv *env, SimulatorResourceModel &resModel)
{
    jobject attributesMap = createHashMap(env);
    jobject propertiesMap = createHashMap(env);
    if (!attributesMap || !propertiesMap)
        return nullptr;

    for (auto &attributeEntry : resModel.getAttributes())
    {
        jstring jAttrName = env->NewStringUTF((attributeEntry.first).c_str());
        jobject jAttributeValue = JniAttributeValue::toJava(env, attributeEntry.second);
        addEntryToHashMap(env, attributesMap, jAttrName, jAttributeValue);

        jobject jAttributeProperty = JniAttributeProperty::toJava(env, attributeEntry.second.getProperty());
        if (jAttributeProperty)
            addEntryToHashMap(env, propertiesMap, jAttrName, jAttributeProperty);
    }

    static jmethodID simulatorResourceModelCtor = env->GetMethodID(
                gSimulatorClassRefs.simulatorResourceModelCls, "<init>", "(Ljava/util/Map;Ljava/util/Map;)V");

    return env->NewObject(gSimulatorClassRefs.simulatorResourceModelCls,
                          simulatorResourceModelCtor, attributesMap, propertiesMap);
}
std::shared_ptr<SimulatorResource> SimulatorResourceFactory::buildResource(
    const std::shared_ptr<RAML::RamlResource> &ramlResource)
{
    // Build resource request and respone model schema
    RequestModelBuilder requestModelBuilder;
    std::unordered_map<std::string, RequestModelSP> requestModels =
        requestModelBuilder.build(ramlResource);

    // Build SimulatorResourceModel from "GET" response schema
    if (requestModels.end() == requestModels.find("GET"))
    {
        OIC_LOG(ERROR, TAG, "Resource's RAML does not have GET request model!");
        return nullptr;
    }

    RequestModelSP getRequestModel = requestModels["GET"];
    ResponseModelSP getResponseModel = getRequestModel->getResponseModel(200);
    if (!getResponseModel)
    {
        OIC_LOG(ERROR, TAG, "Resource's RAML does not have response for GET request!");
        return nullptr;
    }

    std::shared_ptr<SimulatorResourceModelSchema> responseSchema =
        getResponseModel->getSchema();
    if (!responseSchema)
    {
        OIC_LOG(ERROR, TAG, "Failed to get schema from response model!");
        return nullptr;
    }

    SimulatorResourceModel resourceModel = responseSchema->buildResourceModel();

    // Remove the common properties from  resource Model
    std::string resourceURI = ramlResource->getResourceUri();
    std::string resourceName = ramlResource->getDisplayName();
    std::string resourceType;

    // Extracting resource type.
    if (resourceModel.contains("rt"))
    {
        resourceType = resourceModel.get<std::string>("rt");
        resourceModel.remove("rt");
    }
    else if (resourceModel.contains("resourceType"))
    {
        resourceType = resourceModel.get<std::string>("resourceType");
        resourceModel.remove("resourceType");
    }

    // Construct resource type from uri
    if(resourceType.empty())
    {
        std::ostringstream rtString;
        rtString << "oic.r.";

        size_t pos = resourceURI.rfind("/");
        if (pos == std::string::npos)
            pos = -1;

        std::string rtName = resourceURI.substr(pos+1);
        std::transform(rtName.begin(), rtName.end(), rtName.begin(), ::tolower);
        rtString << rtName;
        resourceType = rtString.str();
    }

    // Extracting interface type.
    std::vector<std::string> interfaceTypes;
    if (resourceModel.contains("if"))
    {
        SimulatorResourceModel::TypeInfo typeInfo = resourceModel.getType("if");
        if(AttributeValueType::STRING == typeInfo.type())
        {
            interfaceTypes.push_back(resourceModel.get<std::string>("if"));
        }
        else if(AttributeValueType::VECTOR == typeInfo.type()
            && AttributeValueType::STRING == typeInfo.baseType()
            && typeInfo.depth() == 1)
        {
            interfaceTypes = resourceModel.get<std::vector<std::string>>("if");
            if (interfaceTypes.size() > 1)
                interfaceTypes.erase(interfaceTypes.begin()+1, interfaceTypes.end());
        }

        resourceModel.remove("if");
    }

    for (auto &requestModel : requestModels)
    {
        if (requestModel.second)
        {
            addInterfaceFromQueryParameter((requestModel.second)->getQueryParams("if"),
                interfaceTypes);
        }
    }

    // Remove properties which are not part of resource representation
    resourceModel.remove("p");
    resourceModel.remove("n");
    resourceModel.remove("id");

    // Create simple/collection resource
    std::shared_ptr<SimulatorResource> simResource;
    if (resourceModel.contains("links"))
    {
        std::shared_ptr<SimulatorCollectionResourceImpl> collectionRes(
            new SimulatorCollectionResourceImpl());

        collectionRes->setName(resourceName);
        collectionRes->setResourceType(resourceType);
        if (interfaceTypes.size() > 0)
            collectionRes->setInterface(interfaceTypes);
        collectionRes->setURI(ResourceURIFactory::getInstance()->makeUniqueURI(resourceURI));

        // Set the resource model and its schema to simulated resource
        collectionRes->setResourceModel(resourceModel);
        collectionRes->setResourceModelSchema(responseSchema);
        collectionRes->setRequestModel(requestModels);

        simResource = collectionRes;
    }
    else
    {
        std::shared_ptr<SimulatorSingleResourceImpl> singleRes(
            new SimulatorSingleResourceImpl());

        singleRes->setName(resourceName);
        singleRes->setResourceType(resourceType);
        if (interfaceTypes.size() > 0)
            singleRes->setInterface(interfaceTypes);
        singleRes->setURI(ResourceURIFactory::getInstance()->makeUniqueURI(resourceURI));

        // Set the resource model and its schema to simulated resource
        singleRes->setResourceModel(resourceModel);
        singleRes->setResourceModelSchema(responseSchema);
        singleRes->setRequestModel(requestModels);

        simResource = singleRes;
    }

    return simResource;
}
std::shared_ptr<SimulatorResource> SimulatorResourceFactory::buildResource(
    std::shared_ptr<RAML::RamlResource> ramlResource)
{
    std::string name;
    std::string uri;
    std::string resourceType, rt;
    std::vector<std::string> interfaceType, ifType;

    name = ramlResource->getDisplayName();
    uri = ramlResource->getResourceUri();
    std::map<RAML::ActionType, RAML::ActionPtr> actionType = ramlResource->getActions();

    RAML::RequestResponseBodyPtr successResponseBody = getRAMLResponseBody(
                ramlResource, RAML::ActionType::GET, "200");
    RAML::RequestResponseBodyPtr putErrorResponseBody = getRAMLResponseBody(
                ramlResource, RAML::ActionType::PUT, "403");
    RAML::RequestResponseBodyPtr postErrorResponseBody = getRAMLResponseBody(
                ramlResource, RAML::ActionType::POST, "403");

    SimulatorResourceModel successResponseModel = buildModelFromResponseBody(
                successResponseBody, resourceType, interfaceType);
    SimulatorResourceModel putErrorResponseModel = buildModelFromResponseBody(
                putErrorResponseBody, rt, ifType);
    SimulatorResourceModel postErrorResponseModel = buildModelFromResponseBody(
                postErrorResponseBody, rt, ifType);

    // Create simple/collection resource
    std::shared_ptr<SimulatorResource> simResource;
    if (successResponseModel.containsAttribute("links"))
    {
        try
        {
            std::shared_ptr<SimulatorCollectionResourceImpl> collectionRes(
                new SimulatorCollectionResourceImpl());

            collectionRes->setName(name);
            collectionRes->setResourceType(resourceType);
            collectionRes->setInterface(interfaceType);
            collectionRes->setURI(ResourceURIFactory::getInstance()->constructURI(uri));
            collectionRes->setActionType(actionType);

            collectionRes->setResourceModel(successResponseModel);
            simResource = std::dynamic_pointer_cast<SimulatorResource>(collectionRes);
        }
        catch (InvalidArgsException &e) {}
    }
    else
    {
        try
        {
            std::shared_ptr<SimulatorSingleResourceImpl> singleRes(
                new SimulatorSingleResourceImpl());

            singleRes->setName(name);
            singleRes->setResourceType(resourceType);
            singleRes->setInterface(interfaceType);
            singleRes->setURI(ResourceURIFactory::getInstance()->constructURI(uri));
            singleRes->setActionType(actionType);

            singleRes->setResourceModel(successResponseModel);
            singleRes->setPutErrorResponseModel(putErrorResponseModel);
            singleRes->setPostErrorResponseModel(postErrorResponseModel);

            simResource = std::dynamic_pointer_cast<SimulatorResource>(singleRes);
        }
        catch (InvalidArgsException &e) {}
    }

    return simResource;
}
SimulatorResourceModel SimulatorResourceFactory::buildModelFromResponseBody(
    RAML::RequestResponseBodyPtr responseBody, std::string &resourceType,
    std::vector<std::string> &interfaceType)
{
    SimulatorResourceModel resModel;

    if (!responseBody)
        return resModel;

    // Iterate throgh all resource property and extract information needed for simulating resource.
    RAML::JsonSchemaPtr resourceProperties = responseBody->getSchema()->getProperties();


    for ( auto &propertyElement : resourceProperties->getProperties())
    {
        if (!propertyElement.second)
            continue;

        std::string propName = propertyElement.second->getName();

        // Resource type
        if ("rt" == propName || "resourceType" == propName)
        {
            resourceType = propertyElement.second->getValueString();
            continue;
        }

        // Interface type
        if ("if" == propName)
        {
            if ("string" == propertyElement.second->getType())
            {
                interfaceType.push_back(propertyElement.second->getValueString());
            }
            else if ("array" == propertyElement.second->getType())
            {
                for (auto &item : propertyElement.second->getItems())
                {
                    if ("string" == item->getType())
                    {
                        interfaceType = item->getAllowedValuesString();
                        break;
                    }
                }
            }
            continue;
        }

        // Other Standard properties which should not be part of resource model
        if ("p" == propName || "n" == propName || "id" == propName)
        {
            continue;
        }

        // Add the attribute to resource model
        if ("array" == propertyElement.second->getType())
        {
            std::vector<SimulatorResourceModel> arrayResModel;
            for ( auto &propertyItem : propertyElement.second->getItems())
            {
                arrayResModel.push_back(buildResourceModel(propertyItem));
            }
            resModel.add(propName, arrayResModel);
        }
        else
        {
            resModel.add(buildAttribute(propertyElement.second));
        }
    }

    if ("array" == resourceProperties->getType())
    {
        std::vector<SimulatorResourceModel> arrayResModel;
        for ( auto &propertyItem : resourceProperties->getItems())
        {
            arrayResModel.push_back(buildResourceModel(propertyItem));
        }
        resModel.add("links", arrayResModel);
    }

    return resModel;
}
bool simulatorResourceModelToCpp(JNIEnv *env, jobject jResModel, SimulatorResourceModel &resModel)
{
    if (!jResModel)
        return false;

    static jfieldID valuesFID = env->GetFieldID(gSimulatorClassRefs.simulatorResourceModelCls,
                                "mValues", "Ljava/util/Map;");
    static jfieldID propertiesFID = env->GetFieldID(gSimulatorClassRefs.simulatorResourceModelCls,
                                    "mProperties", "Ljava/util/Map;");
    static jmethodID entrySetMID = env->GetMethodID(gSimulatorClassRefs.mapCls, "entrySet",
                                   "()Ljava/util/Set;");
    static jmethodID iteratorMID = env->GetMethodID(gSimulatorClassRefs.setCls, "iterator",
                                   "()Ljava/util/Iterator;");
    static jmethodID hasNextMID = env->GetMethodID(gSimulatorClassRefs.iteratorCls, "hasNext",
                                  "()Z");
    static jmethodID nextMID = env->GetMethodID(gSimulatorClassRefs.iteratorCls, "next",
                               "()Ljava/lang/Object;");
    static jmethodID getKeyMID = env->GetMethodID(gSimulatorClassRefs.mapEntryCls, "getKey",
                                 "()Ljava/lang/Object;");
    static jmethodID getValueMID = env->GetMethodID(gSimulatorClassRefs.mapEntryCls, "getValue",
                                   "()Ljava/lang/Object;");

    jobject jValues = env->GetObjectField(jResModel, valuesFID);
    jobject jProperties = env->GetObjectField(jResModel, propertiesFID);

    if (jValues)
    {
        jobject entrySet = env->CallObjectMethod(jValues, entrySetMID);
        jobject iterator = env->CallObjectMethod(entrySet, iteratorMID);
        if (entrySet && iterator)
        {
            while (env->CallBooleanMethod(iterator, hasNextMID))
            {
                jobject entry = env->CallObjectMethod(iterator, nextMID);
                jstring key = (jstring) env->CallObjectMethod(entry, getKeyMID);
                jobject value = env->CallObjectMethod(entry, getValueMID);
                resModel.add(JniString(env, key).get(), JniAttributeValue::toCpp(env, value));

                env->DeleteLocalRef(entry);
                env->DeleteLocalRef(key);
                env->DeleteLocalRef(value);
            }
        }
    }

    if (jProperties)
    {
        jobject entrySet = env->CallObjectMethod(jProperties, entrySetMID);
        jobject iterator = env->CallObjectMethod(entrySet, iteratorMID);
        if (entrySet && iterator)
        {
            while (env->CallBooleanMethod(iterator, hasNextMID))
            {
                jobject entry = env->CallObjectMethod(iterator, nextMID);
                jstring key = (jstring) env->CallObjectMethod(entry, getKeyMID);
                jobject value = env->CallObjectMethod(entry, getValueMID);
                resModel.setAttributeProperty(JniString(env, key).get(),
                                              JniAttributeProperty::toCpp(env, value));

                env->DeleteLocalRef(entry);
                env->DeleteLocalRef(key);
                env->DeleteLocalRef(value);
            }
        }
    }

    return true;
}