/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use std::rc::Rc;

use dom_struct::dom_struct;
use encoding_rs::Encoding;
use js::conversions::{FromJSValConvertible, ToJSValConvertible};
use js::jsval::UndefinedValue;
use js::rust::{HandleObject as SafeHandleObject, HandleValue as SafeHandleValue};

use crate::DomTypes;
use crate::dom::bindings::codegen::Bindings::TextDecoderBinding;
use crate::dom::bindings::codegen::Bindings::TextDecoderStreamBinding::TextDecoderStreamMethods;
use crate::dom::bindings::codegen::UnionTypes::ArrayBufferViewOrArrayBuffer;
use crate::dom::bindings::error::{Error, Fallible};
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object_with_proto};
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::DOMString;
use crate::dom::globalscope::GlobalScope;
use crate::dom::textdecodercommon::TextDecoderCommon;
use crate::dom::transformstreamdefaultcontroller::TransformerType;
use crate::dom::types::{TransformStream, TransformStreamDefaultController};
use crate::script_runtime::{CanGc, JSContext as SafeJSContext};

/// <https://encoding.spec.whatwg.org/#decode-and-enqueue-a-chunk>
#[allow(unsafe_code)]
pub(crate) fn decode_and_enqueue_a_chunk(
    cx: SafeJSContext,
    global: &GlobalScope,
    chunk: SafeHandleValue,
    decoder: &TextDecoderCommon,
    controller: &TransformStreamDefaultController,
    can_gc: CanGc,
) -> Fallible<()> {
    // Step 1. Let bufferSource be the result of converting chunk to an AllowSharedBufferSource.
    let conversion_result = unsafe {
        ArrayBufferViewOrArrayBuffer::from_jsval(*cx, chunk, ()).map_err(|_| {
            Error::Type("Unable to convert chunk into ArrayBuffer or ArrayBufferView".to_string())
        })?
    };
    let buffer_source = conversion_result.get_success_value().ok_or_else(|| {
        Error::Type("Unable to convert chunk into ArrayBuffer or ArrayBufferView".to_string())
    })?;

    // Step 2. Push a copy of bufferSource to decoder’s I/O queue.
    // Step 3. Let output be the I/O queue of scalar values « end-of-queue ».
    // Step 4. While true:
    // Step 4.1 Let item be the result of reading from decoder’s I/O queue.
    // Step 4.2 If item is end-of-queue:
    // Step 4.2.1 Let outputChunk be the result of running serialize I/O queue with decoder and output.
    // Step 4.2.3 Return.
    // Step 4.3 Let result be the result of processing an item with item, decoder’s decoder,
    //      decoder’s I/O queue, output, and decoder’s error mode.
    // Step 4.4 If result is error, then throw a TypeError.
    let output_chunk = decoder.decode(Some(buffer_source), false)?;

    // Step 4.2.2 If outputChunk is not the empty string, then enqueue
    //      outputChunk in decoder’s transform.
    if output_chunk.is_empty() {
        return Ok(());
    }
    rooted!(in(*cx) let mut rval = UndefinedValue());
    unsafe { output_chunk.to_jsval(*cx, rval.handle_mut()) };
    controller.enqueue(cx, global, rval.handle(), can_gc)
}

/// <https://encoding.spec.whatwg.org/#flush-and-enqueue>
#[allow(unsafe_code)]
pub(crate) fn flush_and_enqueue(
    cx: SafeJSContext,
    global: &GlobalScope,
    decoder: &TextDecoderCommon,
    controller: &TransformStreamDefaultController,
    can_gc: CanGc,
) -> Fallible<()> {
    // Step 1. Let output be the I/O queue of scalar values « end-of-queue ».
    // Step 2. While true:
    // Step 2.1 Let item be the result of reading from decoder’s I/O queue.
    // Step 2.2 Let result be the result of processing an item with item,
    //      decoder’s decoder, decoder’s I/O queue, output, and decoder’s error mode.
    // Step 2.3 If result is finished:
    // Step 2.3.1 Let outputChunk be the result of running serialize I/O queue
    //      with decoder and output.
    // Step 2.3.3 Return.
    // Step 2.3.4 Otherwise, if result is error, throw a TypeError.
    let output_chunk = decoder.decode(None, true)?;

    // Step 2.3.2 If outputChunk is not the empty string, then enqueue
    //      outputChunk in decoder’s transform.
    if output_chunk.is_empty() {
        return Ok(());
    }
    rooted!(in(*cx) let mut rval = UndefinedValue());
    unsafe { output_chunk.to_jsval(*cx, rval.handle_mut()) };
    controller.enqueue(cx, global, rval.handle(), can_gc)
}

