/*******************************************************************************
* Copyright (C) 2003-2004 Vintela, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*  - Redistributions of source code must retain the above copyright notice,
*    this list of conditions and the following disclaimer.
*
*  - Redistributions in binary form must reproduce the above copyright notice,
*    this list of conditions and the following disclaimer in the documentation
*    and/or other materials provided with the distribution.
*
*  - Neither the name of Vintela, Inc. nor the names of its
*    contributors may be used to endorse or promote products derived from this
*    software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Vintela, Inc. OR THE CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/

/**
 * @author Dan Nuffer
 */


#include "OW_config.h"

#include "OW_CppProviderIncludes.hpp"
#include "OW_WQLSelectStatement.hpp"

using namespace OpenWBEM;
using namespace WBEMFlags;

// anonymous namespace to prevent symbol conflicts
namespace
{

const String COMPONENT_NAME("ow.test.IndicationProviderTest1");

// This is an example/test of a simple instance/indication provider.  It
// returns non-zero from mustPoll, so the CIMOM will then "poll" the
// provider by calling enumInstances.  The number of seconds between
// polls is indicated by the return value of mustPoll.  The CIMOM
// will generate life-cycle indications (CIM_InstCreation,
// CIM_InstModification, CIM_InstDeletion) for any changes in the set of
// instances returned by enumInstances.

class IndicationProviderTest1 : public CppIndicationProviderIFC, public CppInstanceProviderIFC
{
public:
	// Indication provider methods - Only have to implement getIndicationProviderInfo() and mustPoll()
	// The default implementation of the others suits us fine.
	virtual int mustPoll(const ProviderEnvironmentIFCRef &env, const WQLSelectStatement &, const String &, const String&, const StringArray&)
	{
		OW_LOG_DEBUG(env->getLogger(COMPONENT_NAME), "IndicationProviderTest1::mustPoll");
		// going to be lazy and make the cimom poll
		return 1;
	}

	/**
	 * A provider should override this method to report which classes in
	 * which namespaces it instruments.
	 * It should insert an entry for each class it is responsible for.
	 *  The entry consists of the class name and an optional list of namespaces.
	 *  If the namespace list is empty, all namespaces are implied.
	 * If the method does nothing, then the provider's class must have a
	 * provider qualifier that identifies the provider.  This old behavior is
	 * deprecated and will be removed sometime in the future.  This method
	 * has a default implementation that does nothing, to allow old providers
	 * to be migrated forward with little or no change, but once the old
	 * provider location method is removed, this member function will be pure
	 * virtual.
	 */
	virtual void getIndicationProviderInfo(IndicationProviderInfo& info)
	{
		// Add the class(es) we are monitoring for lifecycle indications. We only need to add the most derived classes to this array.
		const char* theMonitoredClasses[] =
			{
				"OW_IndicationProviderTest1",
				0
			};

		// all the life-cycle indications that may be generated by this provider. We have to add all the base classes to this array.
		const char* instanceLifeCycleIndicationClassNames[] =
			{
				"CIM_InstCreation",
				"CIM_InstModification",
				"CIM_InstDeletion",
				"CIM_InstIndication",
				"CIM_Indication",
				0
			};

		for (const char** pIndicationClassName = instanceLifeCycleIndicationClassNames;
			  *pIndicationClassName != 0;
			  ++pIndicationClassName)
		{
			const char* indicationClassName = *pIndicationClassName;
			IndicationProviderInfoEntry e(indicationClassName);
			for (const char** pClassName = theMonitoredClasses;
				  *pClassName != 0;
				  ++pClassName)
			{
				const char* className = *pClassName;
				e.classes.push_back(className);
			}
			info.addInstrumentedClass(e);

		}
	}

	// These are the indication provider methods.
	virtual void getInstanceProviderInfo(InstanceProviderInfo& info)
	{
		// The class we are instrumenting
		info.addInstrumentedClass("OW_IndicationProviderTest1");
	}

	virtual void deleteInstance(const ProviderEnvironmentIFCRef &, const String &, const CIMObjectPath &)
	{
		OW_THROWCIMMSG(CIMException::FAILED, "Delete not supported");
	}

	virtual CIMObjectPath createInstance(const ProviderEnvironmentIFCRef &, const String &, const CIMInstance &)
	{
		OW_THROWCIMMSG(CIMException::FAILED, "Create not supported");
	}
	
