/*
 *  rm_error.c --
 *    Implements the Renderman error handling. 
 *    See section 7.2 of the RISpec 3.2
 *
 *  Created by Karsten Lueth on 04.11.03.
 * 
 *  Copyright (c) 2003-2008 Karsten Lueth (karsten.lueth@bacon3d.com). All rights reserved.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include "rm_error.h"

/* ----------------------------------------------------------------------
 * Private variables.
 * ---------------------------------------------------------------------- */

/* curr_error_handler --
 *    the current error handler 
 */ 
static RtErrorHandler curr_error_handler = RiErrorAbort; 

/* ----------------------------------------------------------------------
 * Private functions.
 * ---------------------------------------------------------------------- */

/* severity_str --
 *   Converts a severity level to a descriptive string.
 */
static RtString severity_str(RtInt s)
{
    switch (s) {
        case RIE_INFO: /* Rendering stats and other info */
            return "Info"; 
        case RIE_WARNING: /* Something seems wrong, maybe okay */
            return "Warning";
        case RIE_ERROR: /* Problem. Results may be wrong */
            return "Error"; 
        default: /* So bad you should probably abort */
            return "Severe error"; 
    }
}


/* err_code_str--
 *   Converts an error code to a description string
 */
static RtString err_code_str(RtInt c)
{
    switch (c) {
        case RIE_NOERROR:
            return "";
        case RIE_NOMEM:
            return "(Out of memory)";
        case RIE_SYSTEM:
            return "(Miscellaneous system error)";
        case RIE_NOFILE:
            return "(File nonexistent)";
        case RIE_BADFILE:
            return "(Bad file format)";
        case RIE_VERSION:
            return "(File version mismatch)";
        case RIE_DISKFULL:
            return "(Target disk is full)";
        case RIE_INCAPABLE:
            return "(Optional RI feature)";
        case RIE_UNIMPLEMENT:
            return "(Unimplemented feature)";
        case RIE_LIMIT:
            return "(Program limit)";
        case RIE_BUG:
            return "(Bug in renderer?)";
        case RIE_NOTSTARTED:
            return "(RiBegin not called)";
        case RIE_NESTING:
            return "(Bad begin-end nesting)";
        case RIE_NOTOPTIONS:
            return "(Invalid state for options)";
        case RIE_NOTATTRIBS:
            return "(Invalid state for attributes)";
        case RIE_NOTPRIMS:
            return "(Invalid state for primitives)";
        case RIE_ILLSTATE:
            return "(Invalid state)";
        case RIE_BADMOTION:
            return "(Badly formed motion block)";
        case RIE_BADSOLID:
            return "(Badly formed solid block)";
        case RIE_BADTOKEN:
            return "(Invalid token for request)";
        case RIE_RANGE:
            return "(Parameter out of range)";
        case RIE_CONSISTENCY:
            return "(Parameters inconsistent)";
        case RIE_BADHANDLE :
            return "(Bad context/object/light handle)";
        case RIE_NOSHADER:
            return "(Cannot load requested shader)";
        case RIE_MISSINGDATA:
            return "(Required parameters not provided)";
        case RIE_SYNTAX:
            return "(Declare type syntax error)";
        case RIE_MATH:
            return "(Math error)";
        default:
            return "(Unknown code)"; 
    }
}

/* ----------------------------------------------------------------------
 * Global variables.
 * ---------------------------------------------------------------------- */

/* RiLastError --
 *   Contains the last error code 
 */
RtInt RiLastError = RIE_NOERROR;

/* ----------------------------------------------------------------------
 * Renderman Interface
 * ---------------------------------------------------------------------- */

/* ignore all errors */ 
RtVoid RiErrorIgnore(RtInt code, RtInt severity, char *msg)
{
    /* do nothing */ 
}

/* print all errors */ 
RtVoid RiErrorPrint(RtInt code, RtInt severity, char *msg)
{
    FILE *strm;
    if (severity>RIE_WARNING) strm = stderr; else strm = stdout;
	switch (severity) {
		case RIE_INFO:
			fprintf(strm, "%s\n", msg);
			break;
		default:
			fprintf(strm, "%s %s: %s\n", severity_str(severity), err_code_str(code), msg); 
	}
}

/* aborts for errors */ 
RtVoid RiErrorAbort(RtInt code, RtInt severity, char *msg)
{
    RiErrorPrint(code, severity, msg); 
    if (severity>RIE_WARNING) {
        exit(code);
    }
}

/* Sets the error handler */ 
RtVoid RiErrorHandler(RtErrorHandler handler)
{
    curr_error_handler = handler;    
}

/* ----------------------------------------------------------------------
 * RM Additions. 
 * ---------------------------------------------------------------------- */

/* sends an error message to the error handler */ 
void rm_error(RtInt code, RtInt severity, char *msg)
{
    curr_error_handler(code, severity, msg); 
}

/* Generates a info message. */
RtVoid rm_info(char* msg)
{
	rm_error(RIE_NOERROR, RIE_INFO, msg); 
}


/* End of file */ 
