/*
    This file is part of darktable,
    copyright (c) 2009--2012 johannes hanika.
    copyright (c) 2011 henrik andersson.
    copyright (c) 2012 tobias ellinghaus.

    darktable 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, either version 3 of the License, or
    (at your option) any later version.

    darktable 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.

    You should have received a copy of the GNU General Public License
    along with darktable.  If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DT_DEVELOP_IMAGEOP_H
#define DT_DEVELOP_IMAGEOP_H

#include "common/darktable.h"
#include "control/settings.h"
#include "develop/pixelpipe.h"
#include "dtgtk/togglebutton.h"
#include "gui/simple_gui.h"
#include <gmodule.h>
#include <gtk/gtk.h>
#include <sched.h>
struct dt_develop_t;
struct dt_dev_pixelpipe_t;
struct dt_dev_pixelpipe_iop_t;
struct dt_iop_roi_t;
struct dt_develop_blend_params_t;
struct dt_develop_tiling_t;

#define	IOP_GROUP_BASIC    1
#define	IOP_GROUP_COLOR    2
#define	IOP_GROUP_CORRECT  4
#define	IOP_GROUP_EFFECT   8
#define	IOP_GROUP_TONE    16
#define	IOP_SPECIAL_GROUP_ACTIVE_PIPE  32
#define	IOP_SPECIAL_GROUP_USER_DEFINED 64

#define IOP_TAG_DISTORT       1
#define IOP_TAG_DECORATION    2
// might be some other filters togglable by user?
//#define IOP_TAG_SLOW        4
//#define IOP_TAG_DETAIL_FIX  8


#define	IOP_GROUP_ALL (IOP_GROUP_BASIC|IOP_GROUP_COLOR|IOP_GROUP_CORRECT|IOP_GROUP_EFFECT)

/** Flag for the iop module to be enabled/included by default when creating a style */
#define IOP_FLAGS_INCLUDE_IN_STYLES     1
#define IOP_FLAGS_SUPPORTS_BLENDING     2                       // Does provide blending modes
#define IOP_FLAGS_DEPRECATED            4
#define IOP_FLAGS_BLEND_ONLY_LIGHTNESS  8                       // Does only blend with L-channel in Lab space. Keeps a, b of original image.
#define IOP_FLAGS_ALLOW_TILING         16                       // Does allow tile-wise processing (valid for CPU and GPU processing)
#define IOP_FLAGS_HIDDEN               32                       // Hide the iop from userinterface
#define IOP_FLAGS_TILING_FULL_ROI      64                       // Tiling code has to expect arbitrary roi's for this module (incl. flipping, mirroring etc.)
#define IOP_FLAGS_ONE_INSTANCE        128                       // The module doesn't support multiple instances
#define IOP_FLAGS_PREVIEW_NON_OPENCL  256                       // Preview pixelpipe of this module must not run on GPU but always on CPU
#define IOP_FLAGS_NO_HISTORY_STACK    512                       // This iop will never show up in the history stack
#define IOP_FLAGS_NO_MASKS  1024    // The module doesn't support masks (used with SUPPORT_BLENDING)
/** status of a module*/
typedef enum dt_iop_module_state_t
{
  dt_iop_state_HIDDEN = 0, // keep first
  dt_iop_state_ACTIVE,
  dt_iop_state_FAVORITE,
  dt_iop_state_LAST

}
dt_iop_module_state_t;
typedef struct dt_iop_params_t
{
  int keep;
}
dt_iop_params_t;
typedef void dt_iop_gui_data_t;
typedef void dt_iop_data_t;
typedef void dt_iop_global_data_t;

