package com.dbxml.db.core;

/*
 * dbXML - Native XML Database
 * Copyright (C) 1999-2004  The dbXML Group, L.L.C.
 *
 * 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; either version 2
 * of the License, or (at your option) any later version.
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Id: FaultCodes.java,v 1.2 2004/02/12 00:17:56 bradford Exp $
 */

import java.util.HashMap;
import java.util.Map;

import org.xmldb.api.base.ErrorCodes;
import org.xmldb.api.base.XMLDBException;

/**
 * FaultCodes defines the dbXML specific fault codes and associated error
 * messages.
 */

public abstract class FaultCodes {
   // Categories
   public static final int GEN = 0;     // General
   public static final int OBJ = 100;   // Extensions
   public static final int COL = 200;   // Collections
   public static final int IDX = 300;   // Indexes
   public static final int TRX = 400;   // Transactions
   public static final int DBE = 500;   // Database
   public static final int QRY = 600;   // Queries
   public static final int SEC = 700;   // Security
   public static final int URI = 800;   // URI
   public static final int TRG = 900;   // Triggers
   public static final int SCR = 1000;  // Scripting
   public static final int JAVA = 2000; // Java

   // General errors 0 series
   public static final int GEN_UNKNOWN = 0;
   public static final int GEN_GENERAL_ERROR = 40;
   public static final int GEN_CRITICAL_ERROR = 70;
   public static final int GEN_FATAL_ERROR = 90;

   // Extension invocation errors 100 series
   public static final int OBJ_OBJECT_NOT_FOUND = 100;
   public static final int OBJ_METHOD_NOT_FOUND = 101;
   public static final int OBJ_NULL_RESULT = 140;
   public static final int OBJ_INVALID_RESULT = 141;
   public static final int OBJ_DUPLICATE_OBJECT = 142;
   public static final int OBJ_RUNTIME_EXCEPTION = 170;
   public static final int OBJ_CLASS_FORMAT_ERROR = 171;
   public static final int OBJ_INVALID_CONTEXT = 172;
   public static final int OBJ_CANNOT_CREATE = 173;

   // Collection-related errors 200 series
   public static final int COL_COLLECTION_NOT_FOUND = 200;
   public static final int COL_DOCUMENT_NOT_FOUND = 201;
   public static final int COL_DUPLICATE_COLLECTION = 240;
   public static final int COL_NULL_RESULT = 241;
   public static final int COL_NO_FILER = 242;
   public static final int COL_NO_INDEXMANAGER = 242;
   public static final int COL_DOCUMENT_MALFORMED = 243;
   public static final int COL_CANNOT_STORE = 244;
   public static final int COL_CANNOT_RETRIEVE = 245;
   public static final int COL_COLLECTION_READ_ONLY = 246;
   public static final int COL_COLLECTION_CLOSED = 247;
   public static final int COL_CANNOT_CREATE = 270;
   public static final int COL_CANNOT_DROP = 271;

   // Index-related errors 300 series
   public static final int IDX_VALUE_NOT_FOUND = 300;
   public static final int IDX_INDEX_NOT_FOUND = 301;
   public static final int IDX_MATCHES_NOT_FOUND = 340;
   public static final int IDX_DUPLICATE_INDEX = 341;
   public static final int IDX_NOT_SUPPORTED = 370;
   public static final int IDX_STYLE_NOT_FOUND = 371;
   public static final int IDX_CORRUPTED = 372;
   public static final int IDX_CANNOT_CREATE = 373;

   // Transaction-related errors 400 series
   public static final int TRX_NO_CONTEXT = 440;
   public static final int TRX_NOT_ACTIVE = 441;
   public static final int TRX_NOT_SUPPORTED = 470;

   // Database-related errors 500 series
   public static final int DBE_NO_PARENT = 500;
   public static final int DBE_CANNOT_DROP = 570;
   public static final int DBE_CANNOT_CREATE = 571;

   // Query-related errors 600 series
   public static final int QRY_NULL_RESULT = 600;
   public static final int QRY_COMPILATION_ERROR = 640;
   public static final int QRY_PROCESSING_ERROR = 641;
   public static final int QRY_NOT_SUPPORTED = 670;
   public static final int QRY_STYLE_NOT_FOUND = 671;

   // Security-related errors 700 series
   public static final int SEC_INVALID_USER = 770;
   public static final int SEC_INVALID_ROLE = 771;
   public static final int SEC_INVALID_ACCESS = 772;
   public static final int SEC_INVALID_CREDENTIALS = 773;

   // URI Mapper errors 800 series
   public static final int URI_EMPTY = 800;
   public static final int URI_NULL = 801;
   public static final int URI_PARSE_ERROR = 820;

