#include "../include/yt_serialization.h"

namespace maps::mrc::yt {

namespace {

static const TString COLUMN_NAME_GOOD_PTS_CNT     = "good_pts_cnt";
static const TString COLUMN_NAME_PTS_CNT_0     = "pts_cnt_0";
static const TString COLUMN_NAME_PTS_CNT_1     = "pts_cnt_1";
static const TString COLUMN_NAME_SAMPSON_DISTANCE = "sampson_distance";
static const TString COLUMN_NAME_FUND_MAT         = "fund_mat";
static const TString COLUMN_NAME_HULL0            = "hull0";
static const TString COLUMN_NAME_HULL1            = "hull1";
static const TString COLUMN_NAME_KEYPOINTS0       = "keypoints0";
static const TString COLUMN_NAME_KEYPOINTS1       = "keypoints1";

NYT::TNode fundMatToNode(const cv::Mat& fundMat) {
    REQUIRE(fundMat.cols == 3 && fundMat.rows == 3 && fundMat.depth() == CV_64F, "Invalid fundamental matrix");
    NYT::TNode result = NYT::TNode::CreateList();
    for (int row = 0; row < fundMat.rows; row++) {
        const double *ptr = fundMat.ptr<double>(row);
        for (int col = 0; col < fundMat.cols; col++) {
            result.Add(ptr[col]);
        }
    }
    return result;
}

cv::Mat fundMatFromNode(const NYT::TNode& node)
{
    const TVector<NYT::TNode>& matNode = node.AsList();
    return (cv::Mat_<double>(3, 3) <<
            matNode[0].AsDouble(), matNode[1].AsDouble(), matNode[2].AsDouble(),
            matNode[3].AsDouble(), matNode[4].AsDouble(), matNode[5].AsDouble(),
            matNode[6].AsDouble(), matNode[7].AsDouble(), matNode[8].AsDouble());
}

} // namespace


NYT::TNode serialize(const eye::FramesMatchData& value)
{
    return NYT::TNode()
        (COLUMN_NAME_GOOD_PTS_CNT, value.goodPtsCnt)
        (COLUMN_NAME_PTS_CNT_0, value.ptsCnt0)
        (COLUMN_NAME_PTS_CNT_1, value.ptsCnt1)
        (COLUMN_NAME_FUND_MAT, fundMatToNode(value.fundMatrix))
        (COLUMN_NAME_HULL0, serialize(value.hull0))
        (COLUMN_NAME_HULL1, serialize(value.hull1));
}

template<>
eye::FramesMatchData deserialize<eye::FramesMatchData>(const NYT::TNode& node)
{
    return eye::FramesMatchData {
        .goodPtsCnt = static_cast<int>(node[COLUMN_NAME_GOOD_PTS_CNT].AsInt64()),
        .ptsCnt0 = static_cast<int>(node[COLUMN_NAME_PTS_CNT_0].AsInt64()),
        .ptsCnt1 = static_cast<int>(node[COLUMN_NAME_PTS_CNT_1].AsInt64()),
        .fundMatrix = fundMatFromNode(node[COLUMN_NAME_FUND_MAT]),
        .hull0 = deserialize<std::vector<cv::Point2f>>(node[COLUMN_NAME_HULL0]),
        .hull1 = deserialize<std::vector<cv::Point2f>>(node[COLUMN_NAME_HULL1])
    };
}

} // namespace maps::mrc::yt