/** part of the module which only contains the cached dlopen stuff. */
struct dt_iop_module_so_t;
struct dt_iop_module_t;
typedef struct dt_iop_module_so_t
{
  /** opened module. */
  GModule *module;
  /** string identifying this operation. */
  dt_dev_operation_t op;
  /** other stuff that may be needed by the module, not only in gui mode. inited only once, has to be read-only then. */
  dt_iop_global_data_t *data;
  /** gui is also only inited once at startup. */
  dt_iop_gui_data_t *gui_data;
  /** which results in this widget here, too. */
  GtkWidget *widget;

  /** this initializes static, hardcoded presets for this module and is called only once per run of dt. */
  void (*init_presets)    (struct dt_iop_module_so_t *self);
  /** called once per module, at startup. */
  void (*init_global)     (struct dt_iop_module_so_t *self);
  /** called once per module, at shutdown. */
  void (*cleanup_global)  (struct dt_iop_module_so_t *self);

  /** callbacks, loaded once, referenced by the instances. */
  int (*version)          ();
  const char* (*name)     ();
  int (*groups)           ();
  int (*flags)            ();

  int (*operation_tags)         ();
  int (*operation_tags_filter)  ();

  int (*output_bpp)       (struct dt_iop_module_t *self, struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece);
  void (*tiling_callback) (struct dt_iop_module_t *self, struct dt_dev_pixelpipe_iop_t *piece, const struct dt_iop_roi_t *roi_in, const struct dt_iop_roi_t *roi_out, struct dt_develop_tiling_t *tiling);

  void (*gui_reset)       (struct dt_iop_module_t *self);
  void (*gui_update)      (struct dt_iop_module_t *self);
  void (*gui_init)        (struct dt_iop_module_t *self);
  dt_gui_simple_t* (*gui_init_simple) (struct dt_iop_module_so_t *self);
  void (*gui_cleanup)     (struct dt_iop_module_t *self);
  void (*gui_post_expose) (struct dt_iop_module_t *self, cairo_t *cr, int32_t width, int32_t height, int32_t pointerx, int32_t pointery);
  void (*gui_focus)       (struct dt_iop_module_t *self, gboolean in);
  /** Optional callback for keyboard accelerators */
  void (*init_key_accels)(struct dt_iop_module_so_t *so);
  void (*original_init_key_accels)(struct dt_iop_module_so_t *so);
  void (*connect_key_accels)(struct dt_iop_module_t *self);
  void (*original_connect_key_accels)(struct dt_iop_module_t *self);
  void (*disconnect_key_accels)(struct dt_iop_module_t *self);

  int  (*mouse_leave)     (struct dt_iop_module_t *self);
  int  (*mouse_moved)     (struct dt_iop_module_t *self, double x, double y, double pressure, int which);
  int  (*button_released) (struct dt_iop_module_t *self, double x, double y, int which, uint32_t state);
  int  (*button_pressed)  (struct dt_iop_module_t *self, double x, double y, double pressure, int which, int type, uint32_t state);
  int  (*scrolled)        (struct dt_iop_module_t *self, double x, double y, int up, uint32_t state);
  void (*configure)       (struct dt_iop_module_t *self, int width, int height);

  void (*init)            (struct dt_iop_module_t *self); // this MUST set params_size!
  void (*original_init)   (struct dt_iop_module_t *self);
  void (*cleanup)         (struct dt_iop_module_t *self);
  void (*init_pipe)       (struct dt_iop_module_t *self, struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece);
  void (*commit_params)   (struct dt_iop_module_t *self, struct dt_iop_params_t *params, struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece);
  void (*reload_defaults) (struct dt_iop_module_t *self);
  void (*cleanup_pipe)    (struct dt_iop_module_t *self, struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece);
  void (*modify_roi_in)   (struct dt_iop_module_t *self, struct dt_dev_pixelpipe_iop_t *piece, const struct dt_iop_roi_t *roi_out, struct dt_iop_roi_t *roi_in);
  void (*modify_roi_out)  (struct dt_iop_module_t *self, struct dt_dev_pixelpipe_iop_t *piece, struct dt_iop_roi_t *roi_out, const struct dt_iop_roi_t *roi_in);
  int  (*legacy_params)   (struct dt_iop_module_t *self, const void *const old_params, const int old_version, void *new_params, const int new_version);

  void (*process)         (struct dt_iop_module_t *self, struct dt_dev_pixelpipe_iop_t *piece, void *i, void *o, const struct dt_iop_roi_t *roi_in, const struct dt_iop_roi_t *roi_out);
  void (*process_tiling)  (struct dt_iop_module_t *self, struct dt_dev_pixelpipe_iop_t *piece, void *i, void *o, const struct dt_iop_roi_t *roi_in, const struct dt_iop_roi_t *roi_out, const int bpp);
  int  (*process_cl)      (struct dt_iop_module_t *self, struct dt_dev_pixelpipe_iop_t *piece, void *i, void *o, const struct dt_iop_roi_t *roi_in, const struct dt_iop_roi_t *roi_out);
  int  (*process_tiling_cl)      (struct dt_iop_module_t *self, struct dt_dev_pixelpipe_iop_t *piece, void *i, void *o, const struct dt_iop_roi_t *roi_in, const struct dt_iop_roi_t *roi_out, const int bpp);

  int (*distort_transform) (struct dt_iop_module_t *self, struct dt_dev_pixelpipe_iop_t *piece, float *points, int points_count);
  int (*distort_backtransform) (struct dt_iop_module_t *self, struct dt_dev_pixelpipe_iop_t *piece, float *points, int points_count);
}
dt_iop_module_so_t;