   // Trigger errors 900 series
   public static final int TRG_TRIGGER_NOT_FOUND = 900;
   public static final int TRG_CANCEL_OPERATION = 940;
   public static final int TRG_CANNOT_CREATE = 970;
   public static final int TRG_DUPLICATE_TRIGGER = 971;

   // Scripting errors 1000 series
   public static final int SCR_CANNOT_EXECUTE = 1040;
   public static final int SCR_RUNTIME_ERROR = 1041;

   // Java errors 2000 series
   public static final int JAVA_RUNTIME_ERROR = 2070;

   private static final Map FaultMsg = new HashMap();

   private FaultCodes() {
   }

   static {
      // General errors 0 series
      putCodeMessage(GEN_UNKNOWN, "Unknown");
      putCodeMessage(GEN_GENERAL_ERROR, "General Error");
      putCodeMessage(GEN_CRITICAL_ERROR, "Critical Error");
      putCodeMessage(GEN_FATAL_ERROR, "Fatal Error");

      // Extension invocation errors 100 series
      putCodeMessage(OBJ_OBJECT_NOT_FOUND, "Extension Not Found");
      putCodeMessage(OBJ_METHOD_NOT_FOUND, "Extension Method Not Found");
      putCodeMessage(OBJ_NULL_RESULT, "Extension Null Result");
      putCodeMessage(OBJ_INVALID_RESULT, "Extension Invalid Result");
      putCodeMessage(OBJ_DUPLICATE_OBJECT, "Extension Duplicate Object");
      putCodeMessage(OBJ_RUNTIME_EXCEPTION, "Extension Runtime Exception");
      putCodeMessage(OBJ_CLASS_FORMAT_ERROR, "Extension Class Format Error");
      putCodeMessage(OBJ_INVALID_CONTEXT, "Extension Invalid Context");
      putCodeMessage(OBJ_CANNOT_CREATE, "Extension Cannot Create");

      // Collection-related errors 200 series
      putCodeMessage(COL_COLLECTION_NOT_FOUND, "Collection Not Found");
      putCodeMessage(COL_DOCUMENT_NOT_FOUND, "Collection Document Not Found");
      putCodeMessage(COL_DUPLICATE_COLLECTION, "Collection Duplicated");
      putCodeMessage(COL_NULL_RESULT, "Collection Null Result");
      putCodeMessage(COL_NO_FILER, "Collection No Filer");
      putCodeMessage(COL_NO_INDEXMANAGER, "Collection No IndexManager");
      putCodeMessage(COL_DOCUMENT_MALFORMED, "Collection Document Malformed");
      putCodeMessage(COL_CANNOT_STORE, "Collection Cannot ContentImport");
      putCodeMessage(COL_CANNOT_RETRIEVE, "Collection Cannot Retrieve");
      putCodeMessage(COL_COLLECTION_READ_ONLY, "Collection Read-only");
      putCodeMessage(COL_COLLECTION_CLOSED, "Collection Closed");
      putCodeMessage(COL_CANNOT_CREATE, "Collection Cannot Create");
      putCodeMessage(COL_CANNOT_DROP, "Collection Cannot Drop");

      // Index-related errors 300 series
      putCodeMessage(IDX_VALUE_NOT_FOUND, "Index Value Not Found");
      putCodeMessage(IDX_INDEX_NOT_FOUND, "Index Not Found");
      putCodeMessage(IDX_MATCHES_NOT_FOUND, "Index Matches Not Found");
      putCodeMessage(IDX_DUPLICATE_INDEX, "Index Duplicate Index");
      putCodeMessage(IDX_NOT_SUPPORTED, "Index Not Supported");
      putCodeMessage(IDX_STYLE_NOT_FOUND, "Index Style Not Found");
      putCodeMessage(IDX_CORRUPTED, "Index Corrupted");
      putCodeMessage(IDX_CANNOT_CREATE, "Index Cannot Create");

      // Transaction-related errors 400 series
      putCodeMessage(TRX_NO_CONTEXT, "Transaction No Context");
      putCodeMessage(TRX_NOT_ACTIVE, "Transaction Not Active");
      putCodeMessage(TRX_NOT_SUPPORTED, "Transaction Not Supported");

      // Database-related errors 500 series
      putCodeMessage(DBE_NO_PARENT, "Database No Parent");
      putCodeMessage(DBE_CANNOT_DROP, "Database Cannot Drop");
      putCodeMessage(DBE_CANNOT_CREATE, "Database Cannot Create");

      // Query-related errors 600 series
      putCodeMessage(QRY_NULL_RESULT, "Query Null Result");
      putCodeMessage(QRY_COMPILATION_ERROR, "Query Compilation Error");
      putCodeMessage(QRY_PROCESSING_ERROR, "Query Processing Error");
      putCodeMessage(QRY_NOT_SUPPORTED, "Query Not Supported");
      putCodeMessage(QRY_STYLE_NOT_FOUND, "Query Style Not Found");

      // Security-related errors 700 series
      putCodeMessage(SEC_INVALID_USER, "Security Invalid User");
      putCodeMessage(SEC_INVALID_ROLE, "Security Invalid Role");
      putCodeMessage(SEC_INVALID_ACCESS, "Security Invalid Access");
      putCodeMessage(SEC_INVALID_CREDENTIALS, "Security Invalid Credentials");

      // URI-related errors 800 series
      putCodeMessage(URI_EMPTY, "URI Empty");
      putCodeMessage(URI_NULL, "URI Null");
      putCodeMessage(URI_PARSE_ERROR, "URI Parse Error");

      // Trigger errors 900 series
      putCodeMessage(TRG_CANCEL_OPERATION, "Trigger Operation Canceled");
      putCodeMessage(TRG_CANNOT_CREATE, "Trigger Cannot Create");
      putCodeMessage(TRG_DUPLICATE_TRIGGER, "Trigger Duplicate Trigger");

      // Scripting errors 1000 series
      putCodeMessage(SCR_CANNOT_EXECUTE, "Script Cannot Execute");
      putCodeMessage(SCR_RUNTIME_ERROR, "Script Runtime Error");

      // Java-related errors 2000 series
      putCodeMessage(JAVA_RUNTIME_ERROR, "Java Runtime Error");
   }

