/*###############################################################################
# Linux Management Providers (LMP), System Memory provider package
# Copyright (C) 2008 Guillaume BOTTEX, ETRI <guillaumebottex@etri.re.kr, guillaumebottex@gmail.com>
#
# This program is being developed under the "OpenDRIM" project.
# The "OpenDRIM" project web page: http://opendrim.sourceforge.net
# The "OpenDRIM" project mailing list: opendrim@googlegroups.com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; version 2
# of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#################################################################################

#################################################################################
# To contributors, please leave your contact information in this section
# AND comment your changes in the source code.
#
# Modified by <Author(s)>, <Affiliation>, <Year>
###############################################################################*/

#include "cmpiOpenDRIM_Memory.h"
#include "OpenDRIM_MemoryAccess.h"

static const CMPIBroker * _broker;

#ifdef CMPI_VER_100
#define SystemMemory_OpenDRIM_MemoryProviderSetInstance SystemMemory_OpenDRIM_MemoryProviderModifyInstance
#endif

int SystemMemory_OpenDRIM_Memory_init(const CMPIBroker* broker);

int SystemMemory_OpenDRIM_Memory_finalize();

/* ---------------------------------------------------------------------------*/
/*                      Instance Provider Interface                           */
/* ---------------------------------------------------------------------------*/

CMPIStatus SystemMemory_OpenDRIM_MemoryProviderCleanup(CMPIInstanceMI * mi, const CMPIContext* ctx, CMPIBoolean terminate) {
	_E_;
	int errorCode = SystemMemory_OpenDRIM_Memory_finalize();
	CMPIStatus rc;
	CMSetStatus(&rc, (CMPIrc) errorCode);
	_L_;
	return rc;
}

CMPIStatus SystemMemory_OpenDRIM_MemoryProviderEnumInstanceNames(CMPIInstanceMI* mi, const CMPIContext* ctx, const CMPIResult* rslt, const CMPIObjectPath* ref) {
	_E_;
	CMPIStatus rc = {CMPI_RC_OK, NULL};
	vector<OpenDRIM_Memory> instances;
	string errorMessage;
	
	int errorCode = SystemMemory_OpenDRIM_Memory_retrieve(_broker, ctx, instances, NULL, errorMessage, "ein");
	if (errorCode != OK) {
		errorMessage = (string) OpenDRIM_Memory_classnames[0] + ": " + errorMessage;
		CMSetStatusWithChars(_broker, &rc, (CMPIrc) errorCode, errorMessage.c_str());
		return rc;
	}
	for (size_t i=0; i < instances.size(); i++) {
		CMPIObjectPath* op = SystemMemory_OpenDRIM_Memory_toCMPIObjectPath(_broker, instances[i]);
		CMReturnObjectPath(rslt, op);
	}
	CMReturnDone(rslt);
	_L_;
	return rc;
}

CMPIStatus SystemMemory_OpenDRIM_MemoryProviderEnumInstances(CMPIInstanceMI* mi, const CMPIContext* ctx, const CMPIResult* rslt, const CMPIObjectPath* ref, const char** properties) {
	_E_;
	CMPIStatus rc = {CMPI_RC_OK, NULL};
	vector<OpenDRIM_Memory> instances;
	string errorMessage;
	
	int errorCode = SystemMemory_OpenDRIM_Memory_retrieve(_broker, ctx, instances, properties, errorMessage, "ei");
	if (errorCode != OK) {
		errorMessage = (string) OpenDRIM_Memory_classnames[0] + ": " + errorMessage;
		CMSetStatusWithChars(_broker, &rc, (CMPIrc) errorCode, errorMessage.c_str());
		return rc;
	}
	for (size_t i=0; i < instances.size(); i++) {
		CMPIInstance* ci = SystemMemory_OpenDRIM_Memory_toCMPIInstance(_broker, instances[i]);
		CMReturnInstance(rslt, ci);
	}
	CMReturnDone(rslt);
	_L_;
	return rc;
}