typedef struct dt_iop_module_t
{
  /** opened module. */
  GModule *module;
  /** string identifying this operation. */
  dt_dev_operation_t op;
  /** used to identify this module in the history stack. */
  int32_t instance;
  /** order in which plugins are stacked. */
  int32_t priority;
  /** module sets this if the enable checkbox should be hidden. */
  int32_t hide_enable_button;
  /** set to 1 if you want an input color picked during next eval. gui mode only. */
  int32_t request_color_pick;
  /** set to 1 if you want an input histogram generated during next eval. gui mode only. */
  int32_t request_histogram;
  /** set to 1 if you want the mask to be transferred into alpha channel during next eval. gui mode only. */
  int32_t request_mask_display;
  /** set to 1 if you want the blendif mask to be suppressed in the module in focus. gui mode only. */
  int32_t suppress_mask;
  /** bounding box in which the mean color is requested. */
  float color_picker_box[4];
  /** single point to pick if in point mode */
  float color_picker_point[2];
  /** place to store the picked color of module input. */
  float picked_color[3], picked_color_min[3], picked_color_max[3];
  /** place to store the picked color of module output (before blending). */
  float picked_output_color[3], picked_output_color_min[3], picked_output_color_max[3];
  /** pointer to pre-module histogram data; if available: 64 bins with 4 channels each */
  float *histogram;
  /** maximum levels in histogram, one per channel */
  float histogram_max[4];
  /** reference for dlopened libs. */
  darktable_t *dt;
  /** the module is used in this develop module. */
  struct dt_develop_t *dev;
  /** non zero if this node should be processed. */
  int32_t enabled, default_enabled;
  /** parameters for the operation. will be replaced by history revert. */
  dt_iop_params_t *params, *default_params;
  /** size of individual params struct. */
  int32_t params_size;
  /** parameters needed if a gui is attached. will be NULL if in export/batch mode. */
  dt_iop_gui_data_t *gui_data;
  /** other stuff that may be needed by the module, not only in gui mode. */
  dt_iop_global_data_t *data;
  /** blending params */
  struct dt_develop_blend_params_t *blend_params, *default_blendop_params;
  /** holder for blending ui control */
  gpointer blend_data;
  /** child widget which is added to the GtkExpander. copied from module_so_t. */
  GtkWidget *widget;
  /** off button, somewhere in header, common to all plug-ins. */
  GtkDarktableToggleButton *off;
  /** this is the module header, contains labe and buttons */
  GtkWidget *header;

  /** button used to show/hide this module in the plugin list. */
  dt_iop_module_state_t state;
  /** expander containing the widget and flag to store expanded state */
  GtkWidget *expander;
  gboolean expanded;
  /** reset parameters button */
  GtkWidget *reset_button;
  /** show preset menu button */
  GtkWidget *presets_button;
  /** fusion slider */
  GtkWidget *fusion_slider;
  /** list of closures: show, enable/disable */
  GSList *accel_closures;
  GSList *accel_closures_local;
  gboolean local_closures_connected;
  /** the corresponding SO object */
  dt_iop_module_so_t *so;

  /** multi-instances things */
  int multi_priority; //user may change this
  char multi_name[128]; //user may change this name
  gboolean multi_show_close;
  gboolean multi_show_up;
  gboolean multi_show_down;
  GtkWidget *duplicate_button;
  GtkWidget *multimenu_button;

  /** version of the parameters in the database. */
  int (*version)          ();
  /** get name of the module, to be translated. */
  const char* (*name)     ();
  /** get the groups this module belongs to. */
  int (*groups)           ();
  /** get the iop module flags. */
  int (*flags)            ();

  int (*operation_tags)         ();

  int (*operation_tags_filter)  ();
  /** how many bytes per pixel in the output. */
  int (*output_bpp)       (struct dt_iop_module_t *self, struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece);
  /** report back info for tiling: memory usage and overlap. Memory usage: factor * input_size + overhead */
  void (*tiling_callback) (struct dt_iop_module_t *self, struct dt_dev_pixelpipe_iop_t *piece, const struct dt_iop_roi_t *roi_in, const struct dt_iop_roi_t *roi_out, struct dt_develop_tiling_t *tiling);

  /** callback methods for gui. */
  /** synch gtk interface with gui params, if necessary. */
  void (*gui_update)      (struct dt_iop_module_t *self);
  /** reset ui to defaults */
  void (*gui_reset)       (struct dt_iop_module_t *self);
  /** construct widget. */
  void (*gui_init)        (struct dt_iop_module_t *self);
  /** construct widget using the simple api. */
  dt_gui_simple_t* (*gui_init_simple) (struct dt_iop_module_so_t *self);
  /** destroy widget. */
  void (*gui_cleanup)     (struct dt_iop_module_t *self);
  /** optional method called after darkroom expose. */
  void (*gui_post_expose) (struct dt_iop_module_t *self, cairo_t *cr, int32_t width, int32_t height, int32_t pointerx, int32_t pointery);
  /** optional callback to be notified if the module acquires gui focus/loses it. */
  void (*gui_focus)       (struct dt_iop_module_t *self, gboolean in);

  /** optional event callbacks */
  int  (*mouse_leave)     (struct dt_iop_module_t *self);
  int  (*mouse_moved)     (struct dt_iop_module_t *self, double x, double y, double pressure, int which);
  int  (*button_released) (struct dt_iop_module_t *self, double x, double y, int which, uint32_t state);
  int  (*button_pressed)  (struct dt_iop_module_t *self, double x, double y, double pressure, int which, int type, uint32_t state);
  int  (*key_pressed)     (struct dt_iop_module_t *self, uint16_t which);
  int  (*scrolled)        (struct dt_iop_module_t *self, double x, double y, int up, uint32_t state);
  void (*configure)       (struct dt_iop_module_t *self, int width, int height);

  void (*init)            (struct dt_iop_module_t *self); // this MUST set params_size!
  void (*original_init)   (struct dt_iop_module_t *self);
  void (*cleanup)         (struct dt_iop_module_t *self);
  /** this inits the piece of the pipe, allocing piece->data as necessary. */
  void (*init_pipe)       (struct dt_iop_module_t *self, struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece);
  /** this resets the params to factory defaults. used at the beginning of each history synch. */
  /** this commits (a mutex will be locked to synch gegl/gui) the given history params to the gegl pipe piece. */
  void (*commit_params)   (struct dt_iop_module_t *self, struct dt_iop_params_t *params, struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece);
  /** this is the chance to update default parameters, after the full raw is loaded. */
  void (*reload_defaults) (struct dt_iop_module_t *self);
  /** this destroys all (gegl etc) resources needed by the piece of the pipeline. */
  void (*cleanup_pipe)    (struct dt_iop_module_t *self, struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece);
  void (*modify_roi_in)   (struct dt_iop_module_t *self, struct dt_dev_pixelpipe_iop_t *piece, const struct dt_iop_roi_t *roi_out, struct dt_iop_roi_t *roi_in);
  void (*modify_roi_out)  (struct dt_iop_module_t *self, struct dt_dev_pixelpipe_iop_t *piece, struct dt_iop_roi_t *roi_out, const struct dt_iop_roi_t *roi_in);
  int  (*legacy_params)   (struct dt_iop_module_t *self, const void *const old_params, const int old_version, void *new_params, const int new_version);

  /** this is the temp homebrew callback to operations, as long as gegl is so slow.
    * x,y, and scale are just given for orientation in the framebuffer. i and o are
    * scaled to the same size width*height and contain a max of 3 floats. other color
    * formats may be filled by this callback, if the pipeline can handle it. */
  void (*process)         (struct dt_iop_module_t *self, struct dt_dev_pixelpipe_iop_t *piece, void *i, void *o, const struct dt_iop_roi_t *roi_in, const struct dt_iop_roi_t *roi_out);
  /** a tiling variant of process(). */
  void (*process_tiling)  (struct dt_iop_module_t *self, struct dt_dev_pixelpipe_iop_t *piece, void *i, void *o, const struct dt_iop_roi_t *roi_in, const struct dt_iop_roi_t *roi_out, const int bpp);
  /** the opencl equivalent of process(). */
  int (*process_cl)      (struct dt_iop_module_t *self, struct dt_dev_pixelpipe_iop_t *piece, void *i, void *o, const struct dt_iop_roi_t *roi_in, const struct dt_iop_roi_t *roi_out);
  /** a tiling variant of process_cl(). */
  int (*process_tiling_cl)  (struct dt_iop_module_t *self, struct dt_dev_pixelpipe_iop_t *piece, void *i, void *o, const struct dt_iop_roi_t *roi_in, const struct dt_iop_roi_t *roi_out, const int bpp);

  /** this functions are used for distort iop
   * points is an array of float {x1,y1,x2,y2,...}
   * size is 2*points_count */
  /** points before the iop is applied => point after processed */
  int (*distort_transform) (struct dt_iop_module_t *self, struct dt_dev_pixelpipe_iop_t *piece, float *points, int points_count);
  /** reverse points after the iop is applied => point before process */
  int (*distort_backtransform) (struct dt_iop_module_t *self, struct dt_dev_pixelpipe_iop_t *piece, float *points, int points_count);

  /** Key accelerator registration callbacks */
  void (*connect_key_accels)(struct dt_iop_module_t *self);
  void (*original_connect_key_accels)(struct dt_iop_module_t *self);
  void (*disconnect_key_accels)(struct dt_iop_module_t *self);
}
dt_iop_module_t;

