/* This is -*- C -*- */
/* vim: set sw=2: */
/*
* guppi-price-series-core-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-price-series-core.h"
#include <libgnome/gnome-defs.h>
#include <libgnome/gnome-config.h>
#include <libgnome/gnome-i18n.h>
#include <guppi-convenient.h>
#include <guppi-memory.h>
typedef struct _PriceDay PriceDay;
struct _PriceDay {
GDate dt;
guint code;
double op, hi, lo, cl, vo, oi;
};
static GtkObjectClass *parent_class = NULL;
static void
guppi_price_series_core_finalize (GtkObject *obj)
{
GuppiPriceSeriesCore *core = GUPPI_PRICE_SERIES_CORE (obj);
PriceDay **data;
gint i;
data = (PriceDay **)guppi_garray_data (core->garray);
for (i=0; i<core->size; ++i) {
guppi_free (data[i]);
data[i] = NULL;
}
guppi_unref0 (core->garray);
if (parent_class->finalize)
parent_class->finalize (obj);
}
/***************************************************************************/
static PriceDay*
get_priceday (GuppiPriceSeriesCore *core, const GDate *date,
gboolean create_if_missing)
{
gint i;
PriceDay *pd;
PriceDay **data;
g_return_val_if_fail (core && GUPPI_IS_PRICE_SERIES_CORE (core), NULL);
g_return_val_if_fail (date && g_date_valid ((GDate *) date), NULL);
if (core->size == 0) {
if (!create_if_missing)
return NULL;
pd = guppi_new0 (PriceDay, 1);
pd->dt = *date;
core->start_date = *date;
core->end_date = *date;
guppi_garray_set_size (core->garray, 186);
core->size = 1;
data = (PriceDay **)guppi_garray_data (core->garray);
data[0] = pd;
return pd;
}
i = (gint)g_date_julian ((GDate *) date)
- (gint)g_date_julian (&core->start_date);
if (0 <= i && i < core->size) {
data = (PriceDay **) guppi_garray_data (core->garray);
if (create_if_missing && data[i] == NULL) {
pd = guppi_new0 (PriceDay, 1);
pd->dt = *date;
data[i] = pd;
}
/* Check that everything is still in sync. */
g_assert (data[i] == NULL
|| (g_date_compare (&(data[i]->dt), (GDate *) date) == 0));
return data[i];
}
if (i < 0) {
gint new_size, j;
if (!create_if_missing)
return NULL;
new_size = core->size - i;
if (guppi_garray_size (core->garray) < new_size)
guppi_garray_set_size (core->garray, new_size);
data = (PriceDay **) guppi_garray_data (core->garray);
for (j = core->size-1; j >= 0; --j)
data[j-i] = data[j];
for (j=1; j<-i; ++j)
data[j] = NULL;
pd = guppi_new0 (PriceDay, 1);
pd->code = 0;
pd->dt = *date;
core->size = new_size;
core->start_date = *date;
data[0] = pd;
return pd;
}
if (i >= core->size) {
gint new_size, j;
if (!create_if_missing)
return NULL;
new_size = i+1;
if (guppi_garray_size (core->garray) < new_size)
guppi_garray_set_size (core->garray, new_size);
data = (PriceDay **) guppi_garray_data (core->garray);
for (j = core->size; j < new_size-1; ++j)
data[j] = NULL;
pd = guppi_new0 (PriceDay, 1);
pd->dt = *date;
core->size = new_size;
core->end_date = *date;
data[i] = pd;
return pd;
}
g_assert_not_reached ();
return NULL;
}
static gint
priceday_offset (guint code)
{
PriceDay pd;
gpointer data;
switch (code) {
case PRICE_OPEN:
data = &pd.op;
break;
case PRICE_HIGH:
data = &pd.hi;
break;
case PRICE_LOW:
data = &pd.lo;
break;
case PRICE_CLOSE:
data = &pd.cl;
break;
case PRICE_VOLUME:
data = &pd.vo;
break;
case PRICE_OPEN_INTEREST:
data = &pd.oi;
break;
default:
data = NULL;
g_assert_not_reached ();
}
return (guchar *)data - (guchar *)&pd;
}
static GuppiData *
v_data_copy (GuppiData *impl)
{
g_assert_not_reached ();
return NULL;
}
static gint
v_data_size_in_bytes (GuppiData *impl)
{
GuppiPriceSeriesCore *core = GUPPI_PRICE_SERIES_CORE (impl);
gint x = 0;
x += sizeof (GuppiPriceSeriesCore);
x += core->size * sizeof (PriceDay);
x += guppi_garray_size (core->garray) * sizeof (PriceDay *);
return x;
}
static void
v_dateind_bounds (GuppiDateIndexed *impl, GDate *start, GDate *end)
{
GuppiPriceSeriesCore *core = GUPPI_PRICE_SERIES_CORE (impl);
if (start)
*start = core->start_date;
if (end)
*end = core->end_date;
}
static gboolean
v_dateind_valid (GuppiDateIndexed *impl, const GDate *date)
{
GuppiPriceSeriesCore *core = GUPPI_PRICE_SERIES_CORE (impl);
PriceDay *pd;
pd = get_priceday (core, date, FALSE);
return pd && pd->code;
}
/*
static gboolean
v_dateind_step (GuppiDateIndexed *impl, const GDate *orig,
gint delta, GDate *modified)
{
}
*/
static gint
v_dateind_size (GuppiDateIndexed *impl)
{
GuppiPriceSeriesCore *core = GUPPI_PRICE_SERIES_CORE (impl);
PriceDay **data;
gint count = 0;
gint i;
data = (PriceDay **) guppi_garray_data (core->garray);
for (i=0; i < core->size; ++i)
if (data[i] != NULL && data[i]->code)
++count;
return count;
}
static guint
v_ps_valid (GuppiPriceSeries *impl, const GDate *date)
{
GuppiPriceSeriesCore *core = GUPPI_PRICE_SERIES_CORE (impl);
PriceDay *pd;
pd = get_priceday (core, date, FALSE);
return pd ? pd->code : 0;
}
static double
v_ps_get (GuppiPriceSeries *impl, guint code, const GDate *date)
{
GuppiPriceSeriesCore *core = GUPPI_PRICE_SERIES_CORE (impl);
PriceDay *pd;
pd = get_priceday (core, date, FALSE);
if (pd == NULL || (pd->code & code) == 0)
return 0;
switch (code) {
case PRICE_OPEN:
return pd->op;
case PRICE_HIGH:
return pd->hi;
case PRICE_LOW:
return pd->lo;
case PRICE_CLOSE:
return pd->cl;
case PRICE_VOLUME:
return pd->vo;
case PRICE_OPEN_INTEREST:
return pd->oi;
default:
return 0;
};
g_assert_not_reached();
return 0;
}
static void
v_ps_set (GuppiPriceSeries *impl, guint code, const GDate *date, double x)
{
GuppiPriceSeriesCore *core = GUPPI_PRICE_SERIES_CORE (impl);
PriceDay *pd;
pd = get_priceday (core, date, TRUE);
switch (code) {
case PRICE_OPEN:
pd->op = x;
break;
case PRICE_HIGH:
pd->hi = x;
break;
case PRICE_LOW:
pd->lo = x;
break;
case PRICE_CLOSE:
pd->cl = x;
break;
case PRICE_VOLUME:
pd->vo = x;
break;
case PRICE_OPEN_INTEREST:
pd->oi = x;
break;
default:
g_assert_not_reached();
}
pd->code |= code;
}
static gint
v_ps_get_many (GuppiPriceSeries *impl,
const GDate *start_date, gint count,
double *timestamp_buffer,
double *open_buffer,
double *high_buffer,
double *low_buffer,
double *close_buffer)
{
GuppiPriceSeriesCore *core = GUPPI_PRICE_SERIES_CORE (impl);
PriceDay **data;
PriceDay *day;
gint sj, i, i1, j;
sj = g_date_julian (&core->start_date);
i = (gint)g_date_julian ((GDate *) start_date) - sj;
i1 = (gint)g_date_julian (&core->end_date) - sj;
data = (PriceDay **)guppi_garray_data (core->garray);
j = 0;
while (count && 0 <= i && i <= i1) {
if ( (day = data[i]) ) {
if (timestamp_buffer)
timestamp_buffer[j] = sj + i;
if (open_buffer)
open_buffer[j] = day->op;
if (high_buffer)
high_buffer[j] = day->hi;
if (low_buffer)
low_buffer[j] = day->lo;
if (close_buffer)
close_buffer[j] = day->cl;
++j;
if (count > 0)
--count;
else
++count;
}
if (count > 0)
++i;
else
--i;
}
return j;
}
static gint
v_ps_get_range (GuppiPriceSeries *impl,
const GDate *start_date, const GDate *end_date,
double *timestamp_buffer,
double *open_buffer,
double *high_buffer,
double *low_buffer,
double *close_buffer)
{
GuppiPriceSeriesCore *core = GUPPI_PRICE_SERIES_CORE (impl);
PriceDay **data;
PriceDay *day;
gint sj, i, j = 0, i0, i1;
sj = g_date_julian (&core->start_date);
i0 = (gint)g_date_julian ((GDate *) start_date) - sj;
i1 = (gint)g_date_julian ((GDate *) end_date) - sj;
data = (PriceDay **)guppi_garray_data (core->garray);
for (i = i0; i <= i1; ++i) {
if ( (day = data[i]) ) {
if (timestamp_buffer)
timestamp_buffer[j] = sj + i;
if (open_buffer)
open_buffer[j] = day->op;
if (high_buffer)
high_buffer[j] = day->hi;
if (low_buffer)
low_buffer[j] = day->lo;
if (close_buffer)
close_buffer[j] = day->cl;
++j;
}
}
return j;
}
static gboolean
v_ps_get_bounds (GuppiPriceSeries *impl, guint code,
const GDate *start_date, const GDate *end_date,
double *min, double *max)
{
GuppiPriceSeriesCore *core = GUPPI_PRICE_SERIES_CORE (impl);
PriceDay **data;
PriceDay *day;
gint sj, i, i0, i1, offset;
double x, m = 0, M = -1;
gboolean first = TRUE;
sj = g_date_julian (&core->start_date);
i0 = (gint)g_date_julian ((GDate *) start_date) - sj;
i1 = (gint)g_date_julian ((GDate *) end_date) - sj;
data = (PriceDay **)guppi_garray_data (core->garray);
offset = priceday_offset (code);
for (i = i0; i <= i1; ++i) {
if ( (day = data[i]) ) {
x = *(double *)(((guchar *)day) + offset);
if (first) {
m = M = x;
first = FALSE;
} else {
if (x < m) m = x;
if (x > M) M = x;
}
}
}
if (!first) {
if (min) *min = m;
if (max) *max = M;
}
return !first;
}
/***************************************************************************/
static void
guppi_price_series_core_class_init (GuppiPriceSeriesCoreClass *klass)
{
GtkObjectClass* object_class = (GtkObjectClass *)klass;
GuppiDataClass *data_class = GUPPI_DATA_CLASS (klass);
GuppiDateIndexedClass *dind_class = GUPPI_DATE_INDEXED_CLASS (klass);
GuppiPriceSeriesClass *ps_class = GUPPI_PRICE_SERIES_CLASS (klass);
parent_class = gtk_type_class(GUPPI_TYPE_PRICE_SERIES);
object_class->finalize = guppi_price_series_core_finalize;
data_class->is_leaf_type = TRUE;
data_class->copy = v_data_copy;
data_class->get_size_in_bytes = v_data_size_in_bytes;
dind_class->bounds = v_dateind_bounds;
dind_class->valid = v_dateind_valid;
/* dind_class->step = v_dateind_step; */
dind_class->size = v_dateind_size;
ps_class->valid = v_ps_valid;
ps_class->get = v_ps_get;
ps_class->set = v_ps_set;
ps_class->get_many = v_ps_get_many;
ps_class->get_range = v_ps_get_range;
ps_class->get_bounds = v_ps_get_bounds;
}
static void
guppi_price_series_core_init (GuppiPriceSeriesCore *obj)
{
g_date_clear (&obj->start_date, 1);
g_date_clear (&obj->end_date, 1);
obj->size = 0;
obj->garray = guppi_garray_new (sizeof (PriceDay *));
}
GtkType
guppi_price_series_core_get_type (void)
{
static GtkType guppi_price_series_core_type = 0;
if (!guppi_price_series_core_type) {
static const GtkTypeInfo guppi_price_series_core_info = {
"GuppiPriceSeriesCore",
sizeof(GuppiPriceSeriesCore),
sizeof(GuppiPriceSeriesCoreClass),
(GtkClassInitFunc)guppi_price_series_core_class_init,
(GtkObjectInitFunc)guppi_price_series_core_init,
NULL, NULL, (GtkClassInitFunc)NULL
};
guppi_price_series_core_type = gtk_type_unique (GUPPI_TYPE_PRICE_SERIES, &guppi_price_series_core_info);
}
return guppi_price_series_core_type;
}
GuppiPriceSeries *
guppi_price_series_core_new (void)
{
return GUPPI_PRICE_SERIES (guppi_type_new (guppi_price_series_core_get_type ()));
}
syntax highlighted by Code2HTML, v. 0.9.1