/*****************************************************************************
 *
 * Implementation of InstanceProvider enumerateInstances method.
 *
 *****************************************************************************/
void InteropProvider::enumerateInstances(
    const OperationContext & context,
    const CIMObjectPath & ref,
    const Boolean includeQualifiers,
    const Boolean includeClassOrigin,
    const CIMPropertyList& propertyList,
    InstanceResponseHandler & handler)
{
    PEG_METHOD_ENTER(TRC_CONTROLPROVIDER,
        "InteropProvider::enumerateInstances()");

    initProvider();

    // test for legal namespace for this provider. Exception if not
    //namespaceSupported(ref);
    // NOTE: Above is commented out because the routing tables will always
    // do the right thing and that's the only way requests get here.
    handler.processing();

    // Call the internal enumerateInstances to generate instances of defined
    // class.  This expects the instances to be returned complete including
    // complete path.
    handler.deliver(localEnumerateInstances(context, ref, propertyList));
    handler.complete();
    PEG_METHOD_EXIT();
}
/*****************************************************************************
 *
 * Implementation of InstanceProvider enumerateInstanceNames method
 *
 *****************************************************************************/
void InteropProvider::enumerateInstanceNames(
    const OperationContext & context,
    const CIMObjectPath & classReference,
    ObjectPathResponseHandler & handler)
{
    PEG_METHOD_ENTER(TRC_CONTROLPROVIDER,
        "InteropProvider::enumerateInstanceNames()");

    initProvider();

    PEG_TRACE((TRC_CONTROLPROVIDER, Tracer::LEVEL4,
        "%s enumerateInstanceNames. classReference= %s",
        thisProvider,
        (const char *) classReference.toString().getCString()));

    // test for legal namespace for this provider. Exception if not
    // namespaceSupported(classReference);
    // NOTE: Above is commented out because the routing tables will always
    // do the right thing and that's the only way requests get here.

    // begin processing the request
    handler.processing();

    // Utilize the local enumeration method to retrieve the instances and
    // extract the instance names.
    Array<CIMInstance> instances = localEnumerateInstances(
        context,
        classReference,
        CIMPropertyList());

    for (Uint32 i = 0 ; i < instances.size() ; i++)
    {
        handler.deliver(instances[i].getPath());
    }

    handler.complete();
    PEG_METHOD_EXIT();
}
//
// Local version of the references operation. It validates the input
// parameters, setting the origin and target property values if not set
// already, and then performs an enumeration on the association class. It then
// filters the results of that enumeration to see if one of the reference
// properties matches the objectName parameter passed into the method. If so,
// then it is added to the array of association instances to be returned.
//
Array<CIMInstance> InteropProvider::localReferences(
    const OperationContext & context,
    const CIMObjectPath & objectName,
    const CIMName & assocClass,
    String & originProperty,
    String & targetProperty,
    const CIMPropertyList & propertyList,
    const CIMName & targetClass)
{
    PEG_METHOD_ENTER(TRC_CONTROLPROVIDER,
        "InteropProvider::localReferences()");

    Array<CIMInstance> instances;
    CIMName originClass = objectName.getClassName();

    Array<CIMName> targetSubclasses;
    CIMNamespaceName lastTargetNamespace;
    CIMNamespaceName originNamespace(objectName.getNameSpace());

    // Check that the association traversal request is valid
    if (validAssocClassForObject(
        context, 
        assocClass, 
        objectName,
        originNamespace, 
        originProperty, 
        targetProperty))
    {
        // retrieve all of the association class instances
        Array<CIMInstance> localInstances = localEnumerateInstances(context,
            CIMObjectPath(hostName, originNamespace,
                assocClass));
        // Filter the association class instances based on the origin instance
        // and other input parameters.
        for(Uint32 i = 0, n = localInstances.size(); i < n; ++i)
        {
            CIMInstance & currentInstance = localInstances[i];
            CIMObjectPath originPath = getRequiredValue<CIMObjectPath>(
                currentInstance, originProperty);
            originPath.setNameSpace(objectName.getNameSpace());
            originPath.setHost(objectName.getHost());
            // Only include instances where the origin instance is present in
            // the association.
            if(originPath.identical(objectName))
            {
                if(!targetClass.isNull())
                {
                    // Have to check if the target reference is of the
                    // targetClass type. We first must determine all the
                    // possible subclasses of the targetClass in the target
                    // namespace.
                    CIMObjectPath targetPath = getRequiredValue<CIMObjectPath>(
                        currentInstance, targetProperty);

                    CIMNamespaceName targetNamespace(
                        targetPath.getNameSpace());
                    if(targetNamespace.isNull())
                    {
                        targetNamespace = originNamespace;
                        targetPath.setNameSpace(targetNamespace);
                    }
                    if(targetNamespace != lastTargetNamespace)
                    {
                        try
                        {
                            targetSubclasses = repository->enumerateClassNames(
                                targetNamespace, targetClass, true);
                        }
                        catch(...)
                        {
                            // If an exception was thrown during enumeration,
                            // then the base class didn't exist in the
                            // namespace, so the target instance retrieved
                            // must not match the targetClass parameter.
                            continue;
                        }
                        targetSubclasses.append(targetClass);
                        lastTargetNamespace = targetNamespace;
                    }

                    // Try to find the targetPath's class in the search space
                    CIMName targetPathClass = targetPath.getClassName();
                    for(Uint32 j = 0, m = targetSubclasses.size(); j < m; ++j)
                    {
                        if(targetPathClass == targetSubclasses[j])
                        {
                            instances.append(currentInstance);
                            break;
                        }
                    }
                }
                else
                {
                    instances.append(currentInstance);
                }
            }
        }
    }

    PEG_METHOD_EXIT();
    return instances;
}
//
// Local version of getInstance to be used by other functions in the the
// provider. Returns a single instance. Note that it always returns an
// instance. If none was found, it is uninialitized.
//
CIMInstance InteropProvider::localGetInstance(
    const OperationContext & context,
    const CIMObjectPath & instanceName,
    const CIMPropertyList & propertyList)
{
    PEG_METHOD_ENTER(TRC_CONTROLPROVIDER, "InteropProvider::localGetInstance");

    PEG_TRACE((TRC_CONTROLPROVIDER, Tracer::LEVEL4,
        "%s getInstance. instanceName= %s , PropertyList= %s",
        thisProvider,
        (const char *)instanceName.toString().getCString(),
        (const char *)propertyListToString(propertyList).getCString()));

    // Test if we're looking for something outside of our namespace. This will
    // happen during associators calls from PG_RegisteredProfile instances
    // through the PG_ElementConformsToProfile association
    CIMNamespaceName opNamespace = instanceName.getNameSpace();
    CIMName opClass = instanceName.getClassName();
    if(opNamespace != PEGASUS_NAMESPACENAME_INTEROP &&
        opClass != PEGASUS_CLASSNAME_PG_ELEMENTCONFORMSTOPROFILE
        // Get CIM_IndicationService instance from IndicationService.
#ifdef PEGASUS_ENABLE_DMTF_INDICATION_PROFILE_SUPPORT
        || opClass == PEGASUS_CLASSNAME_CIM_INDICATIONSERVICE
#endif
        )
    {
        AutoMutex mut(interopMut);
        CIMInstance gotInstance = cimomHandle.getInstance(
                                         context,
                                         opNamespace,
                                         instanceName, 
                                         false, 
                                         false, 
                                         false, 
                                         propertyList);
        PEG_METHOD_EXIT();
        return gotInstance;
    }

    // Create reference from host, namespace, class components of
    // instance name
    CIMObjectPath ref;
    ref.setHost(instanceName.getHost());
    ref.setClassName(opClass);
    ref.setNameSpace(opNamespace);

    // Enumerate instances for this class. Returns all instances
    // Note that this returns paths setup and instances already
    // filtered per the input criteria.
    Array<CIMInstance> instances =  localEnumerateInstances(
        context,
        ref,
        propertyList);

    // deliver a single instance if found.
    CIMInstance retInstance;

    bool found = false;
    for(Uint32 i = 0, n = instances.size(); i < n; i++)
    {
        CIMObjectPath currentInstRef = instances[i].getPath();
        currentInstRef.setHost(instanceName.getHost());
        currentInstRef.setNameSpace(instanceName.getNameSpace());
        if(instanceName == currentInstRef)
        {
            retInstance = instances[i];
            found = true;
            break;
        }
    }

    if(!found)
    {
      cout << "Coule not find instance: " << instanceName.toString() << endl;
    }
    PEG_METHOD_EXIT();
    return retInstance;
}
Array<CIMInstance> InteropProvider::getReferencedInstances(
    const Array<CIMInstance> &refs,
    const String &targetRole,
    const OperationContext & context,
    const CIMPropertyList & propertyList)
{
    PEG_METHOD_ENTER(TRC_CONTROLPROVIDER,
                     "InteropProvider::getReferencedObjects");

    Array<CIMInstance> referencedInstances;
    Array<CIMInstance> classInstances;
    CIMName prevClassName;

    ConstArrayIterator<CIMInstance> refsIter(refs);
    for(Uint32 i = 0; i < refsIter.size(); i++)
    {
        CIMInstance thisRef = refsIter[i];
        CIMObjectPath thisTarget = getRequiredValue<CIMObjectPath>(
                                       thisRef,
                                       targetRole);

        // Test if we're looking for something outside of our namespace. This
        // will happen during associators calls from PG_RegisteredProfile
        // instances through the PG_ElementConformsToProfile association
        CIMNamespaceName opNamespace = thisTarget.getNameSpace();
        CIMName opClass = thisTarget.getClassName();

        if((opNamespace != PEGASUS_NAMESPACENAME_INTEROP &&
                opClass != PEGASUS_CLASSNAME_PG_ELEMENTCONFORMSTOPROFILE)
                // Get CIM_IndicationService instance from IndicationService.
#ifdef PEGASUS_ENABLE_DMTF_INDICATION_PROFILE_SUPPORT
                || opClass == PEGASUS_CLASSNAME_CIM_INDICATIONSERVICE
#endif
          )
        {
            AutoMutex mut(interopMut);
            CIMInstance gotInstance = cimomHandle.getInstance(
                                          context,
                                          opNamespace,
                                          thisTarget,
                                          false,
                                          false,
                                          false,
                                          propertyList);
            referencedInstances.append(gotInstance);
            continue;
        }

        TARGET_CLASS classEnum  = translateClassInput(opClass);
        CIMInstance retInstance;
        switch(classEnum)
        {
        case PG_SOFTWAREIDENTITY:
        {
            CIMInstance retInstance =
                getSoftwareIdentityInstance(thisTarget);
            normalizeInstance(
                retInstance, thisTarget, false, false, propertyList);
            retInstance.setPath(thisTarget);
            referencedInstances.append(retInstance);
        }
        break;
        case PG_NAMESPACE:
        {
            CIMInstance retInstance = getNameSpaceInstance(thisTarget);
            normalizeInstance(
                retInstance, thisTarget, false, false, propertyList);
            retInstance.setPath(thisTarget);
            referencedInstances.append(retInstance);
        }
        break;
        default:
        {
            if( opClass != prevClassName )
            {
                CIMObjectPath ref;
                ref.setHost(thisTarget.getHost());
                ref.setClassName(thisTarget.getClassName());
                ref.setNameSpace(thisTarget.getNameSpace());
                classInstances = localEnumerateInstances(
                                     context,
                                     ref,
                                     propertyList);
                ArrayIterator<CIMInstance> instsIter(classInstances);
                for(Uint32 n = 0; n < instsIter.size(); n++)
                {
                    CIMObjectPath tmpInst = instsIter[n].getPath();
                    tmpInst.setHost(thisTarget.getHost());
                    tmpInst.setNameSpace(thisTarget.getNameSpace());
                    instsIter[n].setPath(tmpInst);
                }
                prevClassName = opClass;
            }
            ConstArrayIterator<CIMInstance> instsConstIter(classInstances);
            for(Uint32 j = 0; j < instsConstIter.size(); j++)
            {
                if(thisTarget == instsConstIter[j].getPath())
                {
                    referencedInstances.append(instsConstIter[j]);
                    break;
                }
            }
        }
        break;
        }
    }
    PEG_METHOD_EXIT();
    return referencedInstances;
}
//
// Local version of getInstance to be used by other functions in the the
// provider. Returns a single instance. Note that it always returns an
// instance. If none was found, it is uninialitized.
//
CIMInstance InteropProvider::localGetInstance(
    const OperationContext & context,
    const CIMObjectPath & instanceName,
    const CIMPropertyList & propertyList)
{
    PEG_METHOD_ENTER(TRC_CONTROLPROVIDER, "InteropProvider::localGetInstance");

    PEG_TRACE((TRC_CONTROLPROVIDER, Tracer::LEVEL4,
               "%s getInstance. instanceName= %s , PropertyList= %s",
               thisProvider,
               (const char *)instanceName.toString().getCString(),
               (const char *)propertyList.toString().getCString()));

    // Test if we're looking for something outside of our namespace. This will
    // happen during associators calls from PG_RegisteredProfile instances
    // through the PG_ElementConformsToProfile association
    CIMNamespaceName opNamespace = instanceName.getNameSpace();
    CIMName opClass = instanceName.getClassName();
    if((opNamespace != PEGASUS_NAMESPACENAME_INTEROP &&
            opClass != PEGASUS_CLASSNAME_PG_ELEMENTCONFORMSTOPROFILE)
            // Get CIM_IndicationService instance from IndicationService.
#ifdef PEGASUS_ENABLE_DMTF_INDICATION_PROFILE_SUPPORT
            || opClass == PEGASUS_CLASSNAME_CIM_INDICATIONSERVICE
#endif
      )
    {
        AutoMutex mut(interopMut);
        CIMInstance gotInstance = cimomHandle.getInstance(
                                      context,
                                      opNamespace,
                                      instanceName,
                                      false,
                                      false,
                                      false,
                                      propertyList);
        PEG_METHOD_EXIT();
        return gotInstance;
    }

    TARGET_CLASS classEnum  = translateClassInput(opClass);
    CIMInstance retInstance;
    switch(classEnum)
    {
    case PG_SOFTWAREIDENTITY:
    {
        retInstance = getSoftwareIdentityInstance(instanceName);
        normalizeInstance(
            retInstance, instanceName, false, false, propertyList);
    }
    break;
    case PG_NAMESPACE:
    {
        retInstance = getNameSpaceInstance(instanceName);
        normalizeInstance(
            retInstance, instanceName, false, false, propertyList);
    }
    break;
    // ATTN: Implement getIntstance for all other classes. Currently
    // this method calls localEnumerateInstances() to select instance
    // which is too expensive.
    default:
    {
        // Create reference from host, namespace, class components of
        // instance name
        CIMObjectPath ref;
        ref.setHost(instanceName.getHost());
        ref.setClassName(opClass);
        ref.setNameSpace(opNamespace);

        // Enumerate instances for this class. Returns all instances
        // Note that this returns paths setup and instances already
        // filtered per the input criteria.
        Array<CIMInstance> instances =  localEnumerateInstances(
                                            context,
                                            ref,
                                            propertyList);
        ConstArrayIterator<CIMInstance> instancesIter(instances);

        // deliver a single instance if found.
        bool found = false;
        for(Uint32 i = 0; i < instancesIter.size(); i++)
        {
            CIMObjectPath currentInstRef = instancesIter[i].getPath();
            currentInstRef.setHost(instanceName.getHost());
            currentInstRef.setNameSpace(instanceName.getNameSpace());
            if(instanceName == currentInstRef)
            {
                retInstance = instancesIter[i];
                found = true;
                break;
            }
        }

        if (!found)
        {
            PEG_METHOD_EXIT();
            throw CIMObjectNotFoundException(instanceName.toString());
        }
    }
    }

    PEG_METHOD_EXIT();
    return retInstance;
}