/** loads and inits the modules in the plugins/ directory. */
void dt_iop_load_modules_so();
/** cleans up the dlopen refs. */
void dt_iop_unload_modules_so();
/** returns a list of instances referencing stuff loaded in load_modules_so. */
GList *dt_iop_load_modules(struct dt_develop_t *dev);
int dt_iop_load_module(dt_iop_module_t *module, dt_iop_module_so_t *module_so, struct dt_develop_t *dev);
gint sort_plugins(gconstpointer a, gconstpointer b);
/** calls module->cleanup and closes the dl connection. */
void dt_iop_cleanup_module(dt_iop_module_t *module);
/** initialize pipe. */
void dt_iop_init_pipe(struct dt_iop_module_t *module, struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece);
/** checks if iop do have an ui */
gboolean dt_iop_is_hidden(dt_iop_module_t *module);
/** cleans up gui of module and of blendops */
void dt_iop_gui_cleanup_module(dt_iop_module_t *module);
/** updates the gui params and the enabled switch. */
void dt_iop_gui_update(dt_iop_module_t *module);
/** reset the ui to its defaults */
void dt_iop_gui_reset(dt_iop_module_t *module);
/** set expanded state of iop */
void dt_iop_gui_set_expanded(dt_iop_module_t *module, gboolean expanded, gboolean collapse_others);
/** refresh iop according to set expanded state */
void dt_iop_gui_update_expanded(dt_iop_module_t *module);
/** change module state */
void dt_iop_gui_set_state(dt_iop_module_t *module,dt_iop_module_state_t state);

