/*
 * Copyright (C) 2016 Google, Inc.
 *
 * 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
 *
 *     http://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.
 */

#include <cassert>
#include <cmath>
#include <cstring>
#include <array>
#include <unordered_map>

#include "Helpers.h"
#include "Meshes.h"

namespace {

class Mesh {
   public:
    struct Position {
        float x;
        float y;
        float z;
    };

    struct Normal {
        float x;
        float y;
        float z;
    };

    struct Face {
        int v0;
        int v1;
        int v2;
    };

    static uint32_t vertex_stride() {
        // Position + Normal
        const int comp_count = 6;

        return sizeof(float) * comp_count;
    }

    static VkVertexInputBindingDescription vertex_input_binding() {
        VkVertexInputBindingDescription vi_binding = {};
        vi_binding.binding = 0;
        vi_binding.stride = vertex_stride();
        vi_binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;

        return vi_binding;
    }

    static std::vector<VkVertexInputAttributeDescription> vertex_input_attributes() {
        std::vector<VkVertexInputAttributeDescription> vi_attrs(2);
        // Position
        vi_attrs[0].location = 0;
        vi_attrs[0].binding = 0;
        vi_attrs[0].format = VK_FORMAT_R32G32B32_SFLOAT;
        vi_attrs[0].offset = 0;
        // Normal
        vi_attrs[1].location = 1;
        vi_attrs[1].binding = 0;
        vi_attrs[1].format = VK_FORMAT_R32G32B32_SFLOAT;
        vi_attrs[1].offset = sizeof(float) * 3;

        return vi_attrs;
    }

    static VkIndexType index_type() { return VK_INDEX_TYPE_UINT32; }

    static VkPipelineInputAssemblyStateCreateInfo input_assembly_state() {
        VkPipelineInputAssemblyStateCreateInfo ia_info = {};
        ia_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
        ia_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
        ia_info.primitiveRestartEnable = false;
        return ia_info;
    }

    void build(const std::vector<std::array<float, 6>> &vertices, const std::vector<std::array<int, 3>> &faces) {
        positions_.reserve(vertices.size());
        normals_.reserve(vertices.size());
        for (const auto &v : vertices) {
            positions_.emplace_back(Position{v[0], v[1], v[2]});
            normals_.emplace_back(Normal{v[3], v[4], v[5]});
        }

        faces_.reserve(faces.size());
        for (const auto &f : faces) faces_.emplace_back(Face{f[0], f[1], f[2]});
    }

    uint32_t vertex_count() const { return static_cast<uint32_t>(positions_.size()); }

    VkDeviceSize vertex_buffer_size() const { return vertex_stride() * vertex_count(); }

    void vertex_buffer_write(void *data) const {
        float *dst = reinterpret_cast<float *>(data);
        for (size_t i = 0; i < positions_.size(); i++) {
            const Position &pos = positions_[i];
            const Normal &normal = normals_[i];
            dst[0] = pos.x;
            dst[1] = pos.y;
            dst[2] = pos.z;
            dst[3] = normal.x;
            dst[4] = normal.y;
            dst[5] = normal.z;
            dst += 6;
        }
    }

    uint32_t index_count() const { return static_cast<uint32_t>(faces_.size()) * 3; }

    VkDeviceSize index_buffer_size() const { return sizeof(uint32_t) * index_count(); }

    void index_buffer_write(void *data) const {
        uint32_t *dst = reinterpret_cast<uint32_t *>(data);
        for (const auto &face : faces_) {
            dst[0] = face.v0;
            dst[1] = face.v1;
            dst[2] = face.v2;
            dst += 3;
        }
    }

    std::vector<Position> positions_;
    std::vector<Normal> normals_;
    std::vector<Face> faces_;
};

class BuildPyramid {
   public:
    BuildPyramid(Mesh &mesh) {
        const std::vector<std::array<float, 6>> vertices = {
            //      position                normal
            {{0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f}},     {{-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f}},
            {{1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f}}, {{1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f}},
            {{-1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f}},
        };

        const std::vector<std::array<int, 3>> faces = {
            {{0, 1, 2}}, {{0, 2, 3}}, {{0, 3, 4}}, {{0, 4, 1}}, {{1, 4, 3}}, {{1, 3, 2}},
        };

        mesh.build(vertices, faces);
    }
};

class BuildIcosphere {
   public:
    BuildIcosphere(Mesh &mesh) : mesh_(mesh), radius_(1.0f) {
        const int tessellate_level = 2;

        build_icosahedron();
        for (int i = 0; i < tessellate_level; i++) tessellate();
    }

