/* This is -*- C -*- */
/* vim: set sw=2: */

/*
 * guppi-date-series-calc-impl.c
 *
 * Copyright (C) 2000 EMC Capital Management, Inc.
 * Copyright (C) 2001 The Free Software Foundation
 *
 * Developed by Jon Trowbridge <trow@gnu.org>
 *
 * 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
 * License, 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 */

#include <config.h>
#include "guppi-date-series-calc.h"

#include <libgnome/gnome-defs.h>
#include <libgnome/gnome-config.h>
#include <libgnome/gnome-i18n.h>

#include <guppi-memory.h>

static GtkObjectClass *parent_class = NULL;

enum {
  ARG_0,
  ARG_USE_CACHE,
  ARG_BOUNDS_FN,
  ARG_VALID_FN,
  ARG_GET_FN,
  ARG_GET_MANY_FN,
  ARG_GET_RANGE_FN,
  ARG_GET_BOUNDS_FN,
  ARG_USER_DATA_DESTROY_FN,
  ARG_USER_DATA
};

static void
guppi_date_series_calc_get_arg (GtkObject *obj, GtkArg *arg, guint arg_id)
{
  switch (arg_id) {

  default:
    break;
  };
}

static void
guppi_date_series_calc_set_arg (GtkObject *obj, GtkArg *arg, guint arg_id)
{
  GuppiDateSeriesCalc *calc = GUPPI_DATE_SERIES_CALC (obj);
  gpointer ptr = GTK_VALUE_POINTER (*arg);
  gboolean b;

  switch (arg_id) {

  case ARG_USE_CACHE:
    b = GTK_VALUE_BOOL (*arg);
    if (b != calc->using_cache) {
      guppi_unref0 (calc->cache);
      calc->hinted_cache = FALSE;
      calc->using_cache = b;
    }
    break;

  case ARG_BOUNDS_FN:
    calc->bounds = (void (*) (GDate *, GDate *, gpointer)) ptr;
    break;
    
  case ARG_VALID_FN:
    calc->valid = (gboolean (*) (const GDate *, gpointer)) ptr;
    break;

  case ARG_GET_FN:
    calc->get = (double (*) (const GDate *, gpointer)) ptr;
    break;
    
  case ARG_GET_MANY_FN:
    calc->get_many = (gint (*) (const GDate *, gint, double *, gpointer)) ptr;
    break;

  case ARG_GET_RANGE_FN:
    calc->get_range =
      (gint (*) (const GDate *, const GDate *, double *, double *, gint, gpointer)) ptr;
    break;

  case ARG_GET_BOUNDS_FN:
    calc->get_bounds =
      (gboolean (*) (const GDate *, const GDate *, double *, double *, gpointer)) ptr;
    break;

  case ARG_USER_DATA_DESTROY_FN:
    calc->user_data_destroy_fn = (void (*) (gpointer)) ptr;
    break;
    
  case ARG_USER_DATA:
    if (calc->user_data && calc->user_data_destroy_fn)
      calc->user_data_destroy_fn (calc->user_data);
    calc->user_data = ptr;
    break;

  default:
    break;
  };
}

static void
guppi_date_series_calc_finalize (GtkObject *obj)
{
  GuppiDateSeriesCalc *calc = GUPPI_DATE_SERIES_CALC (obj);

  if (calc->user_data && calc->user_data_destroy_fn)
    calc->user_data_destroy_fn (calc->user_data);

  if (calc->cache)
    guppi_unref0 (calc->cache);

  if (parent_class->finalize)
    parent_class->finalize (obj);
}

/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */

static GuppiData *
v_data_copy (GuppiData *d)
{
  g_assert_not_reached ();
  return NULL;
}

static gint
v_data_get_size_in_bytes (GuppiData *d)
{
  return -1;
}

static void
v_di_bounds (GuppiDateIndexed *di, GDate *start, GDate *end)
{
  GuppiDateSeriesCalc *calc = GUPPI_DATE_SERIES_CALC (di);
  GDate sd, ed;

  g_assert (calc->bounds);
  calc->bounds (&sd, &ed, calc->user_data);

  if (calc->using_cache && calc->cache == NULL)
    calc->cache = GUPPI_DATE_SERIES (guppi_data_new ("GuppiDateSeriesCore"));

  if (calc->cache && !calc->hinted_cache) {
    guppi_date_indexed_bounds_hint (GUPPI_DATE_INDEXED (calc->cache), 
				    &sd, &ed);
    calc->hinted_cache = TRUE;
  }

  if (start) *start = sd;
  if (end) *end = ed;
}

static gboolean
v_di_valid (GuppiDateIndexed *di, const GDate *dt)
{
  GuppiDateSeriesCalc *calc = GUPPI_DATE_SERIES_CALC (di);

  g_assert (calc->valid);
  return calc->valid ((GDate *)dt, calc->user_data);
}