void dt_iop_gui_update_header(dt_iop_module_t *module);

/** commits params and updates piece hash. */
void dt_iop_commit_params(dt_iop_module_t *module, struct dt_iop_params_t *params, struct dt_develop_blend_params_t * blendop_params, struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece);
/** creates a label widget for the expander, with callback to enable/disable this module. */
GtkWidget *dt_iop_gui_get_expander(dt_iop_module_t *module);
/** get the widget of plugin ui in expander */
GtkWidget *dt_iop_gui_get_widget(dt_iop_module_t *module);
/** get the eventbox of plugin ui in expander */
GtkWidget *dt_iop_gui_get_pluginui(dt_iop_module_t *module);

/** requests the focus for this plugin (to draw overlays over the center image) */
void dt_iop_request_focus(dt_iop_module_t *module);
/** loads default settings from database. */
void dt_iop_load_default_params(dt_iop_module_t *module);
/** reloads certain gui/param defaults when the image was switched. */
void dt_iop_reload_defaults(dt_iop_module_t *module);
/** fills the given params blob with the result of per-iso interpolation, searching the matching presets. returns 1 on failure. */
int  dt_iop_load_preset_interpolated_iso(dt_iop_module_t *module, const dt_image_t *cimg, void *output_params, float *output_iso1, float *output_iso2);

