// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/// A wrapper around BlockDevice that adds helper methods for navigating a
/// BlobFS filesystem.
use crate::bit_vector::*;
use crate::block_device::*;
use crate::errors::*;
use crate::structs::*;
use crate::utils::*;

use core::mem;

pub struct BlobDevice<'a> {
    pub bd: &'a mut dyn BlockDevice,
}

impl<'a> BlobDevice<'a> {
    const MAGIC_0: u64 = 0xac2153479e694d21;
    const MAGIC_1: u64 = 0x985000d4d4d3d314;

    pub fn new(bd: &'a mut dyn BlockDevice) -> Self {
        return BlobDevice { bd: bd };
    }

    pub fn sanity_check(&self) -> Result<(), BFSErr> {
        return Ok(());
    }

    /// Base address fetchers

    pub fn superblock_base(&self) -> usize {
        return self.bd.geom().block_size * 0;
    }

    pub fn blockmap_base(&self) -> usize {
        return self.bd.geom().block_size * 1;
    }

    pub fn nodemap_base(&self) -> usize {
        return self.bd.geom().block_size * 2;
    }

    pub fn journal_base(&self) -> usize {
        return self.bd.geom().block_size * 3;
    }

    pub fn block_base(&self) -> usize {
        return self.bd.geom().block_size * 4;
    }

    /// Format a whole device to support BlobFS.

    pub fn format(&mut self) -> Result<(), BFSErr> {
        // Erase the whole device.
        for i in 0..self.bd.geom().block_count {
            self.bd.erase_block(i)?;
        }

        // Write the initial superblock.
        self.format_superblock()?;

        // Write the initial blockmap.
        self.format_blockmap()?;

        return Ok(());
    }

    pub fn read_superblock(&self, superblock: &mut Superblock) -> Result<(), BFSErr> {
        let blob = as_unsafe_blob_mut(superblock);
        self.bd.read_range(0, blob)?;

        // Sanity check the superblock
        dcheck!(superblock.magic0 == BlobDevice::MAGIC_0, BFSErr::Corrupt);
        dcheck!(superblock.magic1 == BlobDevice::MAGIC_1, BFSErr::Corrupt);

        return Ok(());
    }

    pub fn write_superblock(&mut self, superblock: &Superblock) -> Result<(), BFSErr> {
        // Sanity check the superblock
        dcheck!(superblock.magic0 == BlobDevice::MAGIC_0, BFSErr::Corrupt);
        dcheck!(superblock.magic1 == BlobDevice::MAGIC_1, BFSErr::Corrupt);

        let blob = as_unsafe_blob(superblock);
        self.bd.write_range(0, blob)?;
        return Ok(());
    }

    pub fn format_superblock(&mut self) -> Result<(), BFSErr> {
        let block_size = self.bd.geom().block_size;
        let block_count = self.bd.geom().block_count;

        let superblock_count = 1;
        let bitmap_block_count = 1;
        let node_block_count = 1;
        let journal_block_count = 1;
        let data_block_count = block_count
            - superblock_count
            - bitmap_block_count
            - node_block_count
            - journal_block_count;

        let inodes_per_block = block_size / mem::size_of::<Inode>();

        // Write the superblock to offset 0
        let superblock = Superblock {
            magic0: BlobDevice::MAGIC_0,
            magic1: BlobDevice::MAGIC_1,
            version: 0,
            flags: 0,
            block_size: block_size as u32,
            unused: 0,
            data_block_count: data_block_count as u64,
            journal_block_count: journal_block_count as u64,
            inode_count: inodes_per_block as u64,
            alloc_block_count: 0,
            alloc_inode_count: 0,
        };
        self.write_superblock(&superblock)?;
        return Ok(());
    }

    pub fn format_blockmap(&mut self) -> Result<(), BFSErr> {
        let bits: [u8; 1] = [0xF0];
        self.bd.write_range(self.blockmap_base(), &bits)?;
        return Ok(());
    }

    pub fn read_blockmap(&self, bitmap: &mut BitVector) -> Result<(), BFSErr> {
        self.bd
            .read_range(self.blockmap_base(), slice_as_unsafe_blob_mut(bitmap.bits))?;
        return Ok(());
    }

    pub fn write_blockmap(&mut self, bitmap: &mut BitVector) -> Result<(), BFSErr> {
        self.bd
            .write_range(self.blockmap_base(), slice_as_unsafe_blob(bitmap.bits))?;
        return Ok(());
    }

    pub fn read_node_header(&self, index: usize, node: &mut NodeHeader) -> Result<(), BFSErr> {
        let base = self.nodemap_base();
        let offset = index * mem::size_of::<Inode>() * index;
        let blob = as_unsafe_blob_mut(node);
        self.bd.read_range(base + offset, blob)?;
        return Ok(());
    }

    pub fn read_inode(&self, index: usize, inode: &mut Inode) -> Result<(), BFSErr> {
        let base = self.nodemap_base();
        let offset = index * mem::size_of::<Inode>();
        let blob = as_unsafe_blob_mut(inode);
        self.bd.read_range(base + offset, blob)?;
        return Ok(());
    }

    pub fn write_inode(&mut self, index: usize, inode: &Inode) -> Result<(), BFSErr> {
        dcheck!(
            (inode.header.flags & NodeHeader::FLAG_INODE) != 0,
            BFSErr::InvalidArg
        );
        let base = self.nodemap_base();
        let offset = index * mem::size_of::<Inode>();
        let blob = as_unsafe_blob(inode);
        self.bd.write_range(base + offset, blob)?;
        return Ok(());
    }

    /// Invalidate an inode by zeroing out its header. The inode cannot be reused
    /// until the block containing it is erased.
    pub fn invalidate_inode(&mut self, index: usize) -> Result<(), BFSErr> {
        let base = self.nodemap_base();
        let offset = index * mem::size_of::<Inode>();
        let blob = [0; mem::size_of::<NodeHeader>()];
        self.bd.overwrite_range(base + offset, &blob)?;
        return Ok(());
    }

    pub fn blob_size_in_blocks(&self, blob: &[u8]) -> u16 {
        let block_size = self.bd.geom().block_size;
        let result = (blob.len() + block_size + 1) / block_size;
        assert!(result < u16::MAX as usize);
        return result as u16;
    }

    pub fn read_blob(&self, extent: Extent, blob_out: &mut [u8]) -> Result<(), BFSErr> {
        let block_size = self.bd.geom().block_size;
        let mut cursor = extent.offset();
        for chunk in blob_out.chunks_mut(block_size) {
            self.bd.read_block(cursor, chunk)?;
            cursor = cursor + 1;
        }
        return Ok(());
    }

    pub fn write_blob(&mut self, extent: Extent, blob_in: &[u8]) -> Result<(), BFSErr> {
        let block_size = self.bd.geom().block_size;
        let mut cursor = extent.offset();
        for chunk in blob_in.chunks(block_size) {
            self.bd.write_block(cursor, &chunk)?;
            cursor = cursor + 1;
        }
        return Ok(());
    }

    pub fn delete_blob(&mut self, extent: Extent) -> Result<(), BFSErr> {
        let offset = extent.offset();
        for i in 0..extent.size as usize {
            self.bd.erase_block(offset + i)?;
        }
        return Ok(());
    }
}
