//! Defines the [PdfiumError] enum, used to wrap Pdfium errors as `Err` values.

use crate::bindgen::{
    FPDF_ERR_FILE, FPDF_ERR_FORMAT, FPDF_ERR_PAGE, FPDF_ERR_PASSWORD, FPDF_ERR_SECURITY,
    FPDF_ERR_UNKNOWN,
};
use std::error::Error;
use std::ffi::IntoStringError;
use std::fmt::{Display, Formatter, Result};
use std::num::ParseIntError;

#[cfg(target_arch = "wasm32")]
use wasm_bindgen::JsValue;

/// A wrapped internal library error from Pdfium's `FPDF_ERR_*` constant values.
///
/// Pdfium only provides detailed internal error information for document loading functions.
/// All other functions in the Pdfium API return a value indicating success or failure,
/// but otherwise detailed error information for failed API calls is not available. In these
/// cases, an error value of [PdfiumInternalError::Unknown] will be returned.
// For more information, see: https://github.com/ajrcarey/pdfium-render/issues/78
#[derive(Debug)]
pub enum PdfiumInternalError {
    /// The document could not be loaded due to a file system error.
    FileError = FPDF_ERR_FILE as isize,

    /// The document could not be loaded due to a format parsing error.
    FormatError = FPDF_ERR_FORMAT as isize,

    /// The document could not be loaded because the wrong password was supplied.
    PasswordError = FPDF_ERR_PASSWORD as isize,

    /// The document could not be loaded because of the document's security settings.
    SecurityError = FPDF_ERR_SECURITY as isize,

    /// The page could not be loaded due to an internal error.
    PageError = FPDF_ERR_PAGE as isize,

    /// A generic error value returned in all other unhandled situations.
    Unknown = FPDF_ERR_UNKNOWN as isize,
}

#[derive(Debug)]
pub enum PdfiumError {
    /// The Pdfium WASM module has not been configured.
    /// It is essential that the exported `initialize_pdfium_render()` function be called
    /// from Javascript _before_ calling any `pdfium-render` function from within your Rust code.
    /// See: <https://github.com/ajrcarey/pdfium-render/blob/master/examples/index.html>
    #[cfg(target_arch = "wasm32")]
    PdfiumWASMModuleNotConfigured,

    /// The external Pdfium library could not be loaded.
    #[cfg(not(target_arch = "wasm32"))]
    LoadLibraryError(libloading::Error),

    UnrecognizedPath,
    PageIndexOutOfBounds,
    LinkIndexOutOfBounds,
    UnknownBitmapFormat,
    UnknownBitmapRotation,
    UnknownFormType,
    UnknownFormFieldType,
    UnknownActionType,
    UnknownAppearanceMode,
    PageObjectIndexOutOfBounds,
    PageObjectNotAttachedToPage,
    PageObjectAlreadyAttachedToDifferentPage,
    PageAnnotationIndexOutOfBounds,
    PageObjectNotAttachedToAnnotation,
    FormFieldOptionIndexOutOfBounds,
    PageFlattenFailure,
    PageMissingEmbeddedThumbnail,
    UnknownPdfPageObjectType,
    UnknownPdfPageTextRenderMode,
    UnknownPdfPagePathFillMode,
    UnknownPdfAnnotationType,
    UnknownPdfDestinationViewType,
    UnknownPdfSecurityHandlerRevision,
    UnsupportedPdfPageObjectType,
    TextSegmentIndexOutOfBounds,
    CharIndexOutOfBounds,
    NoCharsInPageObject,
    NoCharsInAnnotation,
    NoCharsInRect,
    ImageObjectFilterIndexOutOfBounds,
    ImageObjectFilterIndexInBoundsButFilterUndefined,
    UnknownPdfColorSpace,
    InvalidTransformationMatrix,
    SignatureIndexOutOfBounds,
    AttachmentIndexOutOfBounds,
    NoDataInAttachment,
    FontGlyphIndexOutOfBounds,
    UnknownPathSegmentType,
    NoPagesInDocument,
    NoPageObjectsInCollection,
    NoPageLinksInCollection,
    NoAnnotationsInCollection,
    PageObjectNotCopyable,
    ImageObjectFiltersNotCopyable,
    PathObjectBezierControlPointsNotCopyable,
    PathObjectUnknownSegmentTypeNotCopyable,
    GroupContainsNonCopyablePageObjects,
    SourcePageIndexNotInCache,
    NoUriForAction,
    DestinationPageIndexNotAvailable,
    DestinationPageLocationNotAvailable,
    PageAnnotationAttachmentPointIndexOutOfBounds,
    NoAttachmentPointsInPageAnnotation,
    CoordinateConversionFunctionIndicatedError,

