/*
  This file is part of CDO. CDO is a collection of Operators to
  manipulate and analyse Climate model Data.

  Copyright (C) 2003-2020 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
  See COPYING file for copying and redistribution conditions.

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; version 2 of the License.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
*/
#ifndef MPIM_GRID_H
#define MPIM_GRID_H

#include <cstdio>
#include <vector>

#include <cdi.h>

#include "grid_proj.h"
#include "grid_rot.h"
#include "grid_convert.h"

extern "C" int qu2reg3_double(double *pfield, int *kpoint, int klat, int klon, double msval, int *kret, int omisng, int operio,
                              int oveggy);

extern bool gridVerbose;
extern char *gridSearchDir;

static inline bool
gridProjIsSupported(int gridID)
{
  const auto gridtype = gridInqType(gridID);
  const auto pt = (gridtype == GRID_PROJECTION) ? gridInqProjType(gridID) : -1;
  return (pt == CDI_PROJ_RLL || pt == CDI_PROJ_LCC || pt == CDI_PROJ_LAEA || pt == CDI_PROJ_STERE || pt == CDI_PROJ_SINU);
}

static inline bool
gridHasCoordinates(int gridID)
{
  return (gridInqXvals(gridID, nullptr) && gridInqYvals(gridID, nullptr));
}

static inline bool
gridHasBounds(int gridID)
{
  return (gridInqXbounds(gridID, nullptr) && gridInqYbounds(gridID, nullptr));
}

void gridEnableVerbose(bool enable);
void gridSetSearchDir(char *dir);

int nfc_to_nlat(int nfc, int ntr);
int nlat_to_ntr(int nlat);
int nlat_to_ntr_linear(int nlat);
int nlat_to_ntr_cubic(int nlat);
int ntr_to_nlat(int ntr);
int ntr_to_nlat_linear(int ntr);
int ntr_to_nlat_cubic(int ntr);
int nlat_to_nlon(int nlat);
int nlat_to_nlon_cubic(int nlat);

void grid_copy_keys(int gridID1, int gridID2);
void grid_copy_mapping(int gridID1, int gridID2);

bool grid_is_distance_generic(int gridID);

void grid_to_radian(const char *units, size_t nvals, double *values, const char *description);
void cdo_grid_to_radian(int gridID, int varID, size_t nvals, double *values, const char *description);
void cdo_grid_to_degree(int gridID, int varID, size_t nvals, double *values, const char *description);

void grid_gen_corners(size_t n, const double *vals, double *corners);
void grid_gen_bounds(size_t n, const std::vector<double> &vals, std::vector<double> &bounds);
void grid_check_lat_borders(int n, double *ybounds);

void grid_gen_xbounds2D(size_t nx, size_t ny, const std::vector<double> &xbounds, std::vector<double> &xbounds2D);
void grid_gen_ybounds2D(size_t nx, size_t ny, const std::vector<double> &ybounds, std::vector<double> &ybounds2D);

int gridWeights(int gridID, double *weights);
int gridGenArea(int gridID, double *area);
int gridGenAreaReg2Dweights(int gridID, double *area);

int gridToZonal(int gridID);
int gridToMeridional(int gridID);
int gridToUnstructured(int gridID, int lbounds);
int gridToUnstructuredSelecton(int gridID1, size_t selectionSize, int *selectionIndexList, int nocoords, int nobounds);
int gridToCurvilinear(int gridID, int lbounds);
int gridCurvilinearToRegular(int gridID);
int gridToRegular(int gridID);
void field2regular(int gridID1, int gridID2, double missval, double *array, size_t nmiss, int lnearest);

// GME grid
void gme_factorni(int kni, int *kni2, int *kni3);
void gme_grid_restore(double *p, int ni, int nd);
void gme_grid(int lbounds, size_t gridsize, double *rlon, double *rlat, double *blon, double *blat, int *imask, int ni, int nd,
              int ni2, int ni3);

void cdoPrintGrid(int gridID, int opt);

bool grid_has_proj_params(int gridID);

#endif /* MPIM_GRID_H */