CMPIStatus SystemMemory_OpenDRIM_MemoryProviderGetInstance(CMPIInstanceMI* mi, const CMPIContext* ctx, const CMPIResult* rslt, const CMPIObjectPath* cop, const char** properties) {
	_E_;
	CMPIStatus rc = {CMPI_RC_OK, NULL};
	OpenDRIM_Memory instance;
	SystemMemory_OpenDRIM_Memory_toCPP(_broker, cop, instance);
	string errorMessage;
	
	int errorCode = SystemMemory_OpenDRIM_Memory_getInstance(_broker, ctx, instance, properties, errorMessage);
	if (errorCode != OK) {
		errorMessage = (string) OpenDRIM_Memory_classnames[0] + ": " + errorMessage;
		CMSetStatusWithChars(_broker, &rc, (CMPIrc) errorCode, errorMessage.c_str());
		return rc;
	}
	CMPIInstance* ci = SystemMemory_OpenDRIM_Memory_toCMPIInstance(_broker, instance);
	CMReturnInstance(rslt, ci);
	CMReturnDone(rslt);
	_L_;
	return rc;
}

CMPIStatus SystemMemory_OpenDRIM_MemoryProviderSetInstance(CMPIInstanceMI* mi, const CMPIContext* ctx, const CMPIResult* rslt, const CMPIObjectPath* cop, const CMPIInstance* ci, const char** properties) {
	_E_;
	CMPIStatus rc = {CMPI_RC_OK, NULL};
	OpenDRIM_Memory newInstance, oldInstance;
	SystemMemory_OpenDRIM_Memory_toCPP(_broker, ci, newInstance);
	SystemMemory_OpenDRIM_Memory_toCPP(_broker, cop, oldInstance);
	string errorMessage;
	
	int errorCode = SystemMemory_OpenDRIM_Memory_getInstance(_broker, ctx, oldInstance, properties, errorMessage);
	if (errorCode != OK) {
		errorMessage = (string) OpenDRIM_Memory_classnames[0] + ": " + errorMessage;
		CMSetStatusWithChars(_broker, &rc, (CMPIrc) errorCode, errorMessage.c_str());
		return rc;
	}
	errorCode = SystemMemory_OpenDRIM_Memory_setInstance(_broker, ctx, newInstance, oldInstance, properties, errorMessage);
	if (errorCode != OK) {
		errorMessage = (string) OpenDRIM_Memory_classnames[0] + ": " + errorMessage;
		CMSetStatusWithChars(_broker, &rc, (CMPIrc) errorCode, errorMessage.c_str());
		return rc;
	}
	CMReturnDone(rslt);
	_L_;
	return rc;
}

CMPIStatus SystemMemory_OpenDRIM_MemoryProviderCreateInstance(CMPIInstanceMI* mi, const CMPIContext* ctx, const CMPIResult* rslt, const CMPIObjectPath* cop, const CMPIInstance* ci) {
	_E_;
	CMPIStatus rc = {CMPI_RC_OK, NULL};
	OpenDRIM_Memory instance;
	SystemMemory_OpenDRIM_Memory_toCPP(_broker, ci, instance);
	string errorMessage;
	
	int errorCode = SystemMemory_OpenDRIM_Memory_getInstance(_broker, ctx, instance, NULL, errorMessage);
	if (errorCode != NOT_FOUND) {
		if (errorCode == OK)
			errorCode = ALREADY_EXISTS;
		errorMessage = (string) OpenDRIM_Memory_classnames[0] + ": " + errorMessage;
		CMSetStatusWithChars(_broker, &rc, (CMPIrc) errorCode, errorMessage.c_str());
		return rc;
	}
	errorCode = SystemMemory_OpenDRIM_Memory_createInstance(_broker, ctx, instance, errorMessage);
	if (errorCode != OK) {
		errorMessage = (string) OpenDRIM_Memory_classnames[0] + ": " + errorMessage;
		CMSetStatusWithChars(_broker, &rc, (CMPIrc) errorCode, errorMessage.c_str());
		return rc;
	}
	errorCode = SystemMemory_OpenDRIM_Memory_getInstance(_broker, ctx, instance, NULL, errorMessage);
	if (errorCode != OK) {
		errorMessage = (string) OpenDRIM_Memory_classnames[0] + ": " + errorMessage;
		CMSetStatusWithChars(_broker, &rc, (CMPIrc) errorCode, errorMessage.c_str());
		return rc;
	}
	CMPIObjectPath* _cop = SystemMemory_OpenDRIM_Memory_toCMPIObjectPath(_broker, instance);
	CMReturnObjectPath(rslt, _cop);
	CMReturnDone(rslt);
	_L_;
	return rc;
}

