/* GIMP LiquidRescale Plug-in Iterator for GAP
 * Copyright (C) 2007-2010 Carlo Baldassi (the "Author") <carlobaldassi@gmail.com>.
 * All Rights Reserved.
 *
 * Based on code generated by gap_filter_codegen.c by Wolfgang Hofer.
 *
 * 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; either version 2 of the Licence, or
 * (at your option) any later version.

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

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org.licences/>.
 */

/* SYTEM (UNIX) includes */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

/* GIMP includes */
#include "gtk/gtk.h"
#include "libgimp/gimp.h"

/* LOCAL includes */
#include "config.h"
#include "../src/main_common.h"

gint p_plug_in_lqr_iter(GimpRunMode run_mode, gint32 total_steps, gdouble current_step, gint32 len_struct);
static void query(void);
static void run(const gchar *name, gint nparam, const GimpParam *param, gint *nretvals, GimpParam **retvals);

GimpPlugInInfo PLUG_IN_INFO =
{
  NULL,  /* init_proc */
  NULL,  /* quit_proc */
  query, /* query_proc */
  run,   /* run_proc */
};

/* ----------------------------------------------------------------------
 * iterator functions for basic datatypes
 * ----------------------------------------------------------------------
 */

static void p_delta_gint(gint *val, gint val_from, gint val_to, gint32 total_steps, gdouble current_step)
{
    double     delta;

    if(total_steps < 1) return;

    delta = ((double)(val_to - val_from) / (double)total_steps) * ((double)total_steps - current_step);
    *val  = ROUND(val_from + delta);
}
static void p_delta_gfloat(gfloat *val, gfloat val_from, gfloat val_to, gint32 total_steps, gdouble current_step)
{
    double     delta;

    if(total_steps < 1) return;

    delta = ((double)(val_to - val_from) / (double)total_steps) * ((double)total_steps - current_step);
    *val  = val_from + delta;
}

/* ----------------------------------------------------------------------
 * p_plug_in_lqr_iter
 * ----------------------------------------------------------------------
 */
gint p_plug_in_lqr_iter(GimpRunMode run_mode, gint32 total_steps, gdouble current_step, gint32 len_struct)
{
    PlugInVals  buf, buf_from, buf_to;

    if(len_struct != sizeof(PlugInVals))
    {
      fprintf(stderr, "ERROR: p_plug_in_lqr_iter  stored Data missmatch in size %d != %d\n",
                       (int)len_struct, sizeof(PlugInVals) );
      return -1;  /* ERROR */
    }

    gimp_get_data("plug_in_lqr-ITER-FROM", &buf_from);
    gimp_get_data("plug_in_lqr-ITER-TO",   &buf_to);
    memcpy(&buf, &buf_from, sizeof(buf));

    p_delta_gint(&buf.new_width, buf_from.new_width, buf_to.new_width, total_steps, current_step);
    p_delta_gint(&buf.new_height, buf_from.new_height, buf_to.new_height, total_steps, current_step);
    buf.pres_layer_ID = buf_to.pres_layer_ID;
    p_delta_gint(&buf.pres_coeff, buf_from.pres_coeff, buf_to.pres_coeff, total_steps, current_step);
    buf.disc_layer_ID = buf_to.disc_layer_ID;
    p_delta_gint(&buf.disc_coeff, buf_from.disc_coeff, buf_to.disc_coeff, total_steps, current_step);
    p_delta_gfloat(&buf.rigidity, buf_from.rigidity, buf_to.rigidity, total_steps, current_step);
    buf.rigmask_layer_ID = buf_to.rigmask_layer_ID;
    p_delta_gint(&buf.delta_x, buf_from.delta_x, buf_to.delta_x, total_steps, current_step);
    p_delta_gfloat(&buf.enl_step, buf_from.enl_step, buf_to.enl_step, total_steps, current_step);
    buf.resize_aux_layers = buf_to.resize_aux_layers;
    buf.resize_canvas = buf_to.resize_canvas;
    buf.output_target = buf_to.output_target;
    buf.output_seams = buf_to.output_seams;
    buf.nrg_func = buf_to.nrg_func;
    buf.res_order = buf_to.res_order;
    buf.mask_behavior = buf_to.mask_behavior;
    buf.scaleback = buf_to.scaleback;
    buf.scaleback_mode = buf_to.scaleback_mode;
    buf.no_disc_on_enlarge = buf_to.no_disc_on_enlarge;
    g_strlcpy(buf.pres_layer_name, buf_to.pres_layer_name, VALS_MAX_NAME_LENGTH);
    g_strlcpy(buf.disc_layer_name, buf_to.disc_layer_name, VALS_MAX_NAME_LENGTH);
    g_strlcpy(buf.rigmask_layer_name, buf_to.rigmask_layer_name, VALS_MAX_NAME_LENGTH);
    g_strlcpy(buf.selected_layer_name, buf_to.selected_layer_name, VALS_MAX_NAME_LENGTH);

    gimp_set_data("plug_in_lqr", &buf, sizeof(buf));

    return 0; /* OK */
}
MAIN ()

