/* ---------------------------------------
 * gap_track_detail_on_top_layers_lastvals
 * ---------------------------------------
 * processing based on last values used in the same gimp session.
 * (uses defaults when called the 1.st time)
 * Intended for use in the player
 */
gint32
gap_track_detail_on_top_layers_lastvals(gint32 imageId)
{
    gint32       rc;
    gboolean     doProgress;
    FilterValues fiVals;

    /* clear undo stack */
    if (gimp_image_undo_is_enabled(imageId))
    {
        gimp_image_undo_disable(imageId);
    }

    doProgress = FALSE;
    gap_detail_tracking_get_values(&fiVals);
    rc = gap_track_detail_on_top_layers(imageId, doProgress, &fiVals);

    gimp_image_undo_enable(imageId); /* clear undo stack */

    return(rc);

}  /* end gap_track_detail_on_top_layers_lastvals */
static void
run (const gchar *name,          /* name of plugin */
     gint nparams,               /* number of in-paramters */
     const GimpParam * param,    /* in-parameters */
     gint *nreturn_vals,         /* number of out-parameters */
     GimpParam ** return_vals)   /* out-parameters */
{
  const gchar *l_env;
  gint32       image_id = -1;
  gboolean doProgress;
  gboolean doFlush;
  GapLastvalAnimatedCallInfo  animCallInfo;


  /* Get the runmode from the in-parameters */
  GimpRunMode run_mode = param[0].data.d_int32;

  /* status variable, use it to check for errors in invocation usualy only
     during non-interactive calling */
  GimpPDBStatusType status = GIMP_PDB_SUCCESS;

  /* always return at least the status to the caller. */
  static GimpParam values[2];

  INIT_I18N();

  l_env = g_getenv("GAP_DEBUG");
  if(l_env != NULL)
  {
    if((*l_env != 'n') && (*l_env != 'N')) gap_debug = 1;
  }

  if(gap_debug)
  {
    printf("\n\nDEBUG: run %s\n", name);
  }



  if(strcmp(name, GAP_DETAIL_TRACKING_XML_ALIGNER_PLUG_IN_NAME) == 0)
  {
    runXmlAlign(name, nparams, param, nreturn_vals, return_vals);
    return;
  }

  if(strcmp(name, GAP_EXACT_ALIGNER_PLUG_IN_NAME) == 0)
  {
    runExactAlign(name, nparams, param, nreturn_vals, return_vals);
    return;
  }


  doProgress = FALSE;
  doFlush = FALSE;

  /* initialize the return of the status */
  values[0].type = GIMP_PDB_STATUS;
  values[0].data.d_status = status;
  values[1].type = GIMP_PDB_DRAWABLE;
  values[1].data.d_drawable = -1;
  *nreturn_vals = 2;
  *return_vals = values;

  /* init default values and Possibly retrieve data from a previous interactive run */
  gap_detail_tracking_get_values(&fiVals);

  /* get image and drawable */
  image_id = param[1].data.d_int32;


  /* how are we running today? */
  switch (run_mode)
  {
    case GIMP_RUN_INTERACTIVE:
      /* detail tracking primary feature is intended to work without dialog interaction
       * when ivoked by menu or keyboard shortcut using PLUG_IN_NAME.
       * This plug in also registers with a 2nd variant PLUG_IN_NAME_CFG
       * where the user can configure the options (for one gimp session)
       */
      if(strcmp(name, PLUG_IN_NAME_CFG) ==0)
      {
        gboolean dialogOk;

        if (fiVals.coordsRelToFrame1)
        {
          /* default offsets for handle at center */
          fiVals.offsX = gimp_image_width(image_id) / 2.0;
          fiVals.offsY = gimp_image_height(image_id) / 2.0;
        }


        dialogOk = gap_detail_tracking_dialog(&fiVals);
        if( dialogOk != TRUE)
        {
          status = GIMP_PDB_CALLING_ERROR;
        }

      }
      doProgress = TRUE;
      doFlush =  TRUE;
      break;

    case GIMP_RUN_NONINTERACTIVE:
      /* check to see if invoked with the correct number of parameters */
      if (nparams == global_number_in_args)
      {
          fiVals.refShapeRadius               = param[3].data.d_int32;
          fiVals.targetMoveRadius             = param[4].data.d_int32;
          fiVals.loacteColodiffThreshold      = param[5].data.d_float;
          fiVals.coordsRelToFrame1            = (param[6].data.d_int32 == 0) ? FALSE : TRUE;
          fiVals.offsX                        = param[7].data.d_int32;
          fiVals.offsY                        = param[8].data.d_int32;
          fiVals.offsRotate                   = param[9].data.d_float;
          fiVals.enableScaling                = (param[10].data.d_int32 == 0) ? FALSE : TRUE;
          fiVals.bgLayerIsReference           = (param[11].data.d_int32 == 0) ? FALSE : TRUE;
          fiVals.removeMidlayers              = (param[12].data.d_int32 == 0) ? FALSE : TRUE;

          fiVals.moveLogFile[0] = '\0';
          if(param[13].data.d_string != NULL)
          {
            g_snprintf(fiVals.moveLogFile, sizeof(fiVals.moveLogFile) -1, "%s", param[13].data.d_string);
          }

      }
      else
      {
        status = GIMP_PDB_CALLING_ERROR;
      }

      break;

    case GIMP_RUN_WITH_LAST_VALS:
      animCallInfo.animatedCallInProgress = FALSE;
      gimp_get_data(GAP_LASTVAL_KEY_ANIMATED_CALL_INFO, &animCallInfo);

      if(animCallInfo.animatedCallInProgress != TRUE)
      {
        doProgress = TRUE;
        doFlush =  TRUE;
      }
      break;

    default:
      break;
  }

  if (status == GIMP_PDB_SUCCESS)
  {
    gulong cache_ntiles;
    gulong regionTileWidth;
    gulong regionTileHeight;

    gimp_image_undo_group_start (image_id);

    /* this plug in repeatedly accesses the same tiles in the same pixel regionsarea
     * therefore tile caching is essential for performance reason
     * therefore calculate optimal tile cache size (but limit to 300 tiles that should be enogh
     * in most practical use cases)
     */
    regionTileWidth = 1 + (2 * (fiVals.targetMoveRadius + fiVals.refShapeRadius))/ gimp_tile_width() ;
    regionTileHeight = 1 + (2 * (fiVals.targetMoveRadius + fiVals.refShapeRadius))/ gimp_tile_height() ;

    /* processing may track 2 details in different regions of same size */
    cache_ntiles = (regionTileWidth * regionTileHeight) * 2;

    gimp_tile_cache_ntiles (MAX(300, cache_ntiles));

    /* Run the main function */
    values[1].data.d_drawable =
          gap_track_detail_on_top_layers(image_id, doProgress, &fiVals);

    gimp_image_undo_group_end (image_id);

    if (values[1].data.d_drawable < 0)
    {
       status = GIMP_PDB_CALLING_ERROR;
    }

    /* If run mode is interactive, flush displays, else (script) don't
     * do it, as the screen updates would make the scripts slow
     */
    if (doFlush)
    {
      gimp_displays_flush ();
    }


  }
  values[0].data.d_status = status;

}       /* end run */