/*
 * Copyright (c) 2017-2020 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 "src/core/AccessWindowStatic.h"

#include "arm_compute/core/Helpers.h"
#include "arm_compute/core/ITensorInfo.h"
#include "arm_compute/core/Window.h"

using namespace arm_compute;

AccessWindowStatic::AccessWindowStatic(ITensorInfo *info, int start_x, int start_y, int end_x, int end_y)
    : _info(info), _start_x(start_x), _start_y(start_y), _end_x(end_x), _end_y(end_y)
{
}

ValidRegion AccessWindowStatic::compute_valid_region(const Window &window,
                                                     ValidRegion   input_valid_region,
                                                     bool          border_undefined,
                                                     BorderSize    border_size) const
{
    ARM_COMPUTE_UNUSED(border_undefined);
    ARM_COMPUTE_UNUSED(border_size);

    return compute_valid_region(window, input_valid_region);
}

ValidRegion AccessWindowStatic::compute_valid_region(const Window &window, ValidRegion input_valid_region) const
{
    if (_info == nullptr)
    {
        return input_valid_region;
    }

    ARM_COMPUTE_UNUSED(window);

    Coordinates &anchor = input_valid_region.anchor;
    TensorShape &shape  = input_valid_region.shape;

    // Start of the valid region is equal to the start of the static access but
    // never outside of the tensor.
    anchor.set(0, std::max<int>(0, _start_x));
    if (_info->num_dimensions() > 1)
    {
        anchor.set(1, std::max<int>(0, _start_y));
    }

    // End of the valid region is equal to the end of the static access but
    // never outside of the tensor.
    shape.set(0, std::min<int>(_end_x, _info->tensor_shape()[0]));
    if (_info->num_dimensions() > 1)
    {
        shape.set(1, std::min<int>(_end_y, _info->tensor_shape()[1]));
    }

    return input_valid_region;
}

void AccessWindowStatic::set_valid_region(const Window &window, const ValidRegion &input_valid_region)
{
    if (_info != nullptr)
    {
        _info->set_valid_region(compute_valid_region(window, input_valid_region));
    }
}

bool AccessWindowStatic::update_window_if_needed(Window &window) const
{
    // If the padding is not enough and the tensor is not resizable, shrink the window to size 0
    if (_info == nullptr || _info->is_resizable())
    {
        return false;
    }

    const TensorShape &shape                = _info->tensor_shape();
    const Strides     &strides              = _info->strides_in_bytes();
    const size_t       offset_first_element = _info->offset_first_element_in_bytes();

    bool window_modified = false;

    // Calculate if padding is enough
    if (_start_y < 0)
    {
        const int front_pad_y_available = -static_cast<int>(offset_first_element / strides[1]);

        if (_start_y < front_pad_y_available)
        {
            window_modified = true;
        }
    }

    if (!window_modified)
    {
        if (_end_y > static_cast<int>(shape[1]))
        {
            const int stride_z             = _info->num_dimensions() > 2 ? strides[2] : _info->total_size();
            const int tail_pad_y_available = (stride_z / strides[1]) - shape[1];

            if (static_cast<int>(shape[1]) + tail_pad_y_available < _end_y)
            {
                window_modified = true;
            }
        }

        if (!window_modified)
        {
            const int stride_y = _info->num_dimensions() > 1 ? strides[1] : _info->total_size();

            if (_start_x < 0)
            {
                const int front_pad_x_available =
                    -std::min<int>(static_cast<int>(offset_first_element), stride_y - shape[0] * strides[0]) /
                    static_cast<int>(strides[0]);

                if (_start_x < front_pad_x_available)
                {
                    window_modified = true;
                }
            }

            if (!window_modified && _end_x > static_cast<int>(shape[0]))
            {
                const int tail_pad_x_available = (stride_y / strides[0]) - shape[0];

                if (static_cast<int>(shape[0]) + tail_pad_x_available < _end_x)
                {
                    window_modified = true;
                }
            }
        }
    }

    // If padding is not enough
    if (window_modified)
    {
        for (size_t i = 0; i < Coordinates::num_max_dimensions; ++i)
        {
            window.set(i, Window::Dimension(0, 0, 1));
        }
    }

    return window_modified;
}

bool AccessWindowStatic::update_padding_if_needed(const Window &window)
{
    ARM_COMPUTE_UNUSED(window);

    // Only update the padding if the tensor allows it
    if (_info == nullptr || !_info->is_resizable())
    {
        return false;
    }

    const TensorShape &shape = _info->tensor_shape();

    PaddingSize padding;
    padding.left   = std::max(0, -_start_x);
    padding.right  = std::max<int>(0, _end_x - shape[0]);
    padding.top    = std::max(0, -_start_y);
    padding.bottom = std::max<int>(0, _end_y - shape[1]);

    // Update strides in tensor info
    return _info->extend_padding(padding);
}
