//-----------------------------------------------------------------------------
// Copyright (c) 1994,1995 Southeastern Universities Research Association,
//                         Continuous Electron Beam Accelerator Facility
//
// This software was developed under a United States Government license
// described in the NOTICE file included as part of this distribution.
//
//-----------------------------------------------------------------------------
// 
// Description:
//     cdevError class (abstract base class)
//    
// Author:  Jie Chen & Chip Watson
//
// Revision History:
//   cdevError.cc,v
// Revision 1.10  1997/08/27  18:23:31  chen
// Change error reporting to site specific scheme
//
// Revision 1.9  1997/03/25  22:24:42  akers
// Development in support of a new cdevDirectory
//
// Revision 1.8  1996/02/26  16:28:04  akers
// Change report error formatting
//
// Revision 1.7  1995/12/14  19:11:19  chen
// add support to C interface
//
// Revision 1.6  1995/10/26  19:26:17  akers
// Final Revisions for Version 1.1
//
// Revision 1.5  1995/10/26  14:45:21  akers
// Added carriage return to error handler
//
// Revision 1.4  1995/10/26  14:33:30  akers
// Removal of Warnings
//
// Revision 1.3  1995/10/17  17:44:12  akers
// Added setThreshold functionality and made data items protected
//
// Revision 1.2  1995/10/17  15:29:54  chen
// change reportError interface
//
// Revision 1.1.1.1  1995/06/16  17:14:08  epics
// initial import of cdev
//
//
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdarg.h>
#include "cdevError.h"
#include "cdevErrCode.h"
#include "cdevRequestObject.h"

void defaultErrorHandler(int severity, char *text, 
                         cdevRequestObject* /* obj */)
    {
    if(severity != CDEV_SEVERITY_VOID_DATA && text && *text)
        {
        #ifndef _WIN32
        fprintf(stderr, "%s\n", text);
        #else
	HANDLE stderrHandle=GetStdHandle(STD_ERROR_HANDLE);
        if(stderrHandle != INVALID_HANDLE_VALUE)
            {
            int nReady=strlen(text);
            unsigned long nWritten=0;
            
            WriteFile(stderrHandle, text, nReady, &nWritten, NULL);
            WriteFile(stderrHandle, "\n", 1, &nWritten, NULL);
            }
	#endif
        }
    }

cdevErrorHandler cdevError::defaultErrorHandler_=defaultErrorHandler;

//============================================================================
//         Implementation of cdevError class
//============================================================================
cdevError::cdevError(void)
	: autoErrorOn_(1), 
	  threshold_(CDEV_SEVERITY_WARN), 
	  errorHandler_(defaultErrorHandler), 
	  numhandlers_(0)
    {
    #ifdef _TRACE_OBJECTS
    printf("Create abstract class cdevError\n");
    #endif
    for(int i=0; i < _CDEV_MAX_ERR_HANDLERS; i++)
    handlers_[i]=0;
    }

cdevError::cdevError(cdevErrorHandler handler)
	: autoErrorOn_(1), 
	  threshold_(CDEV_SEVERITY_WARN), 
	  errorHandler_(handler)
    {
    #ifdef _TRACE_OBJECTS
    printf("Create abstract class cdevError\n");
    #endif
    }

cdevError::~cdevError(void)
    {
    #ifdef _TRACE_OBJECTS
    printf("Delete abstract class cdevError\n");
    #endif
    }

void
cdevError::setErrorHandler(cdevErrorHandler handler)
    {
    errorHandler_=handler;
    }

void
cdevError::setThreshold(int errorThreshold)
    {
    threshold_=errorThreshold;
    }

int
cdevError::autoErrorOn(void)
    {
    autoErrorOn_=1;
    return CDEV_SUCCESS;
    }

int
cdevError::autoErrorOff(void)
    {
    autoErrorOn_=0;
    return CDEV_SUCCESS;
    }

int
cdevError::attachErrorHandler(cdevErrorHandler handler)
    {
    // check to see whether this handler is already here
    for(int i=0; i < numhandlers_; i++)
        {
        if(handler == handlers_[i])
        return CDEV_ERROR;
        }

    // make sure the buffer is not overflowed
    if(numhandlers_ >= _CDEV_MAX_ERR_HANDLERS)
    return CDEV_ERROR;
    
    handlers_[numhandlers_++]=handler;
    return CDEV_SUCCESS;
    }

int
cdevError::detachErrorHandler(cdevErrorHandler handler)
    {
    int index =- 1;
    int i=0;
    for(i=0; i < numhandlers_; i++)
        {
        if(handler == handlers_[i])
        index=i;
        }

    // cannot find this handler
    if(index ==- 1)
    return CDEV_ERROR;

    // move elements one position up
    for(i=index+1; i < numhandlers_; i++)
    handlers_[i-1]=handlers_[i];
    
    numhandlers_--;
    
    return CDEV_SUCCESS;
    }


int cdevError::vreportError(int severity, char *name, 
                             cdevRequestObject *obj, char *formatString, 
                             va_list argp)
    {
	int status=0;
    
    if(severity >= threshold_)
        {
		char msg[1024];
    	char *p=msg;
    	int i=0;
		
		sprintf(msg, "%s %s: ", 
                name, 
               (severity == 0?"Information":
               (severity == 1?"Warning":
               (severity == 2?"Error":
               (severity == 3?"Severe Error":
               "Event")))));
        
		p+=::strlen(msg);
        status=vsprintf(p, formatString, argp);
        
        if(!autoErrorOn_) (*errorHandler_) (severity, msg, obj);
        else (*defaultErrorHandler_) (severity, msg, obj);

        // report the error message to all attached message reporter
        for(i=0; i < numhandlers_; i++)
        	{
		(*handlers_[i]) (severity, msg, obj);
        	}
		}
    return status;
    }

int cdevError::reportError(int severity, char *name, 
                           cdevRequestObject *obj, 
						   char *formatString, ...)
    {
    va_list argp;
    int status=0;

    va_start(argp, formatString);
	status=vreportError(severity, name, obj, formatString, argp);
    va_end(argp);

    return status;
    }

void
cdevError::reportError(int severity, char *msg, cdevRequestObject *obj)
    {
    if(severity >= threshold_)
        {
        if(!autoErrorOn_) (*errorHandler_) (severity, msg, obj);
        else (*defaultErrorHandler_) (severity, msg, obj);

        // report the error message to all attached message reporter
        for(int i=0; i < numhandlers_; i++)
        	{
			(*handlers_[i]) (severity, msg, obj);
        	}
		}
    }

void
cdevError::reportError(void *data, cdevRequestObject *obj)
    {
    int severity=CDEV_SEVERITY_VOID_DATA;
    
    if(!autoErrorOn_)
    (*errorHandler_) (severity, (char *) data, obj);

    // report the error message to all attached message reporter
    for(int i=0; i < numhandlers_; i++)
    	{
		(*handlers_[i]) (severity, (char *) data, obj);
    	}
	}