static double
v_ds_get (GuppiDateSeries *ser, const GDate *dt)
{
  GuppiDateSeriesCalc *calc = GUPPI_DATE_SERIES_CALC (ser);
  double x;
  if (calc->cache
      && guppi_date_indexed_valid (GUPPI_DATE_INDEXED (calc->cache), dt))
    return guppi_date_series_get (calc->cache, dt);

  if (calc->using_cache && calc->cache == NULL)
    calc->cache = GUPPI_DATE_SERIES (guppi_data_new ("GuppiDateSeriesCore"));

  g_assert (calc->get);
  
  x = calc->get (dt, calc->user_data);

  if (calc->cache) 
    guppi_date_series_set (calc->cache, dt, x);

  return x;
}

static gboolean
v_ds_get_many (GuppiDateSeries *ser, const GDate *dt, gint count, double *buf, gint *retval)
{
  GuppiDateSeriesCalc *calc = GUPPI_DATE_SERIES_CALC (ser);

  if (calc->get_many) {
    gint r;
    r = calc->get_many (dt, count, buf, calc->user_data);
    if (retval)
      *retval = r;
    return TRUE;
  }

  return FALSE;
}

static gboolean
v_ds_get_range (GuppiDateSeries *ser, const GDate *sd, const GDate *ed,
		double *tbuf, double *buf, gint bufsize, gint *retval)
{
  GuppiDateSeriesCalc *calc = GUPPI_DATE_SERIES_CALC (ser);

  if (calc->get_range) {
    gint r;
    r = calc->get_range (sd, ed, tbuf, buf, bufsize, calc->user_data);
    if (retval)
      *retval = r;
    return TRUE;
  }

  return FALSE;
}

static gboolean
v_ds_get_bounds (GuppiDateSeries *ser, const GDate *sd, const GDate *ed,
		 double *min, double *max, gboolean *retval)
{
  GuppiDateSeriesCalc *calc = GUPPI_DATE_SERIES_CALC (ser);

  if (calc->get_bounds) {
    gboolean r;
    r = calc->get_bounds (sd, ed, min, max, calc->user_data);
    if (retval)
      *retval = r;
    return TRUE;
  }

  return FALSE;
}

/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */

#define add_arg(str, symb) \
gtk_object_add_arg_type("GuppiDateSeriesCalc::" str, GTK_TYPE_POINTER, GTK_ARG_WRITABLE, symb)

static void
guppi_date_series_calc_class_init (GuppiDateSeriesCalcClass *klass)
{
  GtkObjectClass* object_class = (GtkObjectClass *)klass;
  GuppiDataClass *data_class = GUPPI_DATA_CLASS (klass);
  GuppiDateIndexedClass *di_class = GUPPI_DATE_INDEXED_CLASS (klass);
  GuppiDateSeriesClass *ds_class = GUPPI_DATE_SERIES_CLASS (klass);

  parent_class = gtk_type_class (GUPPI_TYPE_DATE_SERIES);

  object_class->get_arg = guppi_date_series_calc_get_arg;
  object_class->set_arg = guppi_date_series_calc_set_arg;
  object_class->finalize = guppi_date_series_calc_finalize;

  data_class->copy = v_data_copy;
  data_class->get_size_in_bytes = v_data_get_size_in_bytes;
  data_class->is_leaf_type = TRUE;

  di_class->bounds = v_di_bounds;
  di_class->valid = v_di_valid;

  ds_class->get = v_ds_get;
  ds_class->get_many = v_ds_get_many;
  ds_class->get_range = v_ds_get_range;
  ds_class->get_bounds = v_ds_get_bounds;

  gtk_object_add_arg_type("GuppiDateSeriesCalc::use_cache",
			  GTK_TYPE_BOOL, GTK_ARG_WRITABLE, ARG_USE_CACHE);

  add_arg ("bounds_fn", ARG_BOUNDS_FN);
  add_arg ("valid_fn", ARG_VALID_FN);
  add_arg ("get_fn", ARG_GET_FN);
  add_arg ("get_many_fn", ARG_GET_MANY_FN);
  add_arg ("get_range_fn", ARG_GET_RANGE_FN);
  add_arg ("get_bounds_fn", ARG_GET_BOUNDS_FN);
  add_arg ("user_data_destroy_fn", ARG_USER_DATA_DESTROY_FN);
  add_arg ("user_data", ARG_USER_DATA);
}

static void
guppi_date_series_calc_init (GuppiDateSeriesCalc *obj)
{

}

GtkType
guppi_date_series_calc_get_type (void)
{
  static GtkType guppi_date_series_calc_type = 0;
  if (!guppi_date_series_calc_type) {
    static const GtkTypeInfo guppi_date_series_calc_info = {
      "GuppiDateSeriesCalc",
      sizeof (GuppiDateSeriesCalc),
      sizeof (GuppiDateSeriesCalcClass),
      (GtkClassInitFunc)guppi_date_series_calc_class_init,
      (GtkObjectInitFunc)guppi_date_series_calc_init,
      NULL, NULL, (GtkClassInitFunc)NULL
    };
    guppi_date_series_calc_type = gtk_type_unique (GUPPI_TYPE_DATE_SERIES, &guppi_date_series_calc_info);
  }
  return guppi_date_series_calc_type;
}



syntax highlighted by Code2HTML, v. 0.9.1