/*
 * Copyright (C) 2007-2024 C# Port
 * Original Copyright (C) 2007-2018 Siemens AG
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 */

namespace V2GDecoderNet.EXI
{
    /// <summary>
    /// EXI Error Codes definitions
    /// </summary>
    public static class EXIErrorCodes
    {
        // Stream errors
        public const int EXI_ERROR_INPUT_STREAM_EOF = -10;
        public const int EXI_ERROR_OUTPUT_STREAM_EOF = -11;
        public const int EXI_ERROR_INPUT_FILE_HANDLE = -12;
        public const int EXI_ERROR_OUTPUT_FILE = -13;

        // Buffer errors
        public const int EXI_ERROR_OUT_OF_BOUNDS = -100;
        public const int EXI_ERROR_OUT_OF_STRING_BUFFER = -101;
        public const int EXI_ERROR_OUT_OF_BYTE_BUFFER = -103;
        public const int EXI_ERROR_OUT_OF_GRAMMAR_STACK = -104;
        public const int EXI_ERROR_OUT_OF_RUNTIME_GRAMMAR_STACK = -105;
        public const int EXI_ERROR_OUT_OF_QNAMES = -106;

        // Grammar errors
        public const int EXI_ERROR_UNKOWN_GRAMMAR_ID = -108;
        public const int EXI_ERROR_UNKOWN_EVENT = -109;
        public const int EXI_ERROR_UNKOWN_EVENT_CODE = -110;
        public const int EXI_ERROR_UNEXPECTED_EVENT_LEVEL1 = -111;
        public const int EXI_ERROR_UNEXPECTED_EVENT_LEVEL2 = -112;

        // Document structure errors
        public const int EXI_ERROR_UNEXPECTED_START_DOCUMENT = -113;
        public const int EXI_ERROR_UNEXPECTED_END_DOCUMENT = -114;
        public const int EXI_ERROR_UNEXPECTED_START_ELEMENT = -115;
        public const int EXI_ERROR_UNEXPECTED_START_ELEMENT_NS = -116;
        public const int EXI_ERROR_UNEXPECTED_START_ELEMENT_GENERIC = -117;
        public const int EXI_ERROR_UNEXPECTED_START_ELEMENT_GENERIC_UNDECLARED = -118;
        public const int EXI_ERROR_UNEXPECTED_END_ELEMENT = -119;
        public const int EXI_ERROR_UNEXPECTED_CHARACTERS = -120;
        public const int EXI_ERROR_UNEXPECTED_ATTRIBUTE = -121;
        public const int EXI_ERROR_UNEXPECTED_ATTRIBUTE_NS = -122;
        public const int EXI_ERROR_UNEXPECTED_ATTRIBUTE_GENERIC = -123;
        public const int EXI_ERROR_UNEXPECTED_ATTRIBUTE_GENERIC_UNDECLARED = -124;
        public const int EXI_ERROR_UNEXPECTED_ATTRIBUTE_XSI_TYPE = -125;
        public const int EXI_ERROR_UNEXPECTED_ATTRIBUTE_XSI_NIL = -126;
        public const int EXI_ERROR_UNEXPECTED_GRAMMAR_ID = -127;
        public const int EXI_ERROR_UNEXPECTED_ATTRIBUTE_MOVE_TO_CONTENT_RULE = -128;

        // Unsupported features
        public const int EXI_UNSUPPORTED_NBIT_INTEGER_LENGTH = -132;
        public const int EXI_UNSUPPORTED_EVENT_CODE_CHARACTERISTICS = -133;
        public const int EXI_UNSUPPORTED_INTEGER_VALUE = -134;
        public const int EXI_NEGATIVE_UNSIGNED_INTEGER_VALUE = -135;
        public const int EXI_UNSUPPORTED_LIST_VALUE_TYPE = -136;
        public const int EXI_UNSUPPORTED_HEADER_COOKIE = -137;
        public const int EXI_UNSUPPORTED_HEADER_OPTIONS = -138;
        public const int EXI_UNSUPPORTED_GLOBAL_ATTRIBUTE_VALUE_TYPE = -139;
        public const int EXI_UNSUPPORTED_DATATYPE = -140;
        public const int EXI_UNSUPPORTED_STRING_VALUE_TYPE = -141;
        public const int EXI_UNSUPPORTED_INTEGER_VALUE_TYPE = -142;
        public const int EXI_UNSUPPORTED_DATETIME_TYPE = -143;
        public const int EXI_UNSUPPORTED_FRAGMENT_ELEMENT = -144;
        public const int EXI_UNSUPPORTED_GRAMMAR_LEARNING_CH = -150;

        // String values errors
        public const int EXI_ERROR_STRINGVALUES_NOT_SUPPORTED = -160;
        public const int EXI_ERROR_STRINGVALUES_OUT_OF_ENTRIES = -161;
        public const int EXI_ERROR_STRINGVALUES_OUT_OF_MEMORY = -162;
        public const int EXI_ERROR_STRINGVALUES_OUT_OF_BOUND = -163;
        public const int EXI_ERROR_STRINGVALUES_CHARACTER = -164;

        // Value errors
        public const int EXI_ERROR_UNEXPECTED_BYTE_VALUE = -200;

        // Conversion errors
        public const int EXI_ERROR_CONVERSION_NO_ASCII_CHARACTERS = -300;
        public const int EXI_ERROR_CONVERSION_TYPE_TO_STRING = -301;

        // Support errors
        public const int EXI_DEVIANT_SUPPORT_NOT_DEPLOYED = -500;
    }

    /// <summary>
    /// EXI Exception for error handling
    /// </summary>
    public class EXIException : Exception
    {
        public int ErrorCode { get; }

        public EXIException(int errorCode) : base(GetErrorMessage(errorCode))
        {
            ErrorCode = errorCode;
        }

        public EXIException(int errorCode, string message) : base(message)
        {
            ErrorCode = errorCode;
        }

        public EXIException(int errorCode, string message, Exception innerException) 
            : base(message, innerException)
        {
            ErrorCode = errorCode;
        }

        private static string GetErrorMessage(int errorCode)
        {
            return errorCode switch
            {
                EXIErrorCodes.EXI_ERROR_INPUT_STREAM_EOF => "Input stream EOF",
                EXIErrorCodes.EXI_ERROR_OUTPUT_STREAM_EOF => "Output stream EOF",
                EXIErrorCodes.EXI_ERROR_OUT_OF_BOUNDS => "Out of bounds",
                EXIErrorCodes.EXI_ERROR_OUT_OF_STRING_BUFFER => "Out of string buffer",
                EXIErrorCodes.EXI_ERROR_OUT_OF_BYTE_BUFFER => "Out of byte buffer",
                EXIErrorCodes.EXI_ERROR_UNKOWN_GRAMMAR_ID => "Unknown grammar ID",
                EXIErrorCodes.EXI_ERROR_UNKOWN_EVENT => "Unknown event",
                EXIErrorCodes.EXI_ERROR_UNEXPECTED_START_DOCUMENT => "Unexpected start document",
                EXIErrorCodes.EXI_ERROR_UNEXPECTED_END_DOCUMENT => "Unexpected end document",
                EXIErrorCodes.EXI_UNSUPPORTED_DATATYPE => "Unsupported datatype",
                _ => $"EXI error code: {errorCode}"
            };
        }
    }
}