mod errors;

use raw::*;
use texture::*;

mod state;
pub use self::state::*;

mod framebuffer;
pub use self::framebuffer::*;

use std::fmt;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum DefaultFramebufferDrawBuffer {
    None,
    FrontLeft,
    FrontRight,
    BackLeft,
    BackRight,
}

impl From<DefaultFramebufferDrawBuffer> for FramebufferDrawBuffer {
    fn from(draw_buffer: DefaultFramebufferDrawBuffer) -> Self {
        match draw_buffer {
            DefaultFramebufferDrawBuffer::None => FramebufferDrawBuffer::None,
            DefaultFramebufferDrawBuffer::FrontLeft => FramebufferDrawBuffer::FrontLeft,
            DefaultFramebufferDrawBuffer::FrontRight => FramebufferDrawBuffer::FrontRight,
            DefaultFramebufferDrawBuffer::BackLeft => FramebufferDrawBuffer::BackLeft,
            DefaultFramebufferDrawBuffer::BackRight => FramebufferDrawBuffer::BackRight,
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum GeneralFramebufferDrawBuffer {
    None,
    ColorAttachment0,
    ColorAttachment1,
    ColorAttachment2,
    ColorAttachment3,
    ColorAttachment4,
    ColorAttachment5,
    ColorAttachment6,
    ColorAttachment7,
}

impl From<GeneralFramebufferDrawBuffer> for FramebufferDrawBuffer {
    fn from(draw_buffer: GeneralFramebufferDrawBuffer) -> Self {
        match draw_buffer {
            GeneralFramebufferDrawBuffer::None => FramebufferDrawBuffer::None,
            GeneralFramebufferDrawBuffer::ColorAttachment0 => {
                FramebufferDrawBuffer::ColorAttachment0
            }
            GeneralFramebufferDrawBuffer::ColorAttachment1 => {
                FramebufferDrawBuffer::ColorAttachment1
            }
            GeneralFramebufferDrawBuffer::ColorAttachment2 => {
                FramebufferDrawBuffer::ColorAttachment2
            }
            GeneralFramebufferDrawBuffer::ColorAttachment3 => {
                FramebufferDrawBuffer::ColorAttachment3
            }
            GeneralFramebufferDrawBuffer::ColorAttachment4 => {
                FramebufferDrawBuffer::ColorAttachment4
            }
            GeneralFramebufferDrawBuffer::ColorAttachment5 => {
                FramebufferDrawBuffer::ColorAttachment5
            }
            GeneralFramebufferDrawBuffer::ColorAttachment6 => {
                FramebufferDrawBuffer::ColorAttachment6
            }
            GeneralFramebufferDrawBuffer::ColorAttachment7 => {
                FramebufferDrawBuffer::ColorAttachment7
            }
        }
    }
}

pub enum DrawTextureAttachOption<'a> {
    AttachTexture(&'a mut Texture),
    AttachTextureLayer {
        texture: &'a mut Texture,
        level: u32,
        layer: u32,
    },
    None,
    Keep,
}

impl<'a> fmt::Debug for DrawTextureAttachOption<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            DrawTextureAttachOption::AttachTexture(ref texture) => {
                write!(
                    f,
                    "DrawTextureAttachOption {{ TextureId: {:?} }}",
                    texture.get_id()
                )
            }
            DrawTextureAttachOption::AttachTextureLayer {
                ref texture,
                level,
                layer,
            } => {
                write!(
                    f,
                    "DrawTextureAttachOption {{ TextureId: {:?}, level: {}, layer: {} }}",
                    texture.get_id(),
                    level,
                    layer
                )
            }
            DrawTextureAttachOption::None => write!(f, "DrawTextureAttachOption {{ None }}"),
            DrawTextureAttachOption::Keep => write!(f, "DrawTextureAttachOption {{ Keep }}"),
        }
    }
}

impl<'a> Default for DrawTextureAttachOption<'a> {
    fn default() -> DrawTextureAttachOption<'a> {
        DrawTextureAttachOption::None
    }
}

#[derive(Debug)]
pub enum DepthStencilOption<'a> {
    Separate {
        depth: DrawTextureAttachOption<'a>,
        stencil: DrawTextureAttachOption<'a>,
    },
    Together(DrawTextureAttachOption<'a>),
}

impl<'a> Default for DepthStencilOption<'a> {
    fn default() -> DepthStencilOption<'a> {
        DepthStencilOption::Separate {
            depth: DrawTextureAttachOption::None,
            stencil: DrawTextureAttachOption::None,
        }
    }
}

#[derive(Debug, Default)]
pub struct DrawTextureTarget<'a> {
    pub depth_stencil: DepthStencilOption<'a>,
    pub color0: DrawTextureAttachOption<'a>,
    pub color1: DrawTextureAttachOption<'a>,
    pub color2: DrawTextureAttachOption<'a>,
    pub color3: DrawTextureAttachOption<'a>,
    pub color4: DrawTextureAttachOption<'a>,
    pub color5: DrawTextureAttachOption<'a>,
    pub color6: DrawTextureAttachOption<'a>,
    pub color7: DrawTextureAttachOption<'a>,
}

#[derive(Debug)]
pub enum FramebufferRenderTarget<'a> {
    Default,
    General(&'a GeneralFramebuffer, &'a DrawTextureTarget<'a>),
}
