/*
 * Copyright (c) 2025, Alliance for Open Media. All rights reserved
 *
 * This source code is subject to the terms of the BSD 3-Clause Clear License
 * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear
 * License was not distributed with this source code in the LICENSE file, you
 * can obtain it at aomedia.org/license/software-license/bsd-3-c-c/.  If the
 * Alliance for Open Media Patent License 1.0 was not distributed with this
 * source code in the PATENTS file, you can obtain it at
 * aomedia.org/license/patent-license/.
 */

#ifndef AVM_AV2_COMMON_GDF_H
#define AVM_AV2_COMMON_GDF_H
#include "av2/common/av2_common_int.h"
#include "av2/common/bru.h"
#ifdef __cplusplus
extern "C" {
#endif

enum Direction { GDF_VER, GDF_HOR, GDF_DIAG0, GDF_DIAG1, GDF_NUM_DIRS };

#define GDF_VERBOSE 0

#define GDF_RDO_QP_NUM_LOG2 2
#define GDF_RDO_SCALE_NUM_LOG2 2
#define GDF_RDO_QP_NUM (1 << GDF_RDO_QP_NUM_LOG2)
#define GDF_RDO_SCALE_NUM (1 << GDF_RDO_SCALE_NUM_LOG2)

/*!\brief Function to initialize information of GDF from cm
 */
void init_gdf(AV2_COMMON *cm);

/*!\brief Function to initialize information of GDF for tests
 */
void init_gdf_test(GdfInfo *gi, int mib_size, int rec_height, int rec_width);

/*!\brief Function to allocate memory storing block's expected coding error of
 * GDF
 */
void alloc_gdf_buffers(GdfInfo *gi);

/*!\brief Function to free memory storing block's expected coding error of GDF
 */
void free_gdf_buffers(GdfInfo *gi);

/*!\brief Function to print paramters of GDF
 */
void gdf_print_info(AV2_COMMON *cm, char *info, int poc);

/*!\brief Function to extend - pad - the copy guided frame of GDF
 */
void gdf_extend_frame_highbd(uint16_t *data, int width, int height, int stride,
                             int border_horz, int border_vert);

/*!\brief Function to setup reference lines for filtering stripe
 */
void gdf_setup_reference_lines(AV2_COMMON *cm, int i_min, int i_max,
                               int frame_stripe, int copy_above,
                               int copy_below);

/*!\brief Function to unset reference lines for filtering stripe
 */
void gdf_unset_reference_lines(AV2_COMMON *cm, int i_min, int i_max,
                               int copy_above, int copy_below);

/*!\brief Function to allocate memory and copy guided frame of GDF
 */
void gdf_copy_guided_frame(AV2_COMMON *cm);
/*!\brief Function to free memory for guided frame of GDF
 */
void gdf_free_guided_frame(AV2_COMMON *cm);

/*!\brief Function to calculate block index in list of block on/off flags
 */
int gdf_get_block_idx(const AV2_COMMON *cm, int y_h, int y_w);

/*!\brief Function to calculate indices for lookup tables of GDF
 *        in which index is calculated based on distances to references frames
 *        and tables are weight, bias, clipping, and expected coding error
 */
int gdf_get_ref_dst_idx(const AV2_COMMON *cm);

/*!\brief Function to calculate indices for lookup weight+bias+clipping tables
 * of GDF in which index is calculated based on QP and tables are weight, bias,
 * clipping, and expected coding error
 */
int gdf_get_qp_idx_base(const AV2_COMMON *cm);

/*!\brief Function to apply GDF to whole frame
 */
void gdf_filter_frame(AV2_COMMON *cm);

/*!\brief Function to check whether GDF allowed.
 */
static inline int is_allow_gdf(const AV2_COMMON *cm) {
  return !cm->features.coded_lossless;
}

/*!\brief Function to check whether GDF enabled.
 */
static inline int is_gdf_enabled(const AV2_COMMON *cm) {
  return is_allow_gdf(cm) && cm->gdf_info.gdf_mode > 0;
}

/*!\brief Function to adjust the GDF block boundary to ensure even alignment.
 * Because the minimum required pixel size in GDF block is 2x2.
 * \param[in]  i_min                The pos of the block's top boundary
 * \param[in]  i_max                The pos of the block's bottom boundary
 * \param[in]  j_min                The pos of the block's left boundary
 * \param[in]  j_max                The pos of the block's right boundary
 * * \return Returns a value indicating whether the block size is valid
 */
static inline int gdf_block_adjust_and_validate(int *i_min, int *i_max,
                                                int *j_min, int *j_max) {
  *i_min = (*i_min + 1) & ~0x1;
  *i_max = *i_max & ~0x1;
  *j_min = (*j_min + 1) & ~0x1;
  *j_max = *j_max & ~0x1;
  return (*i_max > *i_min) && (*j_max > *j_min);
}

/*!\brief Function to copy left/right buffers when disabling filtering
 * across tiles is desired.
 */
void gdf_setup_processing_stripe_leftright_boundary(GdfInfo *gdf, int i_min,
                                                    int i_max, int j_min,
                                                    int j_max,
                                                    int tile_boundary_left,
                                                    int tile_boundary_right);

/*!\brief Function to restore left/right buffers when disabling filtering
 * across tiles is desired.
 */
void gdf_restore_processing_stripe_leftright_boundary(GdfInfo *gdf, int i_min,
                                                      int i_max, int j_min,
                                                      int j_max,
                                                      int tile_boundary_left,
                                                      int tile_boundary_right);
#ifdef __cplusplus
}  // extern "C"
#endif

#endif  // AVM_AV2_COMMON_GDF_H