   private:
    void build_icosahedron() {
        // https://en.wikipedia.org/wiki/Regular_icosahedron
        const float l1 = std::sqrt(2.0f / (5.0f + std::sqrt(5.0f))) * radius_;
        const float l2 = std::sqrt(2.0f / (5.0f - std::sqrt(5.0f))) * radius_;
        // vertices are from three golden rectangles
        const std::vector<std::array<float, 6>> icosahedron_vertices = {
            //   position           normal
            {{
                -l1, -l2, 0.0f, -l1, -l2, 0.0f,
            }},
            {{
                l1, -l2, 0.0f, l1, -l2, 0.0f,
            }},
            {{
                l1, l2, 0.0f, l1, l2, 0.0f,
            }},
            {{
                -l1, l2, 0.0f, -l1, l2, 0.0f,
            }},

            {{
                -l2, 0.0f, -l1, -l2, 0.0f, -l1,
            }},
            {{
                l2, 0.0f, -l1, l2, 0.0f, -l1,
            }},
            {{
                l2, 0.0f, l1, l2, 0.0f, l1,
            }},
            {{
                -l2, 0.0f, l1, -l2, 0.0f, l1,
            }},

            {{
                0.0f, -l1, -l2, 0.0f, -l1, -l2,
            }},
            {{
                0.0f, l1, -l2, 0.0f, l1, -l2,
            }},
            {{
                0.0f, l1, l2, 0.0f, l1, l2,
            }},
            {{
                0.0f, -l1, l2, 0.0f, -l1, l2,
            }},
        };
        const std::vector<std::array<int, 3>> icosahedron_faces = {
            // triangles sharing vertex 0
            {{0, 1, 11}},
            {{0, 11, 7}},
            {{0, 7, 4}},
            {{0, 4, 8}},
            {{0, 8, 1}},
            // adjacent triangles
            {{11, 1, 6}},
            {{7, 11, 10}},
            {{4, 7, 3}},
            {{8, 4, 9}},
            {{1, 8, 5}},
            // triangles sharing vertex 2
            {{2, 3, 10}},
            {{2, 10, 6}},
            {{2, 6, 5}},
            {{2, 5, 9}},
            {{2, 9, 3}},
            // adjacent triangles
            {{10, 3, 7}},
            {{6, 10, 11}},
            {{5, 6, 1}},
            {{9, 5, 8}},
            {{3, 9, 4}},
        };

        mesh_.build(icosahedron_vertices, icosahedron_faces);
    }

    void tessellate() {
        size_t middle_point_count = mesh_.faces_.size() * 3 / 2;
        size_t final_face_count = mesh_.faces_.size() * 4;

        std::vector<Mesh::Face> faces;
        faces.reserve(final_face_count);

        middle_points_.clear();
        middle_points_.reserve(middle_point_count);

        mesh_.positions_.reserve(mesh_.vertex_count() + middle_point_count);
        mesh_.normals_.reserve(mesh_.vertex_count() + middle_point_count);

        for (const auto &f : mesh_.faces_) {
            int v0 = f.v0;
            int v1 = f.v1;
            int v2 = f.v2;

            int v01 = add_middle_point(v0, v1);
            int v12 = add_middle_point(v1, v2);
            int v20 = add_middle_point(v2, v0);

            faces.emplace_back(Mesh::Face{v0, v01, v20});
            faces.emplace_back(Mesh::Face{v1, v12, v01});
            faces.emplace_back(Mesh::Face{v2, v20, v12});
            faces.emplace_back(Mesh::Face{v01, v12, v20});
        }

        mesh_.faces_.swap(faces);
    }

