/*******************************************************************

Copyright (c) 2004 Open Mobile Alliance, Ltd.  All Rights Reserved.

This software is made available under the usage and distribution terms 
covered by the Common Public License 1.0 and by using this software you
are bound by the terms and conditions of the same.

EXCEPT AS EXPRESSLY SET FORTH IN THE COMMON PUBLIC LICENSE,
THIS PROGRAM IS PROVIDED ON AN "AS IS" BASIS, 
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, 
ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, 
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
   
Each recipient is solely responsible for determining the 
appropriateness of using and distributing this program and assumes 
all risks associated with its exercise of rights under the Common 
Public License, including but not limited to the risks and 
costs of program errors, compliance with applicable laws, 
damage to or loss of data, programs or equipment, and 
unavailability or interruption of operations.

********************************************************************/


#include "SctsErrorLog.h"
#ifdef __SCTS_LOG_ERRORS__

/* Static variable definitions : the thread ID - error log mapping */
std::map <int,class SctsErrorLog *> SctsErrorLog::errorLogs;
SctsMutex SctsErrorLog::errorLogsLock;

SctsErrorLog::SctsErrorLog() : nodeTree(new Node("General",0)) 
{
	/* 
	Create a new entry in the mapping table, this associates the thread
	creating the error log with the newly created object.
	*/
	errorLogsLock.Lock();
	errorLogs[SctsThread::GetID()]=this;
	errorLogsLock.Unlock();
	currentNodeTreeItem=nodeTree.GetRootItem();
}

SctsErrorLog::~SctsErrorLog()
{
	/* 
	Remove the associated entry from the mapping table. Any thread 
	can destroy the error log hence the current thread ID shouldn't
	be used to find the mapping entry.
	*/
	std::map <int,SctsErrorLog *>::iterator it;
	errorLogsLock.Lock();
	for (it=errorLogs.begin();it!=errorLogs.end();++it)
	{
		if (it->second==this)
		{
			errorLogs.erase(it);
			break;
		}
	}
	errorLogsLock.Unlock();
}

SctsErrorLog *SctsErrorLog::GetErrorLog()
{
	/* Get the error log associated with the current thread ID */
	std::map <int,SctsErrorLog *>::iterator it;
	errorLogsLock.Lock();
	if ((it=errorLogs.find(SctsThread::GetID()))==errorLogs.end()) 
	{
		errorLogsLock.Unlock();
		return 0;
	}
	errorLogsLock.Unlock();
	return it->second;
}

SctsErrorLog::Node::Node(char *_name,char *_desc) 
{
	errors=0;
	SCTSASSERT(_name);
	name=sctsStrdup(_name);
	desc=sctsStrdup(_desc);
}

SctsErrorLog::Node::~Node()
{
	NodeEntry *temp;
	while (errors)
	{
		temp=errors->next;
		sctsFree(errors->error);
		sctsFree(errors);
		errors=temp;
	}
	sctsFree(name);
	if (desc) sctsFree(desc);
}

/* 
The following static functions are used to manipulate the error log 
associated with the calling thread.
*/

bool SctsErrorLog::Clear()
{
	SctsTree<Node *>::Item *temp;
	SctsErrorLog *log=GetErrorLog();
	if (!log) return false;
	log->currentNodeTreeItem=log->nodeTree.GetRootItem();
	SCTSASSERT(log->currentNodeTreeItem);
	while ((temp=log->nodeTree.GetFirstChildItem(log->currentNodeTreeItem))) log->nodeTree.DeleteItem(temp);
	delete log->currentNodeTreeItem->data;
	log->currentNodeTreeItem->data=new Node("General",0);
	return true;
}

bool SctsErrorLog::OpenNode(char *nodeName,char *nodeDesc)
{
	SctsErrorLog *log=GetErrorLog();
	if (!log) return false;
	SCTSASSERT(log->currentNodeTreeItem && nodeName);
	log->currentNodeTreeItem=log->nodeTree.InsertChildItem(log->currentNodeTreeItem,new Node(nodeName,nodeDesc));
	return true;
}

bool SctsErrorLog::HasErrors()
{
	return (nodeTree.GetFirstChildItem(nodeTree.GetRootItem()) || nodeTree.GetRootItem()->data->errors);
}

bool SctsErrorLog::AppendError(char *error)
{
	Node *currentNode;
	NodeEntry *nodeEntry;
	SctsErrorLog *log=GetErrorLog();
	if (!log) return false;
	SCTSASSERT(error);
	SCTSASSERT(log->currentNodeTreeItem && log->currentNodeTreeItem->data);
	currentNode=log->currentNodeTreeItem->data;
	if (!currentNode->errors)
	{
		if (!(currentNode->errors=(NodeEntry *)sctsMalloc(sizeof(NodeEntry)))) return false;
		currentNode->errors->error=sctsStrdup(error);
		currentNode->errors->next=0;
		return true;
	}
	if (!(nodeEntry=(NodeEntry *)sctsMalloc(sizeof(NodeEntry)))) return false;	
	nodeEntry->error=sctsStrdup(error);
	nodeEntry->next=currentNode->errors;
	currentNode->errors=nodeEntry;
	return true;
}

bool SctsErrorLog::CloseNode()
{
	
	SctsTree<Node *>::Item *temp;
	SctsErrorLog *log=GetErrorLog();
	if (!log) return false;
	SCTSASSERT(log->currentNodeTreeItem!=log->nodeTree.GetRootItem());
	temp=log->currentNodeTreeItem;
	log->currentNodeTreeItem=log->nodeTree.GetParentItem(log->currentNodeTreeItem);
	if (!temp->data->errors && !log->nodeTree.GetFirstChildItem(temp))
		log->nodeTree.DeleteItem(temp);
	return true;
}
		