/* ----------------------------------------------------------------------
 * install (query) -Iterator
 * ----------------------------------------------------------------------
 */

static void query ()
{
  char l_blurb_text[300];
  char iter_name[300];

  static GimpParamDef args_iter[] =
  {
    {GIMP_PDB_INT32, "run_mode", "non-interactive"},
    {GIMP_PDB_INT32, "total_steps", "total number of steps (# of layers-1 to apply the related plug-in)"},
    {GIMP_PDB_FLOAT, "current_step", "current (for linear iterations this is the layerstack position, otherwise some value inbetween)"},
    {GIMP_PDB_INT32, "len_struct", "length of stored data structure with id is equal to the plug_in  proc_name"},
  };
  static int nargs_iter = G_N_ELEMENTS (args_iter);

  static GimpParamDef *return_vals = NULL;
  static int nreturn_vals = 0;

  g_snprintf(l_blurb_text, sizeof(l_blurb_text), "This procedure calculates the modified values for one iterationstep for the call of %s", PLUG_IN_NAME);
  g_snprintf(iter_name, sizeof(iter_name), "%s-Iterator", PLUG_IN_NAME);

  gimp_install_procedure(iter_name,
                         l_blurb_text,
                         "",
                         "Carlo Baldassi <carlobaldassi@gmail.com>",
                         "Carlo Baldassi <carlobaldassi@gmail.com>",
                         "2008",
                         NULL,    /* do not appear in menus */
                         NULL,
                         GIMP_PLUGIN,
                         nargs_iter, nreturn_vals,
                         args_iter, return_vals);

}


/* ----------------------------------------------------------------------
 * run Iterator
 * ----------------------------------------------------------------------
 */


static void
run (const gchar    *name,
     gint      n_params,
     const GimpParam  *param,
     gint     *nreturn_vals,
     GimpParam **return_vals)
{
  static GimpParam values[1];
  GimpRunMode run_mode;
  GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  //gint32     image_id;
  gint32  len_struct;
  gint32  total_steps;
  gdouble current_step;

  gint32     l_rc;

  *nreturn_vals = 1;
  *return_vals = values;
  l_rc = 0;

  run_mode = param[0].data.d_int32;

  if ((run_mode == GIMP_RUN_NONINTERACTIVE) && (n_params == 4))
  {
    total_steps  =  param[1].data.d_int32;
    current_step =  param[2].data.d_float;
    len_struct   =  param[3].data.d_int32;
    l_rc = p_plug_in_lqr_iter(run_mode, total_steps, current_step, len_struct);
    if(l_rc < 0)
    {
       status = GIMP_PDB_EXECUTION_ERROR;
    }
  }
  else status = GIMP_PDB_CALLING_ERROR;

  values[0].type = GIMP_PDB_STATUS;
  values[0].data.d_status = status;

}
