// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use failure::{format_err, Error};
use fidl_fuchsia_images as images;
use fuchsia_scenic as scenic;
use fuchsia_wayland_core as wl;
use std::rc::Rc;
use wayland::*;

use crate::client::Client;
use crate::object::{NewObjectExt, ObjectRef, RequestReceiver};

/// The set of pixel formats that will be announced to clients.
const SUPPORTED_PIXEL_FORMATS: &[wl_shm::Format] =
    &[wl_shm::Format::Argb8888, wl_shm::Format::Xrgb8888];

/// Converts a wayland pixel format to the Fuchsia counterpart.
///
/// Returns `None` if the format is not supported.
fn pixel_format_wl_to_fuchsia(wl_format: wl_shm::Format) -> Option<images::PixelFormat> {
    match wl_format {
        wl_shm::Format::Argb8888 | wl_shm::Format::Xrgb8888 => Some(images::PixelFormat::Bgra8),
        _ => None,
    }
}

/// The wl_shm global.
pub struct Shm {
    scenic: scenic::SessionPtr,
}

impl Shm {
    /// Creates a new `Shm`.
    pub fn new(scenic: scenic::SessionPtr) -> Self {
        Shm { scenic }
    }

    /// Posts an event back to the client for each supported SHM pixel format.
    pub fn post_formats(&self, this: wl::ObjectId, client: &Client) -> Result<(), Error> {
        for format in SUPPORTED_PIXEL_FORMATS.iter() {
            client.post(this, WlShmEvent::Format { format: *format })?;
        }
        Ok(())
    }
}

impl RequestReceiver<WlShm> for Shm {
    fn receive(
        this: ObjectRef<Self>, request: WlShmRequest, client: &mut Client,
    ) -> Result<(), Error> {
        let WlShmRequest::CreatePool { id, fd, size } = request;
        let scenic = this.get(client)?.scenic.clone();
        let memory = scenic::Memory::new(
            scenic.clone(),
            fd.into(),
            size as u64,
            images::MemoryType::HostMemory,
        );
        id.implement(
            client,
            ShmPool {
                memory: Rc::new(memory),
                _size: size,
            },
        )?;
        Ok(())
    }
}

pub struct ShmPool {
    /// The scenic memory object that wraps the VMO handle sent from the
    /// client.
    memory: Rc<scenic::Memory>,

    /// The size of `memory`, in bytes.
    _size: i32,
}

impl ShmPool {
    /// Creates a new wl_buffer object backed by memory from this wl_shm_pool.
    ///
    /// It's possible for the resultant wl_buffer to outlive this pool, so the
    /// buffer must hold a strong reference to any resources it depends on
    /// post-creation.
    pub fn create_buffer(
        this: ObjectRef<Self>, client: &mut Client, offset: u32, width: i32, height: i32,
        stride: i32, format: wl_shm::Format,
    ) -> Result<Buffer, Error> {
        // TODO(tjdetwiler): Support sending the protocol-modeled errors,
        // ex: wl_shm::Error::InvalidFormat.
        let format = pixel_format_wl_to_fuchsia(format)
            .ok_or_else(|| format_err!("Invalid pixel format {:?}", format))?;

        let image_info = images::ImageInfo {
            width: width as u32,
            height: height as u32,
            stride: stride as u32,
            pixel_format: format,
            transform: images::Transform::Normal,
            color_space: images::ColorSpace::Srgb,
            tiling: images::Tiling::Linear,
            alpha_format: images::AlphaFormat::Opaque,
        };
        let this = this.get(client)?;
        Ok(Buffer {
            memory: this.memory.clone(),
            offset,
            image_info,
        })
    }
}

impl RequestReceiver<WlShmPool> for ShmPool {
    fn receive(
        this: ObjectRef<Self>, request: WlShmPoolRequest, client: &mut Client,
    ) -> Result<(), Error> {
        match request {
            WlShmPoolRequest::Destroy => {
                client.delete_id(this.id())?;
            }
            WlShmPoolRequest::CreateBuffer {
                id,
                offset,
                width,
                height,
                stride,
                format,
            } => {
                if offset < 0 {
                    return Err(format_err!(
                        "Negative buffer offset not supported: {}",
                        offset
                    ));
                }
                let offset = offset as u32;

                let buffer = Self::create_buffer(
                    this,
                    client,
                    offset,
                    width,
                    height,
                    stride,
                    format.as_enum()?,
                )?;
                id.implement(client, buffer)?;
            }
            WlShmPoolRequest::Resize { .. } => {}
        }
        Ok(())
    }
}

/// An implementation of 'wl_buffer'.
pub struct Buffer {
    /// The scenic `Memory` object that will back this buffer.
    memory: Rc<scenic::Memory>,
    /// The offest into `memory` that this image is located.
    offset: u32,
    /// Additional description of the format of the buffer needed to draw the
    /// image correctly.
    image_info: images::ImageInfo,
}

/// Allow this to be `Clone` so that surfaces can keep the underlying
/// `scenic::Memory` alive even if the buffer protocol object has been released.
impl Clone for Buffer {
    fn clone(&self) -> Self {
        Buffer {
            memory: self.memory.clone(),
            offset: self.offset,
            image_info: images::ImageInfo { ..self.image_info },
        }
    }
}

impl Buffer {
    pub fn image_info(&self) -> &images::ImageInfo {
        &self.image_info
    }

    /// Create a new scenic `Image` for this buffer. This entity must be
    /// recreated after each change to the backing `Memory` in order for scenic
    /// to present any changes to the `Memory` since it was last presented.
    pub fn create_image(&self) -> scenic::Image {
        let image_info = images::ImageInfo { ..self.image_info };
        scenic::Image::new(&*self.memory, self.offset, image_info)
    }
}

impl RequestReceiver<WlBuffer> for Buffer {
    fn receive(
        this: ObjectRef<Self>, request: WlBufferRequest, client: &mut Client,
    ) -> Result<(), Error> {
        let WlBufferRequest::Destroy = request;
        client.delete_id(this.id())?;
        Ok(())
    }
}