/// <https://encoding.spec.whatwg.org/#textdecoderstream>
#[dom_struct]
pub(crate) struct TextDecoderStream {
    reflector_: Reflector,

    /// <https://encoding.spec.whatwg.org/#textdecodercommon>
    #[ignore_malloc_size_of = "Rc is hard"]
    decoder: Rc<TextDecoderCommon>,

    /// <https://streams.spec.whatwg.org/#generictransformstream>
    transform: Dom<TransformStream>,
}

#[allow(non_snake_case)]
impl TextDecoderStream {
    fn new_inherited(
        decoder: Rc<TextDecoderCommon>,
        transform: &TransformStream,
    ) -> TextDecoderStream {
        TextDecoderStream {
            reflector_: Reflector::new(),
            decoder,
            transform: Dom::from_ref(transform),
        }
    }

    fn new_with_proto(
        cx: SafeJSContext,
        global: &GlobalScope,
        proto: Option<SafeHandleObject>,
        encoding: &'static Encoding,
        fatal: bool,
        ignoreBOM: bool,
        can_gc: CanGc,
    ) -> Fallible<DomRoot<Self>> {
        let decoder = Rc::new(TextDecoderCommon::new_inherited(encoding, fatal, ignoreBOM));
        let transformer_type = TransformerType::Decoder(decoder.clone());

        let transform_stream = TransformStream::new_with_proto(global, None, can_gc);
        transform_stream.set_up(cx, global, transformer_type, can_gc)?;

        Ok(reflect_dom_object_with_proto(
            Box::new(TextDecoderStream::new_inherited(decoder, &transform_stream)),
            global,
            proto,
            can_gc,
        ))
    }
}

#[allow(non_snake_case)]
impl TextDecoderStreamMethods<crate::DomTypeHolder> for TextDecoderStream {
    /// <https://encoding.spec.whatwg.org/#dom-textdecoderstream>
    fn Constructor(
        global: &GlobalScope,
        proto: Option<SafeHandleObject>,
        can_gc: CanGc,
        label: DOMString,
        options: &TextDecoderBinding::TextDecoderOptions,
    ) -> Fallible<DomRoot<TextDecoderStream>> {
        let encoding = match Encoding::for_label_no_replacement(label.as_bytes()) {
            Some(enc) => enc,
            None => {
                return Err(Error::Range(
                    "The given encoding is not supported".to_owned(),
                ));
            },
        };

        Self::new_with_proto(
            GlobalScope::get_cx(),
            global,
            proto,
            encoding,
            options.fatal,
            options.ignoreBOM,
            can_gc,
        )
    }

    /// <https://encoding.spec.whatwg.org/#dom-textdecoder-encoding>
    fn Encoding(&self) -> DOMString {
        DOMString::from(self.decoder.encoding().name().to_ascii_lowercase())
    }

    /// <https://encoding.spec.whatwg.org/#dom-textdecoder-fatal>
    fn Fatal(&self) -> bool {
        self.decoder.fatal()
    }

    /// <https://encoding.spec.whatwg.org/#dom-textdecoder-ignorebom>
    fn IgnoreBOM(&self) -> bool {
        self.decoder.ignore_bom()
    }

    /// <https://streams.spec.whatwg.org/#dom-generictransformstream-readable>
    fn Readable(&self) -> DomRoot<<crate::DomTypeHolder as DomTypes>::ReadableStream> {
        self.transform.get_readable()
    }

    /// <https://streams.spec.whatwg.org/#dom-generictransformstream-writable>
    fn Writable(&self) -> DomRoot<<crate::DomTypeHolder as DomTypes>::WritableStream> {
        self.transform.get_writable()
    }
}