CMPIStatus SystemMemory_OpenDRIM_MemoryProviderDeleteInstance(CMPIInstanceMI* mi, const CMPIContext* ctx, const CMPIResult* rslt, const CMPIObjectPath* cop) {
	_E_;
	CMPIStatus rc = {CMPI_RC_OK, NULL};
	OpenDRIM_Memory instance;
	SystemMemory_OpenDRIM_Memory_toCPP(_broker, cop, instance);
	string errorMessage;
	
	int errorCode = SystemMemory_OpenDRIM_Memory_getInstance(_broker, ctx, instance, NULL, errorMessage);
	if (errorCode != OK) {
		errorMessage = (string) OpenDRIM_Memory_classnames[0] + ": " + errorMessage;
		CMSetStatusWithChars(_broker, &rc, (CMPIrc) errorCode, errorMessage.c_str());
		return rc;
	}
	errorCode = SystemMemory_OpenDRIM_Memory_deleteInstance(_broker, ctx, instance, errorMessage);
	if (errorCode != OK) {
		errorMessage = (string) OpenDRIM_Memory_classnames[0] + ": " + errorMessage;
		CMSetStatusWithChars(_broker, &rc, (CMPIrc) errorCode, errorMessage.c_str());
		return rc;
	}
	CMReturnDone(rslt);
	_L_;
	return rc;
}

CMPIStatus SystemMemory_OpenDRIM_MemoryProviderExecQuery(CMPIInstanceMI* mi, const CMPIContext* ctx, const CMPIResult* rslt, const CMPIObjectPath* ref, const char* lang, const char* query) {
	_E_;
	CMReturn(CMPI_RC_ERR_NOT_SUPPORTED);
}

/* ---------------------------------------------------------------------------*/
/*                   End of Instance Provider Interface                       */
/* ---------------------------------------------------------------------------*/

/* ---------------------------------------------------------------------------*/
/*                        Method Provider Interface                           */
/* ---------------------------------------------------------------------------*/

CMPIStatus SystemMemory_OpenDRIM_MemoryProviderMethodCleanup(CMPIMethodMI * mi, const CMPIContext * ctx, CMPIBoolean terminate) {
	_E_;
	int errorCode = SystemMemory_OpenDRIM_Memory_finalize();
	CMPIStatus rc;
	CMSetStatus(&rc, (CMPIrc) errorCode);
	_L_;
	return rc;
}