/** let plugins have breakpoints: */
int dt_iop_breakpoint(struct dt_develop_t *dev, struct dt_dev_pixelpipe_t *pipe);

/** allow plugins to relinquish CPU and go to sleep for some time */
void dt_iop_nap(int32_t usec);

/** colorspace enums */
typedef enum dt_iop_colorspace_type_t
{
  iop_cs_RAW,
  iop_cs_Lab,
  iop_cs_rgb
}
dt_iop_colorspace_type_t;

/** find which colorspace the module works within */
dt_iop_colorspace_type_t dt_iop_module_colorspace(const dt_iop_module_t *module);

/** flip according to orientation bits, also zoom to given size. */
void dt_iop_flip_and_zoom_8( const uint8_t *in, int32_t iw, int32_t ih, uint8_t *out, int32_t ow, int32_t oh, const int32_t orientation, uint32_t *width, uint32_t *height);

/** for homebrew pixel pipe: zoom pixel array. */
void dt_iop_clip_and_zoom(float *out, const float *const in, const struct dt_iop_roi_t *const roi_out, const struct dt_iop_roi_t * const roi_in, const int32_t out_stride, const int32_t in_stride);

/** clip and zoom mosaiced image without demosaicing it uint16_t -> float4 */
void
dt_iop_clip_and_zoom_demosaic_half_size(
  float *out,
  const uint16_t *const in,
  const struct dt_iop_roi_t *const roi_out,
  const struct dt_iop_roi_t *const roi_in,
  const int32_t out_stride,
  const int32_t in_stride,
  const uint32_t filters);

