/* This is -*- C -*- */
/* vim: set sw=2: */
/*
* guppi-date-series.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.h"
#include <stdlib.h>
#include <string.h>
#include <libgnome/gnome-defs.h>
#include <libgnome/gnome-config.h>
#include <libgnome/gnome-i18n.h>
#include <guppi-convenient.h>
static GtkObjectClass *parent_class = NULL;
static void
guppi_date_series_finalize (GtkObject *obj)
{
if (parent_class->finalize)
parent_class->finalize (obj);
}
static xmlNodePtr
export_xml_element (GuppiDateIndexed *dind, const GDate *dt, GuppiXMLDocument *doc)
{
double x;
x = guppi_date_series_get (GUPPI_DATE_SERIES (dind), (GDate *)dt);
return guppi_xml_new_text_nodef (doc, "scalar", "%g", x);
}
static gboolean
import_xml_element (GuppiDateIndexed *dind, const GDate *dt, GuppiXMLDocument *doc, xmlNodePtr node)
{
gchar *s;
if (strcmp (node->name, "scalar")) {
g_warning ("improper element type \"%s\"", node->name);
return FALSE;
}
s = xmlNodeListGetString (doc->doc, node->xmlChildrenNode, 1);
guppi_date_series_set (GUPPI_DATE_SERIES (dind), (GDate *) dt, atof (s));
free (s);
return TRUE;
}
static void
guppi_date_series_class_init (GuppiDateSeriesClass *klass)
{
GtkObjectClass *object_class = (GtkObjectClass *)klass;
GuppiDateIndexedClass *dind_class = GUPPI_DATE_INDEXED_CLASS (klass);
parent_class = gtk_type_class (GUPPI_TYPE_DATE_INDEXED);
object_class->finalize = guppi_date_series_finalize;
dind_class->export_xml_element = export_xml_element;
dind_class->import_xml_element = import_xml_element;
}
static void
guppi_date_series_init (GuppiDateSeries *obj)
{
}
GtkType
guppi_date_series_get_type (void)
{
static GtkType guppi_date_series_type = 0;
if (!guppi_date_series_type) {
static const GtkTypeInfo guppi_date_series_info = {
"GuppiDateSeries",
sizeof (GuppiDateSeries),
sizeof (GuppiDateSeriesClass),
(GtkClassInitFunc)guppi_date_series_class_init,
(GtkObjectInitFunc)guppi_date_series_init,
NULL, NULL, (GtkClassInitFunc)NULL
};
guppi_date_series_type = gtk_type_unique (GUPPI_TYPE_DATE_INDEXED, &guppi_date_series_info);
}
return guppi_date_series_type;
}
double
guppi_date_series_get (GuppiDateSeries *ser, const GDate *dt)
{
GuppiDateSeriesClass *klass;
g_return_val_if_fail (GUPPI_IS_DATE_SERIES (ser), 0);
g_return_val_if_fail (dt && g_date_valid ((GDate *)dt), 0);
klass = GUPPI_DATE_SERIES_CLASS (GTK_OBJECT (ser)->klass);
g_assert (klass->get);
return klass->get (ser, dt);
}
void
guppi_date_series_set (GuppiDateSeries *ser, const GDate *dt, double x)
{
GuppiDateSeriesClass *klass;
g_return_if_fail (GUPPI_IS_DATE_SERIES (ser));
g_return_if_fail (guppi_data_can_change (GUPPI_DATA (ser)));
g_return_if_fail (dt && g_date_valid ((GDate *) dt));
klass = GUPPI_DATE_SERIES_CLASS (GTK_OBJECT (ser)->klass);
g_assert (klass->set);
klass->set (ser, dt, x);
}
void
guppi_date_series_unset (GuppiDateSeries *ser, const GDate *dt)
{
GuppiDateSeriesClass *klass;
g_return_if_fail (GUPPI_IS_DATE_SERIES (ser));
g_return_if_fail (guppi_data_can_change (GUPPI_DATA (ser)));
g_return_if_fail (dt && g_date_valid ((GDate *) dt));
klass = GUPPI_DATE_SERIES_CLASS (GTK_OBJECT (ser)->klass);
g_assert (klass->unset);
klass->unset (ser, dt);
}
gint
guppi_date_series_get_many (GuppiDateSeries *ser,
const GDate *base_date, gint count,
double *buffer)
{
GuppiDateSeriesClass *klass;
gint retval;
GDate dt;
gint j;
g_return_val_if_fail (GUPPI_IS_DATE_SERIES (ser), 0);
g_return_val_if_fail (base_date && g_date_valid ((GDate *) base_date), 0);
if (count == 0)
return 0;
g_return_val_if_fail (buffer, 0);
klass = GUPPI_DATE_SERIES_CLASS (GTK_OBJECT (ser)->klass);
if (klass->get_many && klass->get_many (ser, base_date, count, buffer, &retval))
return retval;
dt = *base_date;
j = 0;
while (count
&& g_date_valid (&dt)
&& guppi_date_indexed_in_bounds (GUPPI_DATE_INDEXED (ser), &dt)) {
if (guppi_date_indexed_valid (GUPPI_DATE_INDEXED (ser), &dt)) {
buffer[j] = guppi_date_series_get (ser, &dt);
++j;
if (count > 0)
--count;
else
++count;
}
if (count > 0)
g_date_add_days (&dt, 1);
else
g_date_subtract_days (&dt, 1);
}
return j;
}
gint
guppi_date_series_get_range (GuppiDateSeries *ser,
const GDate *start_date, const GDate *end_date,
double *buffer, gint bufsize)
{
g_return_val_if_fail (GUPPI_IS_DATE_SERIES (ser), 0);
g_return_val_if_fail (start_date && g_date_valid ((GDate *) start_date), 0);
g_return_val_if_fail (end_date && g_date_valid ((GDate *) end_date), 0);
if (bufsize == 0)
return 0;
g_return_val_if_fail (buffer, 0);
return guppi_date_series_get_range_timecoded (ser, start_date, end_date,
NULL, buffer, bufsize);
}
gint
guppi_date_series_get_range_timecoded (GuppiDateSeries *ser,
const GDate *start_date, const GDate *end_date,
double *timecode, double *buffer,
gint bufsize)
{
GuppiDateSeriesClass *klass;
gint retval;
GDate sd, ed, dt;
gint j;
g_return_val_if_fail (GUPPI_IS_DATE_SERIES (ser), 0);
g_return_val_if_fail (start_date && g_date_valid ((GDate *) start_date), 0);
g_return_val_if_fail (end_date && g_date_valid ((GDate *) end_date), 0);
if (bufsize == 0)
return 0;
g_return_val_if_fail (buffer || timecode, 0);
sd = *start_date;
ed = *end_date;
guppi_date_indexed_clamp (GUPPI_DATE_INDEXED (ser), &sd);
guppi_date_indexed_clamp (GUPPI_DATE_INDEXED (ser), &ed);
if (g_date_gt (&sd, &ed)) {
dt = sd;
sd = ed;
ed = sd;
}
klass = GUPPI_DATE_SERIES_CLASS (GTK_OBJECT (ser)->klass);
/* Try to use an implementation-supplied method. */
if (klass->get_range
&& klass->get_range (ser, &sd, &ed, timecode, buffer, bufsize, &retval))
return retval;
dt = sd;
j = 0;
if (!guppi_date_indexed_valid (GUPPI_DATE_INDEXED (ser), &dt))
guppi_date_indexed_incr (GUPPI_DATE_INDEXED (ser), &dt);
while (g_date_lteq (&dt, &ed) && j < bufsize) {
if (timecode)
timecode[j] = g_date_julian (&dt);
if (buffer)
buffer[j] = guppi_date_series_get (ser, &dt);
++j;
guppi_date_indexed_incr (GUPPI_DATE_INDEXED (ser), &dt);
}
return j;
}
gboolean
guppi_date_series_get_bounds (GuppiDateSeries *ser,
const GDate *start_date, const GDate *end_date,
double *min, double *max)
{
GuppiDateSeriesClass *klass;
gboolean retval;
GDate sd, ed;
double *buffer;
gint i, N;
double m, M;
g_return_val_if_fail (GUPPI_IS_DATE_SERIES (ser), 0);
g_return_val_if_fail (start_date && g_date_valid ((GDate *) start_date), 0);
g_return_val_if_fail (end_date && g_date_valid ((GDate *) end_date), 0);
klass = GUPPI_DATE_SERIES_CLASS (GTK_OBJECT (ser)->klass);
sd = *start_date;
ed = *end_date;
guppi_date_indexed_clamp (GUPPI_DATE_INDEXED (ser), &sd);
guppi_date_indexed_clamp (GUPPI_DATE_INDEXED (ser), &ed);
if (g_date_gt (&sd, &ed)) {
GDate dt = sd;
sd = ed;
ed = dt;
}
/* Try to use an implementation-supplied method. */
if (klass->get_bounds
&& klass->get_bounds (ser, &sd, &ed, min, max, &retval))
return retval;
N = (gint)g_date_julian (&ed) - (gint)g_date_julian (&ed) + 1;
buffer = guppi_new (double, N);
N = guppi_date_series_get_range (ser, start_date, end_date,
buffer, N);
if (N == 0)
return FALSE;
m = M = buffer[0];
for (i=1; i<N; ++i) {
double x = buffer[i];
if (x < m)
m = x;
if (x > M)
M = x;
}
if (min)
*min = m;
if (max)
*max = M;
guppi_free (buffer);
return TRUE;
}
syntax highlighted by Code2HTML, v. 0.9.1