/*
 * Copyright (c) 2017 ARM Limited.
 *
 * SPDX-License-Identifier: MIT
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
#include "HarrisCornerDetector.h"

#include "Utils.h"
#include "tests/validation/CPP/NonMaximaSuppression.h"
#include "tests/validation/CPP/Sobel.h"
#include "tests/validation/Helpers.h"

namespace arm_compute
{
namespace test
{
namespace validation
{
namespace reference
{
namespace
{
template <typename T>
std::tuple<SimpleTensor<T>, SimpleTensor<T>, float> compute_sobel(const SimpleTensor<uint8_t> &src, int gradient_size, int block_size, BorderMode border_mode, uint8_t constant_border_value)
{
    SimpleTensor<T> grad_x;
    SimpleTensor<T> grad_y;
    float           norm_factor = 0.f;

    std::tie(grad_x, grad_y) = sobel<T>(src, gradient_size, border_mode, constant_border_value);

    switch(gradient_size)
    {
        case 3:
            norm_factor = 1.f / (4 * 255 * block_size);
            break;
        case 5:
            norm_factor = 1.f / (16 * 255 * block_size);
            break;
        case 7:
            norm_factor = 1.f / (64 * 255 * block_size);
            break;
        default:
            ARM_COMPUTE_ERROR("Gradient size not supported.");
    }

    return std::make_tuple(grad_x, grad_y, norm_factor);
}

template <typename T, typename U>
std::vector<KeyPoint> harris_corner_detector_impl(const SimpleTensor<U> &src, float threshold, float min_dist, float sensitivity, int gradient_size, int block_size, BorderMode border_mode,
                                                  U constant_border_value)
{
    ARM_COMPUTE_ERROR_ON(block_size != 3 && block_size != 5 && block_size != 7);

    SimpleTensor<T> grad_x;
    SimpleTensor<T> grad_y;
    float           norm_factor = 0.f;

    // Sobel
    std::tie(grad_x, grad_y, norm_factor) = compute_sobel<T>(src, gradient_size, block_size, border_mode, constant_border_value);

    SimpleTensor<float> scores(src.shape(), DataType::F32);
    ValidRegion         scores_region = shape_to_valid_region(scores.shape(), border_mode == BorderMode::UNDEFINED, BorderSize(gradient_size / 2 + block_size / 2));

    // Calculate scores
    for(int i = 0; i < scores.num_elements(); ++i)
    {
        Coordinates src_coord = index2coord(src.shape(), i);
        Coordinates block_top_left{ src_coord.x() - block_size / 2, src_coord.y() - block_size / 2 };
        Coordinates block_bottom_right{ src_coord.x() + block_size / 2, src_coord.y() + block_size / 2 };

        if(!is_in_valid_region(scores_region, src_coord))
        {
            scores[i] = 0.f;
            continue;
        }

        float Gx2 = 0.f;
        float Gy2 = 0.f;
        float Gxy = 0.f;

        // Calculate Gx^2, Gy^2 and Gxy within the given window
        for(int y = src_coord.y() - block_size / 2; y <= src_coord.y() + block_size / 2; ++y)
        {
            for(int x = src_coord.x() - block_size / 2; x <= src_coord.x() + block_size / 2; ++x)
            {
                Coordinates block_coord(x, y);

                const float norm_x = tensor_elem_at(grad_x, block_coord, border_mode, static_cast<T>(constant_border_value)) * norm_factor;
                const float norm_y = tensor_elem_at(grad_y, block_coord, border_mode, static_cast<T>(constant_border_value)) * norm_factor;

                Gx2 += std::pow(norm_x, 2);
                Gy2 += std::pow(norm_y, 2);
                Gxy += norm_x * norm_y;
            }
        }

        const float trace2   = std::pow(Gx2 + Gy2, 2);
        const float det      = Gx2 * Gy2 - std::pow(Gxy, 2);
        const float response = det - sensitivity * trace2;

        if(response > threshold)
        {
            scores[i] = response;
        }
        else
        {
            scores[i] = 0.f;
        }
    }

    // Suppress non-maxima candidates
    SimpleTensor<float> suppressed_scores        = non_maxima_suppression(scores, border_mode != BorderMode::UNDEFINED ? BorderMode::CONSTANT : BorderMode::UNDEFINED, 0.f);
    ValidRegion         suppressed_scores_region = shape_to_valid_region(suppressed_scores.shape(), border_mode == BorderMode::UNDEFINED, BorderSize(gradient_size / 2 + block_size / 2 + 1));

    // Create vector of candidate corners
    std::vector<KeyPoint> corner_candidates;

    for(int i = 0; i < suppressed_scores.num_elements(); ++i)
    {
        Coordinates coord = index2coord(suppressed_scores.shape(), i);

        if(is_in_valid_region(suppressed_scores_region, coord) && suppressed_scores[i] > 0.f)
        {
            KeyPoint corner;
            corner.x               = coord.x();
            corner.y               = coord.y();
            corner.tracking_status = 1;
            corner.strength        = suppressed_scores[i];
            corner.scale           = 0.f;
            corner.orientation     = 0.f;
            corner.error           = 0.f;

            corner_candidates.emplace_back(corner);
        }
    }

    // Sort descending by strength
    std::sort(corner_candidates.begin(), corner_candidates.end(), [](const KeyPoint & a, const KeyPoint & b)
    {
        return a.strength > b.strength;
    });

    std::vector<KeyPoint> corners;
    corners.reserve(corner_candidates.size());

    // Only add corner if there is no stronger within min_dist
    for(const KeyPoint &point : corner_candidates)
    {
        const auto strongest = std::find_if(corners.begin(), corners.end(), [&](const KeyPoint & other)
        {
            return std::sqrt((std::pow(point.x - other.x, 2) + std::pow(point.y - other.y, 2))) < min_dist;
        });

        if(strongest == corners.end())
        {
            corners.emplace_back(point);
        }
    }

    corners.shrink_to_fit();

    return corners;
}
} // namespace

template <typename T>
std::vector<KeyPoint> harris_corner_detector(const SimpleTensor<T> &src, float threshold, float min_dist, float sensitivity, int gradient_size, int block_size, BorderMode border_mode,
                                             T constant_border_value)
{
    if(gradient_size < 7)
    {
        return harris_corner_detector_impl<int16_t>(src, threshold, min_dist, sensitivity, gradient_size, block_size, border_mode, constant_border_value);
    }
    else
    {
        return harris_corner_detector_impl<int32_t>(src, threshold, min_dist, sensitivity, gradient_size, block_size, border_mode, constant_border_value);
    }
}

template std::vector<KeyPoint> harris_corner_detector(const SimpleTensor<uint8_t> &src, float threshold, float min_dist, float sensitivity, int gradient_size, int block_size, BorderMode border_mode,
                                                      uint8_t constant_border_value);
} // namespace reference
} // namespace validation
} // namespace test
} // namespace arm_compute