    /// A call to `FPDFDest_GetView()` returned a valid FPDFDEST_VIEW_* value, but the number
    /// of view parameters returned does not match the PDF specification.
    PdfDestinationViewInvalidParameters,

    /// A [ParseIntError] occurred while attempting to parse a `PdfColor` from a hexadecimal string
    /// in `PdfColor::from_hex()`.
    ParseHexadecimalColorError(ParseIntError),

    /// The hexadecimal string given to `PdfColor::from_hex()` was not either exactly 7 or 9
    /// characters long.
    ParseHexadecimalColorUnexpectedLength,

    /// The leading `#` character was not found while attempting to parse a `PdfColor` from
    /// a hexidecimal string in `PdfColor::from_hex()`.
    ParseHexadecimalColorMissingLeadingHash,

    /// An error occurred converting a byte stream into a CString.
    CStringConversionError(IntoStringError),

    /// Two data buffers are expected to have the same size, but they do not.
    DataBufferLengthMismatch,

    /// The setting cannot be returned because this `PdfPageGroupObject` is empty.
    EmptyPageObjectGroup,

    /// A call to a internal Pdfium `FPDF_*` function returned a value indicating failure.
    ///
    /// For Pdfium functions that return enumerations, this means the function returned
    /// a value of -1 rather than a valid enumeration constant.
    ///
    /// For Pdfium functions that return C-style boolean integers, this means that the function
    /// returned a value other than `PdfiumLibraryBindings::TRUE`.
    PdfiumFunctionReturnValueIndicatedFailure,

    /// A call to a Pdfium function that returns a standard 8-bit color component value
    /// (for example, `FPDFPageObj_GetStrokeColor()` and `FPDFPageObj_GetStrokeColor()`)
    /// successfully returned a value, but the value could not be converted from a c_int
    /// to a standard Rust u8.
    UnableToConvertPdfiumColorValueToRustu8(std::num::TryFromIntError),

    /// The browser's built-in `Window` object could not be retrieved.
    WebSysWindowObjectNotAvailable,

    /// A JsValue returned from a function call was set to JsValue::UNDEFINED instead of
    /// a valid value of the expected type.
    #[cfg(target_arch = "wasm32")]
    JsValueUndefined,

    /// An error was returned when attempting to use the browser's built-in `fetch()` API.
    #[cfg(target_arch = "wasm32")]
    WebSysFetchError(JsValue),

    /// An invalid Response object was returned when attempting to use the browser's built-in `fetch()` API.
    #[cfg(target_arch = "wasm32")]
    WebSysInvalidResponseError,

    /// An error was returned when attempting to construct a `Blob` object from a byte buffer.
    #[cfg(target_arch = "wasm32")]
    JsSysErrorConstructingBlobFromBytes,

    /// An error occurred when attempting to retrieve the function table for the compiled
    /// Pdfium WASM module.
    #[cfg(target_arch = "wasm32")]
    JsSysErrorRetrievingFunctionTable(JsValue),

    /// An error occurred when attempting to retrieve an exported function from
    /// `pdfium-render`'s WASM module.
    #[cfg(target_arch = "wasm32")]
    JsSysErrorRetrievingFunction(JsValue),

    /// An error occurred when attempting to update an entry in Pdfium's WASM function table.
    #[cfg(target_arch = "wasm32")]
    JsSysErrorPatchingFunctionTable(JsValue),

    /// No previously cached function was available for a WASM function table restore operation.
    ///
    /// This error should never occur; if it does, it indicates a programming error in pdfium-render.
    /// Please file an issue: https://github.com/ajrcarey/pdfium-render/issues
    #[cfg(target_arch = "wasm32")]
    NoPreviouslyCachedFunctionSet,

    /// An error occurred during an image processing operation.
    ImageError,

    /// Dimensions of `Image::Image` are specified in `u32`, but bitmaps in Pdfium are sized in
    /// `c_int` (`i32`), meaning that an `Image::Image` can have dimensions that overflow
    /// the maximum size of a Pdfium bitmap. As a compromise, Image dimensions in `pdfium-render`
    /// are limited to `u16`.
    ///
    /// This error indicates that an `Image::Image` had a width or height larger than the maximum
    /// `u16` size allowed by `pdfium-render`.
    ImageSizeOutOfBounds,

    /// An I/O error occurred during a Pdfium file operation.
    IoError(std::io::Error),

    /// A wrapped internal library error from Pdfium's `FPDF_ERR_*` constant values.
    PdfiumLibraryInternalError(PdfiumInternalError),
}

impl Display for PdfiumError {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        write!(f, "{:#?}", self)
    }
}

impl Error for PdfiumError {}