    int add_middle_point(int a, int b) {
        uint64_t key = (a < b) ? ((uint64_t)a << 32 | b) : ((uint64_t)b << 32 | a);
        auto it = middle_points_.find(key);
        if (it != middle_points_.end()) return it->second;

        const Mesh::Position &pos_a = mesh_.positions_[a];
        const Mesh::Position &pos_b = mesh_.positions_[b];
        Mesh::Position pos_mid = {
            (pos_a.x + pos_b.x) / 2.0f, (pos_a.y + pos_b.y) / 2.0f, (pos_a.z + pos_b.z) / 2.0f,
        };
        float scale = radius_ / std::sqrt(pos_mid.x * pos_mid.x + pos_mid.y * pos_mid.y + pos_mid.z * pos_mid.z);
        pos_mid.x *= scale;
        pos_mid.y *= scale;
        pos_mid.z *= scale;

        Mesh::Normal normal_mid = {pos_mid.x, pos_mid.y, pos_mid.z};
        normal_mid.x /= radius_;
        normal_mid.y /= radius_;
        normal_mid.z /= radius_;

        mesh_.positions_.emplace_back(pos_mid);
        mesh_.normals_.emplace_back(normal_mid);

        int mid = mesh_.vertex_count() - 1;
        middle_points_.emplace(std::make_pair(key, mid));

        return mid;
    }

    Mesh &mesh_;
    const float radius_;
    std::unordered_map<uint64_t, uint32_t> middle_points_;
};

class BuildTeapot {
   public:
    BuildTeapot(Mesh &mesh) {
#include "Meshes.teapot.h"
        const int position_count = sizeof(teapot_positions) / sizeof(teapot_positions[0]);
        const int index_count = sizeof(teapot_indices) / sizeof(teapot_indices[0]);
        assert(position_count % 3 == 0 && index_count % 3 == 0);

        Mesh::Position translate;
        float scale;
        get_transform(teapot_positions, position_count, translate, scale);

        for (int i = 0; i < position_count; i += 3) {
            mesh.positions_.emplace_back(Mesh::Position{
                (teapot_positions[i + 0] + translate.x) * scale, (teapot_positions[i + 1] + translate.y) * scale,
                (teapot_positions[i + 2] + translate.z) * scale,
            });

            mesh.normals_.emplace_back(Mesh::Normal{
                teapot_normals[i + 0], teapot_normals[i + 1], teapot_normals[i + 2],
            });
        }

        for (int i = 0; i < index_count; i += 3) {
            mesh.faces_.emplace_back(Mesh::Face{teapot_indices[i + 0], teapot_indices[i + 1], teapot_indices[i + 2]});
        }
    }

    void get_transform(const float *positions, int position_count, Mesh::Position &translate, float &scale) {
        float min[3] = {
            positions[0], positions[1], positions[2],
        };
        float max[3] = {
            positions[0], positions[1], positions[2],
        };
        for (int i = 3; i < position_count; i += 3) {
            for (int j = 0; j < 3; j++) {
                if (min[j] > positions[i + j]) min[j] = positions[i + j];
                if (max[j] < positions[i + j]) max[j] = positions[i + j];
            }
        }

        translate.x = -(min[0] + max[0]) / 2.0f;
        translate.y = -(min[1] + max[1]) / 2.0f;
        translate.z = -(min[2] + max[2]) / 2.0f;

        float extents[3] = {
            max[0] + translate.x, max[1] + translate.y, max[2] + translate.z,
        };

        float max_extent = extents[0];
        if (max_extent < extents[1]) max_extent = extents[1];
        if (max_extent < extents[2]) max_extent = extents[2];

        scale = 1.0f / max_extent;
    }
};

void build_meshes(std::array<Mesh, Meshes::MESH_COUNT> &meshes) {
    BuildPyramid build_pyramid(meshes[Meshes::MESH_PYRAMID]);
    BuildIcosphere build_icosphere(meshes[Meshes::MESH_ICOSPHERE]);
    BuildTeapot build_teapot(meshes[Meshes::MESH_TEAPOT]);
}

}  // namespace