CMPIStatus SystemMemory_OpenDRIM_MemoryProviderInvokeMethod(CMPIMethodMI* mi, const CMPIContext* ctx, const CMPIResult* rslt, const CMPIObjectPath* ref, const char* methodName, const CMPIArgs* in, CMPIArgs* out) {
	_E_;
	CMPIStatus rc = {CMPI_RC_OK, NULL};
	OpenDRIM_Memory instance;
	SystemMemory_OpenDRIM_Memory_toCPP(_broker, ref, instance);
	string errorMessage;

	const char* properties[] = {"DeviceID", "SystemCreationClassName", "SystemName", "CreationClassName"};
	int errorCode = SystemMemory_OpenDRIM_Memory_getInstance(_broker, ctx, instance, properties, errorMessage);
	if (errorCode != OK) {
		errorMessage = (string) OpenDRIM_Memory_classnames[0] + ": " + errorMessage;
		CMSetStatusWithChars(_broker, &rc, (CMPIrc) errorCode, errorMessage.c_str());
		return rc;
	}

	if ((string) methodName =="RequestStateChange") {
		unsigned int returnValue;
		OpenDRIM_Memory_RequestStateChange_In inArgs;
		SystemMemory_OpenDRIM_Memory_toCPP(_broker, in, inArgs);
		OpenDRIM_Memory_RequestStateChange_Out outArgs;
		
		errorCode = SystemMemory_OpenDRIM_Memory_RequestStateChange(_broker, ctx, instance, returnValue, inArgs, outArgs, errorMessage);
		if (errorCode != OK) {
			errorMessage = (string) OpenDRIM_Memory_classnames[0] + ": " + errorMessage;
			CMSetStatusWithChars(_broker, &rc, (CMPIrc) errorCode, errorMessage.c_str());
			return rc;
		}
		SystemMemory_OpenDRIM_Memory_toCMPIArg(_broker, out, outArgs);
		
		CMPIValue value = CT_toCMPI(returnValue);
		CMReturnData(rslt, &value.uint32, CMPI_uint32);
	}
	else if ((string) methodName =="SetPowerState") {
		unsigned int returnValue;
		OpenDRIM_Memory_SetPowerState_In inArgs;
		SystemMemory_OpenDRIM_Memory_toCPP(_broker, in, inArgs);
		
		errorCode = SystemMemory_OpenDRIM_Memory_SetPowerState(_broker, ctx, instance, returnValue, inArgs, errorMessage);
		if (errorCode != OK) {
			errorMessage = (string) OpenDRIM_Memory_classnames[0] + ": " + errorMessage;
			CMSetStatusWithChars(_broker, &rc, (CMPIrc) errorCode, errorMessage.c_str());
			return rc;
		}
		
		CMPIValue value = CT_toCMPI(returnValue);
		CMReturnData(rslt, &value.uint32, CMPI_uint32);
	}
	else if ((string) methodName =="Reset") {
		unsigned int returnValue;
		
		errorCode = SystemMemory_OpenDRIM_Memory_Reset(_broker, ctx, instance, returnValue, errorMessage);
		if (errorCode != OK) {
			errorMessage = (string) OpenDRIM_Memory_classnames[0] + ": " + errorMessage;
			CMSetStatusWithChars(_broker, &rc, (CMPIrc) errorCode, errorMessage.c_str());
			return rc;
		}
		
		CMPIValue value = CT_toCMPI(returnValue);
		CMReturnData(rslt, &value.uint32, CMPI_uint32);
	}
	else if ((string) methodName =="EnableDevice") {
		unsigned int returnValue;
		OpenDRIM_Memory_EnableDevice_In inArgs;
		SystemMemory_OpenDRIM_Memory_toCPP(_broker, in, inArgs);
		
		errorCode = SystemMemory_OpenDRIM_Memory_EnableDevice(_broker, ctx, instance, returnValue, inArgs, errorMessage);
		if (errorCode != OK) {
			errorMessage = (string) OpenDRIM_Memory_classnames[0] + ": " + errorMessage;
			CMSetStatusWithChars(_broker, &rc, (CMPIrc) errorCode, errorMessage.c_str());
			return rc;
		}
		
		CMPIValue value = CT_toCMPI(returnValue);
		CMReturnData(rslt, &value.uint32, CMPI_uint32);
	}
	else if ((string) methodName =="OnlineDevice") {
		unsigned int returnValue;
		OpenDRIM_Memory_OnlineDevice_In inArgs;
		SystemMemory_OpenDRIM_Memory_toCPP(_broker, in, inArgs);
		
		errorCode = SystemMemory_OpenDRIM_Memory_OnlineDevice(_broker, ctx, instance, returnValue, inArgs, errorMessage);
		if (errorCode != OK) {
			errorMessage = (string) OpenDRIM_Memory_classnames[0] + ": " + errorMessage;
			CMSetStatusWithChars(_broker, &rc, (CMPIrc) errorCode, errorMessage.c_str());
			return rc;
		}
		
		CMPIValue value = CT_toCMPI(returnValue);
		CMReturnData(rslt, &value.uint32, CMPI_uint32);
	}
	else if ((string) methodName =="QuiesceDevice") {
		unsigned int returnValue;
		OpenDRIM_Memory_QuiesceDevice_In inArgs;
		SystemMemory_OpenDRIM_Memory_toCPP(_broker, in, inArgs);
		
		errorCode = SystemMemory_OpenDRIM_Memory_QuiesceDevice(_broker, ctx, instance, returnValue, inArgs, errorMessage);
		if (errorCode != OK) {
			errorMessage = (string) OpenDRIM_Memory_classnames[0] + ": " + errorMessage;
			CMSetStatusWithChars(_broker, &rc, (CMPIrc) errorCode, errorMessage.c_str());
			return rc;
		}
		
		CMPIValue value = CT_toCMPI(returnValue);
		CMReturnData(rslt, &value.uint32, CMPI_uint32);
	}
	else if ((string) methodName =="SaveProperties") {
		unsigned int returnValue;
		
		errorCode = SystemMemory_OpenDRIM_Memory_SaveProperties(_broker, ctx, instance, returnValue, errorMessage);
		if (errorCode != OK) {
			errorMessage = (string) OpenDRIM_Memory_classnames[0] + ": " + errorMessage;
			CMSetStatusWithChars(_broker, &rc, (CMPIrc) errorCode, errorMessage.c_str());
			return rc;
		}
		
		CMPIValue value = CT_toCMPI(returnValue);
		CMReturnData(rslt, &value.uint32, CMPI_uint32);
	}
	else if ((string) methodName =="RestoreProperties") {
		unsigned int returnValue;
		
		errorCode = SystemMemory_OpenDRIM_Memory_RestoreProperties(_broker, ctx, instance, returnValue, errorMessage);
		if (errorCode != OK) {
			errorMessage = (string) OpenDRIM_Memory_classnames[0] + ": " + errorMessage;
			CMSetStatusWithChars(_broker, &rc, (CMPIrc) errorCode, errorMessage.c_str());
			return rc;
		}
		
		CMPIValue value = CT_toCMPI(returnValue);
		CMReturnData(rslt, &value.uint32, CMPI_uint32);
	}
	else {
		errorMessage = (string) OpenDRIM_Memory_classnames[0] + ": " + "The requested method (" + (string) methodName +") was not found.";
		CMSetStatusWithChars(_broker, &rc, (CMPIrc) NOT_SUPPORTED, errorMessage.c_str());
		return rc;
	}
	CMReturnDone(rslt);
	_L_;
	CMReturn(CMPI_RC_OK);
}