   private static void putCodeMessage(int code, String message) {
      FaultMsg.put(new Integer(code), message);
   }

   /**
    * getMessage returns a textual form for the specified fault code.
    *
    * @param code The Fault Code
    * @return It's textual form
    */
   public static String getMessage(int code) {
      String msg = (String)FaultMsg.get(new Integer(code));
		if ( msg != null )
			return msg;
		else
		   return "";
   }

   /**
    * createXMLDBException creates an XMLDBException instance based
    * on the specified Exception.  If the Exception is a DBException,
    * it will extract any important information from it (like fault
    * codes and messages)
    *
    * @param e The Exception to use
    * @return An XMLDBException instance
    */
   public static XMLDBException createXMLDBException(Exception e) {
      if ( e instanceof XMLDBException )
         return (XMLDBException)e;
      else if ( e instanceof DBException ) {
         DBException d = (DBException)e;
         return new XMLDBException(ErrorCodes.VENDOR_ERROR, d.faultCode, getMessage(d.faultCode));
      }
      else {
         String m = e.getMessage();
         if ( m == null )
            m = "";
			
         int code;
			if ( e instanceof RuntimeException )
				code =JAVA_RUNTIME_ERROR;
			else
				code =GEN_UNKNOWN;
			
         return new XMLDBException(ErrorCodes.VENDOR_ERROR, code, m);
      }
   }

   /**
    * getFaultCodeType examines the provided exception to determine
    * the general fault code that is associated with it.  General
    * fault codes are reduced from actual fault codes to be one of
    * the GEN_ prefixed fault code values.
    *
    * @param e The Exception to examine
    * @return The General Fault Code
    */
   public static int getFaultCodeType(Exception e) {
      int code = 0;
      if ( e instanceof DBException )
         code = ((DBException)e).faultCode;
      // Strip it to the General series
      code = code % 100;
      // Narrow to a General value
      code = code - (code % 10);
      return code;
   }

   /**
    * getFaultCodeSeries examines the provided exception to
    * determine the fault code series that is associated with it.
    * Series are reduced from actual fault codes to be one of
    * the fault code prefixes (ex: COL, DB, SEC).
    *
    * @param e The Exception to examine
    * @return The Fault Code Series
    */
   public static int getFaultCodeSeries(Exception e) {
      int code = 0;
      if ( e instanceof DBException )
         code = ((DBException)e).faultCode;
      // Strip it to the series
      code = code - (code % 100);
      return code;
   }

   /**
    * getFaultCode examines the provided exception to determine
    * the fault code that is associated with it.
    *
    * @param e The Exception to examine
    * @return The Fault Code
    */
   public static int getFaultCode(Exception e) {
      if ( e instanceof DBException )
         return ((DBException)e).faultCode;
      else
         return 0;
   }

   /**
    * getFaultMessage examines the provided exception to determine
    * the fault message that is associated with it.
    *
    * @param e The Exception to examine
    * @return The Fault Message
    */
   public static String getFaultMessage(Exception e) {
      return getMessage(getFaultCode(e));
   }
}

