#pragma once

#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>

#include <graphene/surface_mesh/data_structure/Surface_mesh.h>

namespace halfedge_map{

    void sanity_check(cv::Mat& halfedge_id_map)
    {
        cv::Mat vis_image = cv::Mat::zeros(halfedge_id_map.size(), CV_8UC3);

        for (int row = 1; row < halfedge_id_map.rows -1; ++row)
        {
            for (int col = 1; col < halfedge_id_map.cols - 1; ++col)
            {
                if (halfedge_id_map.at<int32_t>(row, col) != -1)
                {
                    vis_image.at<cv::Vec3b>(row, col) = cv::Vec3b(255, 100, 100);
                }
            }
        }

        cv::namedWindow("Halfedgesanity", cv::WINDOW_NORMAL);
        cv::imshow("Halfedgesanity", vis_image);
        cv::waitKey(0);
    }
}

//
// Creates a texture that encodes the halfedge id corresponding to each texel
// (-1 if texel does not correspond to any halfedge)
//
static bool halfedge_id_map(const graphene::surface_mesh::Surface_mesh& mesh, cv::Mat& result)
{
    const unsigned int rows = result.rows;
    const unsigned int cols = result.cols;
    const unsigned int dim  = rows;

    if (rows != cols || rows == 0 || result.type() != CV_32SC1)
    {
        std::cerr << "[ERROR] "<< __FUNCTION__ << ": rows != cols || rows == 0 || type != S32C1" << std::endl;
        return false;
    }
    result.setTo(cv::Scalar(-1));

    auto texcoords = mesh.get_halfedge_property<graphene::Texture_coordinate>("h:texcoord");
    if (!texcoords)
    {
        std::cerr << "[ERROR] " << __FUNCTION__ << ": no tex coords." << std::endl;
        return false;
    }

    for (auto he : mesh.halfedges())
    {
        auto prev_he = mesh.prev_halfedge(he);
        graphene::Texture_coordinate t1 = texcoords[he];
        graphene::Texture_coordinate t2 = texcoords[prev_he];

        // bottom-up to top-down, uv to pixel coordinates
        const graphene::Vec2f corner_1 = graphene::Vec2f(t1[0], 1.0 - t1[1]) * static_cast<double>(dim);
        const graphene::Vec2f corner_2 = graphene::Vec2f(t2[0], 1.0 - t2[1]) * static_cast<double>(dim);

        cv::Point p1 = cv::Point(std::round(corner_1[0]), std::round(corner_1[1]));
        cv::Point p2 = cv::Point(std::round(corner_2[0]), std::round(corner_2[1]));

        int32_t val = he.idx();
        cv::line(result, p1, p2, cv::Scalar(val), 1, cv::LINE_8);
    }

    // DEBUG
    //halfedge_map::sanity_check(result);

    return true;
}