/* ---------------------------------------------------------------------------*/
/*                    End of Method Provider Interface                        */
/* ---------------------------------------------------------------------------*/

/* ---------------------------------------------------------------------------*/
/*                              Provider Factory                              */
/* ---------------------------------------------------------------------------*/

int SystemMemory_OpenDRIM_Memory_init(const CMPIBroker* broker) {
	_E_;
	_broker = broker;
	static bool initialized = false;
	if (!initialized) {
		string errorMessage;
		int errorCode = SystemMemory_OpenDRIM_Memory_load(broker, errorMessage);
		if (errorCode != OK) {
			errorMessage += "SystemMemory_OpenDRIM_Memory_init FAILED: " + (string) OpenDRIM_Memory_classnames[0] + ": " + errorMessage;
			string cmd = "/bin/echo \"" + errorMessage + "\" >> cmpi_prov_debug.txt";
			system(cmd.c_str());
			return -1;
		}
		initialized = true;
	}
	_L_;
	return OK;
}

int SystemMemory_OpenDRIM_Memory_finalize() {
	_E_;
	static bool finalized = false;
	if (!finalized) {
		string errorMessage;
		int errorCode = SystemMemory_OpenDRIM_Memory_unload(errorMessage);
		if (errorCode != OK) {
			errorMessage += "SystemMemory_OpenDRIM_Memory_unload FAILED: " + (string) OpenDRIM_Memory_classnames[0] + ": " + errorMessage;
			string cmd = "/bin/echo \"" + errorMessage + "\" >> cmpi_prov_debug.txt";
			system(cmd.c_str());
			return errorCode;
		}
		finalized = true;
	}
	_L_;
	return OK;
}

#define SystemMemory_OpenDRIM_Memory_INIT if (SystemMemory_OpenDRIM_Memory_init(_broker) < 0) return NULL

CMInstanceMIStub(SystemMemory_OpenDRIM_MemoryProvider, SystemMemory_OpenDRIM_MemoryProvider, _broker, SystemMemory_OpenDRIM_Memory_INIT);
CMMethodMIStub(SystemMemory_OpenDRIM_MemoryProvider, SystemMemory_OpenDRIM_MemoryProvider, _broker, SystemMemory_OpenDRIM_Memory_INIT);

/* ---------------------------------------------------------------------------*/
/*                          End of Provider Factory                           */
/* ---------------------------------------------------------------------------*/