	virtual CIMInstance getInstance(
		const ProviderEnvironmentIFCRef &env,
		const String &ns,
		const CIMObjectPath &instanceName,
		ELocalOnlyFlag localOnly,
		EIncludeQualifiersFlag includeQualifiers,
		EIncludeClassOriginFlag includeClassOrigin,
		const StringArray *propertyList,
		const CIMClass &cimClass)
	{
		OW_LOG_DEBUG(env->getLogger(COMPONENT_NAME), "IndicationProviderTest1::getInstance");
		Int32 id = 0;
		try
		{
			id = instanceName.getKeyT("DeviceID").getValueT().toString().toInt32();
		}
		catch (Exception& e)
		{
			OW_THROWCIMMSG_SUBEX(CIMException::NOT_FOUND, "Invalid DeviceID property", e);
		}

		if (id < 0 || UInt32(id) >= m_insts.size())
		{
			OW_THROWCIMMSG(CIMException::NOT_FOUND, Format("Invalid DeviceID property: %1", id).c_str());
		}
		return m_insts[id].clone(localOnly, includeQualifiers, includeClassOrigin, propertyList);
	}

	virtual void enumInstances(
		const ProviderEnvironmentIFCRef &env,
		const String &ns,
		const String &className,
		CIMInstanceResultHandlerIFC &result,
		ELocalOnlyFlag localOnly,
		EDeepFlag deep,
		EIncludeQualifiersFlag includeQualifiers,
		EIncludeClassOriginFlag includeClassOrigin,
		const StringArray *propertyList,
		const CIMClass &requestedClass,
		const CIMClass &cimClass)
	{
		OW_LOG_DEBUG(env->getLogger(COMPONENT_NAME), "IndicationProviderTest1::enumInstances");
		// we will simulate changing external conditions by calling updateInstances() every time enumInstances is called.
		// the changes will cause the cimom to send lifecycle indications.
		updateInstances(cimClass);
		for (size_t i = 0; i < m_insts.size(); ++i)
		{
			result.handle(m_insts[i].clone(localOnly, deep, includeQualifiers, includeClassOrigin, propertyList, requestedClass, cimClass));
		}
	}
	
	virtual void enumInstanceNames(
		const ProviderEnvironmentIFCRef &env,
		const String &ns,
		const String &className,
		CIMObjectPathResultHandlerIFC &result,
		const CIMClass &cimClass)
	{
		OW_LOG_DEBUG(env->getLogger(COMPONENT_NAME), "IndicationProviderTest1::enumInstanceNames");
		// we will simulate changing external conditions by calling updateInstances() every time enumInstances is called.
		// the changes will cause the cimom to send lifecycle indications.
		updateInstances(cimClass);
		for (size_t i = 0; i < m_insts.size(); ++i)
		{
			result.handle(CIMObjectPath(ns, m_insts[i]));
		}
	}
	
	virtual void modifyInstance(
		const ProviderEnvironmentIFCRef& env,
		const String& ns,
		const CIMInstance& modifiedInstance,
		const CIMInstance& previousInstance,
		EIncludeQualifiersFlag includeQualifiers,
		const StringArray* propertyList,
		const CIMClass& theClass)
	{
		OW_THROWCIMMSG(CIMException::FAILED, "Modify not supported");
	}

private:
	CIMInstanceArray m_insts;

	void updateInstances(const CIMClass &cimClass)
	{
		if (m_insts.size() == 5)
		{
			m_insts.clear();
		}
		else
		{
			// add an instance
			CIMInstance iToAdd(cimClass.newInstance());
			iToAdd.setProperty("SystemCreationClassName", CIMValue("CIM_System"));
			iToAdd.setProperty("SystemName", CIMValue("localhost"));
			iToAdd.setProperty("CreationClassName", CIMValue("OW_IndicationProviderTest1"));
			iToAdd.setProperty("DeviceID", CIMValue(String(UInt32(m_insts.size()))));
			// PowerOnHours is our property that will be modified
			iToAdd.setProperty("PowerOnHours", CIMValue(UInt64(m_insts.size())));
			m_insts.push_back(iToAdd);

			// now modify the first instance's PowerOnHours property
			UInt64 oldPowerOnHours = m_insts[0].getPropertyT("PowerOnHours").getValueT().toUInt64();
			m_insts[0].setProperty("PowerOnHours", CIMValue(UInt64(oldPowerOnHours + 1)));
		}
	}
};


} // end anonymous namespace


OW_PROVIDERFACTORY(IndicationProviderTest1, indicationtest1)


