/* ParamCurve.c */
/* Paul Boersma, April 27, 1997 */

#include "ParamCurve.h"

static void destroy (I) {
	iam (ParamCurve);
	forget (my x);
	forget (my y);
	inherited (ParamCurve) destroy (me);
}

static void info (I) {
	iam (ParamCurve);
	long i;
	double xmin = 1e300, xmax = -1e300, ymin = 1e300, ymax = -1e300;
	for (i = 1; i <= my x -> nx; i ++) {
		double value = my x -> z [1] [i];
		if (value < xmin) xmin = value;
		if (value > xmax) xmax = value;
	}
	for (i = 1; i <= my y -> nx; i ++) {
		double value = my y -> z [1] [i];
		if (value < ymin) ymin = value;
		if (value > ymax) ymax = value;
	}
	Melder_information ("domain:\n   start: %.8g\n   end: %.8g\n"
		"x:\n   minimum: %.8g\n   maximum: %.8g\n"
		"   sampling: nx = %ld, dx = %.8g (rate %.8g), x1 = %.8g\n"
		"y:\n   minimum: %.8g\n   maximum: %.8g\n"
		"   sampling: ny = %ld, dy = %.8g (rate %.8g), y1 = %.8g",
		my xmin, my xmax,
		xmin, xmax, my x -> nx, my x -> dx, 1.0 / my x -> dx, my x -> x1,
		ymin, ymax, my y -> nx, my y -> dx, 1.0 / my y -> dx, my y -> x1);
}

static int copy (I, thou) {
	iam (ParamCurve); thouart (ParamCurve);
	thy x = NULL;
	thy y = NULL;
	if (! inherited (ParamCurve) copy (me, thee) ||
		! (thy x = Data_copy (my x)) ||
		! (thy y = Data_copy (my y)))
		return 0;
	return 1;
}

static int equal (I, thou) {
	iam (ParamCurve); thouart (ParamCurve);
	return inherited (ParamCurve) equal (me, thee) && Data_equal (my x, thy x) && Data_equal (my y, thy y);
}

static int writeAscii (I, FILE *f) {
	iam (ParamCurve);
	return Data_writeAscii (my x, f) && Data_writeAscii (my y, f);
}

static int readAscii (I, FILE *f) {
	iam (ParamCurve);
	return (my x = new (Sound)) != NULL && (my y = new (Sound)) != NULL &&
		Data_readAscii (my x, f) && Data_readAscii (my y, f);
}

static int writeBinary (I, FILE *f) {
	iam (ParamCurve);
	return Data_writeBinary (my x, f) && Data_writeBinary (my y, f);
}

static int readBinary (I, FILE *f) {
	iam (ParamCurve);
	return (my x = new (Sound)) != NULL && (my y = new (Sound)) != NULL &&
		Data_readBinary (my x, f) && Data_readBinary (my y, f);
}

class_methods (ParamCurve, Function)
	class_method (destroy)
	class_method (info)
	class_method (copy)
	class_method (equal)
	class_method (writeAscii)
	class_method (readAscii)
	class_method (writeBinary)
	class_method (readBinary)
class_methods_end

int ParamCurve_init (I, Any void_x, Any void_y) {
	iam (ParamCurve);
	Sound x = void_x, y = void_y;
	if (x -> xmax <= y -> xmin || x -> xmin >= y -> xmax)
		return Melder_error ("Domains do not overlap.");
	if (! (my x = Data_copy (x)) || ! (my y = Data_copy (y)))
		return 0;
	my xmin = x -> xmin > y -> xmin ? x -> xmin : y -> xmin;
	my xmax = x -> xmax < y -> xmax ? x -> xmax : y -> xmax; 
	return 1;
}

Any ParamCurve_create (Any x, Any y) {
	ParamCurve me = new (ParamCurve);
	if (! me || ! ParamCurve_init (me, x, y)) { forget (me); return Melder_errorp ("ParamCurve not created."); }
	return me;
}

int ParamCurve_draw (I, Graphics g, double t1, double t2, double dt,
	double x1, double x2, double y1, double y2, int garnish)
{
	iam (ParamCurve);
	long numberOfPoints, i;
	float *x, *y;
	if (t2 <= t1) {
		double tx1 = my x -> x1;
		double ty1 = my y -> x1;
		double tx2 = my x -> x1 + (my x -> nx - 1) * my x -> dx;
		double ty2 = my y -> x1 + (my y -> nx - 1) * my y -> dx;
		t1 = tx1 > ty1 ? tx1 : ty1;
		t2 = tx2 < ty2 ? tx2 : ty2;
	}
	if (x2 <= x1) Matrix_getWindowExtrema (my x, 0, 0, 1, 1, & x1, & x2);
	if (x1 == x2) { x1 -= 1.0; x2 += 1.0; }
	if (y2 <= y1) Matrix_getWindowExtrema (my y, 0, 0, 1, 1, & y1, & y2);
	if (y1 == y2) { y1 -= 1.0; y2 += 1.0; }
	if (dt <= 0.0)
		dt = my x -> dx < my y -> dx ? my x -> dx : my y -> dx;
	numberOfPoints = (long) ceil ((t2 - t1) / dt) + 1;
	if (! (x = NUMfvector (1, numberOfPoints)) || ! (y = NUMfvector (1, numberOfPoints))) {
		NUMfvector_free (x, 1);
		return 0;
	}
	for (i = 1; i <= numberOfPoints; i ++) {
		double t = i == numberOfPoints ? t2 : t1 + (i - 1) * dt;
		double index = Sampled_xToIndex (my x, t);
		x [i] = NUM_interpolate_sinc (my x -> z [1], my x -> nx, index, 50);
		index = Sampled_xToIndex (my y, t);
		y [i] = NUM_interpolate_sinc (my y -> z [1], my y -> nx, index, 50);
	}
	Graphics_setWindow (g, x1, x2, y1, y2);
	Graphics_setInner (g);
	Graphics_polyline (g, numberOfPoints, & x [1], & y [1]);
	Graphics_unsetInner (g);
	NUMfvector_free (x, 1);
	NUMfvector_free (y, 1);
	if (garnish) {
		Graphics_drawInnerBox (g);
		Graphics_marksBottom (g, 2, 1, 1, 0);
		Graphics_marksLeft (g, 2, 1, 1, 0);
	}
	return 1;
}

void ParamCurve_swapXY (I) {
	iam (ParamCurve);
	Sound help = my x;
	my x = my y;
	my y = help;
}

/* End of file ParamCurve.c */