Meshes::Meshes(VkDevice dev, const std::vector<VkMemoryPropertyFlags> &mem_flags)
    : dev_(dev),
      vertex_input_binding_(Mesh::vertex_input_binding()),
      vertex_input_attrs_(Mesh::vertex_input_attributes()),
      vertex_input_state_(),
      input_assembly_state_(Mesh::input_assembly_state()),
      index_type_(Mesh::index_type()) {
    vertex_input_state_.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
    vertex_input_state_.vertexBindingDescriptionCount = 1;
    vertex_input_state_.pVertexBindingDescriptions = &vertex_input_binding_;
    vertex_input_state_.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertex_input_attrs_.size());
    vertex_input_state_.pVertexAttributeDescriptions = vertex_input_attrs_.data();

    std::array<Mesh, MESH_COUNT> meshes;
    build_meshes(meshes);

    draw_commands_.reserve(meshes.size());
    uint32_t first_index = 0;
    int32_t vertex_offset = 0;
    VkDeviceSize vb_size = 0;
    VkDeviceSize ib_size = 0;
    for (const auto &mesh : meshes) {
        VkDrawIndexedIndirectCommand draw = {};
        draw.indexCount = mesh.index_count();
        draw.instanceCount = 1;
        draw.firstIndex = first_index;
        draw.vertexOffset = vertex_offset;
        draw.firstInstance = 0;

        draw_commands_.push_back(draw);

        first_index += mesh.index_count();
        vertex_offset += mesh.vertex_count();
        vb_size += mesh.vertex_buffer_size();
        ib_size += mesh.index_buffer_size();
    }

    allocate_resources(vb_size, ib_size, mem_flags);

    uint8_t *vb_data, *ib_data;
    vk::assert_success(vk::MapMemory(dev_, mem_, 0, VK_WHOLE_SIZE, 0, reinterpret_cast<void **>(&vb_data)));
    ib_data = vb_data + ib_mem_offset_;

    for (const auto &mesh : meshes) {
        mesh.vertex_buffer_write(vb_data);
        mesh.index_buffer_write(ib_data);
        vb_data += mesh.vertex_buffer_size();
        ib_data += mesh.index_buffer_size();
    }

    vk::UnmapMemory(dev_, mem_);
}

Meshes::~Meshes() {
    vk::FreeMemory(dev_, mem_, nullptr);
    vk::DestroyBuffer(dev_, vb_, nullptr);
    vk::DestroyBuffer(dev_, ib_, nullptr);
}

void Meshes::cmd_bind_buffers(VkCommandBuffer cmd) const {
    const VkDeviceSize vb_offset = 0;
    vk::CmdBindVertexBuffers(cmd, 0, 1, &vb_, &vb_offset);

    vk::CmdBindIndexBuffer(cmd, ib_, 0, index_type_);
}

void Meshes::cmd_draw(VkCommandBuffer cmd, Type type) const {
    const auto &draw = draw_commands_[type];
    vk::CmdDrawIndexed(cmd, draw.indexCount, draw.instanceCount, draw.firstIndex, draw.vertexOffset, draw.firstInstance);
}

void Meshes::allocate_resources(VkDeviceSize vb_size, VkDeviceSize ib_size, const std::vector<VkMemoryPropertyFlags> &mem_flags) {
    VkBufferCreateInfo buf_info = {};
    buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
    buf_info.size = vb_size;
    buf_info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
    buf_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
    vk::CreateBuffer(dev_, &buf_info, nullptr, &vb_);

    buf_info.size = ib_size;
    buf_info.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
    vk::CreateBuffer(dev_, &buf_info, nullptr, &ib_);

    VkMemoryRequirements vb_mem_reqs, ib_mem_reqs;
    vk::GetBufferMemoryRequirements(dev_, vb_, &vb_mem_reqs);
    vk::GetBufferMemoryRequirements(dev_, ib_, &ib_mem_reqs);

    // indices follow vertices
    ib_mem_offset_ = vb_mem_reqs.size + (ib_mem_reqs.alignment - (vb_mem_reqs.size % ib_mem_reqs.alignment));

    VkMemoryAllocateInfo mem_info = {};
    mem_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
    mem_info.allocationSize = ib_mem_offset_ + ib_mem_reqs.size;

    // find any supported and mappable memory type
    uint32_t mem_types = (vb_mem_reqs.memoryTypeBits & ib_mem_reqs.memoryTypeBits);
    for (uint32_t idx = 0; idx < mem_flags.size(); idx++) {
        if ((mem_types & (1 << idx)) && (mem_flags[idx] & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) &&
            (mem_flags[idx] & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
            // TODO this may not be reachable
            mem_info.memoryTypeIndex = idx;
            break;
        }
    }

    vk::AllocateMemory(dev_, &mem_info, nullptr, &mem_);

    vk::BindBufferMemory(dev_, vb_, mem_, 0);
    vk::BindBufferMemory(dev_, ib_, mem_, ib_mem_offset_);
}