void
dt_iop_clip_and_zoom_demosaic_half_size_f(
  float *out,
  const float *const in,
  const struct dt_iop_roi_t *const roi_out,
  const struct dt_iop_roi_t *const roi_in,
  const int32_t out_stride,
  const int32_t in_stride,
  const uint32_t filters,
  const float clip);

/** as dt_iop_clip_and_zoom, but for rgba 8-bit channels. */
void dt_iop_clip_and_zoom_8(const uint8_t *i, int32_t ix, int32_t iy, int32_t iw, int32_t ih, int32_t ibw, int32_t ibh,
                            uint8_t *o, int32_t ox, int32_t oy, int32_t ow, int32_t oh, int32_t obw, int32_t obh);

void dt_iop_YCbCr_to_RGB(const float *yuv, float *rgb);
void dt_iop_RGB_to_YCbCr(const float *rgb, float *yuv);

dt_iop_module_t *get_colorout_module();

/** returns the localized plugin name for a given op name. must not be freed. */
gchar *dt_iop_get_localized_name(const gchar * op);

/** takes four points (x,y) in two arrays and fills the cubic coefficients a, such that y = [X] * a, where
  * [X] is the matrix containing all x^3 x^2 x^1 x^0 lines for all four x. */
void dt_iop_estimate_cubic(const float *const x, const float *const y, float *a);

/** evaluates the cubic fit, i.e. returns y = a^t [x^3 x^2 x^1 1] */
static inline float dt_iop_eval_cubic(const float *const a, const float x)
{
  // could be sse4.1 _mm_dot_ps
  const float x4[4] = {x*x*x, x*x, x, 1.0f};
  return a[3]*x4[3] + a[2]*x4[2] + a[1]*x4[1] + a[0]*x4[0];
}

/** estimates an exponential form f(x) = a*x^g from a few (num) points (x, y).
 *  the largest point should be (1.0, y) to really get good data. */
static inline void dt_iop_estimate_exp(const float *const x, const float *const y, const int num, float *coeff)
{
  // map every thing to y = y0*(x/x0)^g
  // and fix (x0,y0) as the last point.
  // assume (x,y) pairs are ordered by ascending x, so this is the last point:
  float x0 = x[num-1], y0 = y[num-1];

  float g = 0.0f;
  int cnt = 0;
  // solving for g yields
  // g = log(y/y0)/log(x/x0)
  //
  // average that over the course of the other samples:
  for(int k=0; k<num-1; k++)
  {
    const float yy = y[k]/y0, xx = x[k]/x0;
    if(yy > 0.0f && xx > 0.0f)
    {
      const float gg = logf(y[k]/y0)/log(x[k]/x0);
      g += gg;
      cnt ++;
    }
  }
  if(cnt)
    g *= 1.0f/cnt;
  else
    g = 1.0f;
  coeff[0] = 1.0f/x0;
  coeff[1] = y0;
  coeff[2] = g;
}

/** evaluates the exp fit. */
static inline float dt_iop_eval_exp(const float *const coeff, const float x)
{
  return coeff[1] * powf(x*coeff[0], coeff[2]);
}

/** Connects common accelerators to an iop module */
void dt_iop_connect_common_accels(dt_iop_module_t *module);

/** Copy alpha channel 1:1 from input to output */
static inline void dt_iop_alpha_copy(const void *ivoid, void *ovoid, const int width, const int height)
{
#ifdef _OPENMP
  #pragma omp parallel for schedule(static) default(none) shared(ovoid,ivoid)
#endif
  for(int j=0; j<height; j++)
  {
    const float *in  = ((const float *)ivoid)+4*width*j+3;
    float *out = ((float *)ovoid)+4*width*j+3;
    for(int i=0; i<width; i++)
    {
      *out = *in;
      out += 4;
      in += 4;
    }
  }
}

#endif

// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.sh
// vim: shiftwidth=2 expandtab tabstop=2 cindent
// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-space on;