#ifdef __SCTS_USING_RTK__
#include "smlerr.h"
#include "xpt.h"

const char *sctsGetRTKError(int error)
{
	switch(error)
	{
	case SML_ERR_UNSPECIFIC :
			return "Unspecific error";
	case SML_ERR_NOT_ENOUGH_SPACE :
			return "Not enough memory to perform this operation";
	case SML_ERR_WRONG_USAGE :
			return "Function was called in wrong context ";
	case SML_ERR_WRONG_PARAM:
			return "Wrong parameter";
	case SML_ERR_INVALID_SIZE  :
			return "Param has an invalid size";
	case SML_ERR_INVALID_HANDLE:
			return "Handle is invalid/unknown";
	case SML_ERR_INVALID_OPTIONS:
			return "Unkown or unallowed options";
	case SML_ERR_A_MGR_ERROR:
			return "Template error";
	case SML_ERR_MGR_INVALID_INSTANCE_INFO:
			return "An invalid Instance Info structure is used";
	case SML_ERR_COMMAND_NOT_HANDLED:
			return "No callback function is available to handle this command";
	case SML_ERR_ALREADY_INITIALIZED:
			return "No callback function is available to handle this command";
	case SML_ERR_XLT_MISSING_CONT:
			return "required field content missing";
	case SML_ERR_XLT_BUF_ERR:
			return "Buffer too small ";
	case SML_ERR_XLT_INVAL_PCDATA_TYPE :
			return "Invalid (WBXML) Element Type (STR_I etc.)";
	case SML_ERR_XLT_INVAL_LIST_TYPE:
			return "Invalid List Type (COL_LIST etc.)";
	case SML_ERR_XLT_INVAL_TAG_TYPE :
			return "Invalid Tag Type (TT_BEG etc.)";
	case SML_ERR_XLT_ENC_UNK:
			return "Unknown Encoding (WBXML, XML)";
	case SML_ERR_XLT_INVAL_PROTO_ELEM:
			return "Invalid Protocol Element";
	case SML_ERR_MISSING_LIST_ELEM:
			return "Missing Content of Lost Elements ";
	case SML_ERR_XLT_INCOMP_WBXML_VERS:
			return "Incompatible WBXML Content Format Version";
	case SML_ERR_XLT_INVAL_SYNCML_DOC :
			return "Document does not conform to SyncML DTD ";
	case SML_ERR_XLT_INVAL_PCDATA :
			return "Invalid PCData elem (e.g. not encoded as OPAQUE data)";
	case SML_ERR_XLT_TOKENIZER_ERROR:
			return "Unspecified tokenizer error";
	case SML_ERR_XLT_INVAL_WBXML_DOC:
			return "Document does not conform to WBXML specification";
	case SML_ERR_XLT_WBXML_UKN_TOK:
			return "Document contains unknown WBXML token";
	case SML_ERR_XLT_MISSING_END_TAG:
			return "Non-empty start tag without matching end tag";
	case SML_ERR_XLT_INVALID_CODEPAGE:
			return "Invalid namespace/codespace";
	case SML_ERR_XLT_END_OF_BUFFER:
			return "End of buffer reached. Possible cause : invalid content format (WBXML/XML).";
	case SML_ERR_XLT_INVAL_XML_DOC:
			return "Document does not conform to XML 1.0 specification";
	case SML_ERR_XLT_XML_UKN_TAG :
			return "Document contains unknown XML tag";
	case SML_ERR_XLT_INVAL_PUB_IDENT:
			return "Invalid Public Identifier";
	case SML_ERR_XLT_INVAL_EXT:
			return "Invalid Codepage Extension";
	case SML_ERR_XLT_NO_MATCHING_CODEPAGE:
			return "No matching Codepage could be found";
	case SML_ERR_XLT_INVAL_INPUT_DATA:
			return "Data missing in input structure";
	case SML_ERR_WSM_BUF_TABLE_FULL:
			return "No more empty entries in buffer table available";
	case SML_ERR_A_UTI_UNKNOWN_PROTO_ELEMENT:
			return "Unknown Proto Element ";
	case SML_ERR_A_XPT_SERVER_AUTH:     
			return"Server authentication failed";
	case SML_ERR_A_XPT_ACCESS_DENIED:  
			return"Server rejected request";
	case SML_ERR_A_XPT_HTTP_ERROR:     
			return"HTTP error";
	case SML_ERR_A_XPT_COMMUNICATION:  
			return xptGetLastError()->errorMessage;
	case SML_ERR_A_XPT_INVALID_PROTOCOL: 
			return"Protocol not supported";
	case SML_ERR_A_XPT_INVALID_PARM : 
			return"Parameter error";
	case SML_ERR_A_XPT_INVALID_ID :   
			return"Invalid Communication/Service ID";
	case SML_ERR_A_XPT_MEMORY :       
			return"Memory allocation error";
	case SML_ERR_A_XPT_IN_USE :       
			return"Too many open communication instances";
	case SML_ERR_A_XPT_INVALID_STATE :
			return"Invalid communication state";
	case SML_ERR_A_XPT_NO_TRANSPORTS :
			return"No transports are available";
	default:
			return "Unspecified Error ";
	}
}

void sctsClearRTKError()
{
    xptResetError();
}

#endif
#endif
