// Emacs: -*- C++ -*-

#include <FloatPoint.h>
#include <ACG.h>

#define TBL_SIZE 100

int main(int argc, char**argv)
{
    void	print_relational_table(char*, IntPoint[], int);
    void	print_relational_table(char*, FloatPoint[], int);
    void	make_points(FloatPoint[], int, ACG&);              // random integer valued
    void	sort_points(FloatPoint[], int);

    ACG		generator;    
    FloatPoint  floats[TBL_SIZE];
    IntPoint    ints[TBL_SIZE];

    int		number_int_points = 0;
    int		number_real_points = 15;

    for (int i = -1; i <= 1; i++)
	for (int j = -1; j <= 1; j++)
	    ints[number_int_points++] = IntPoint(i, j);

    print_relational_table("IntPoints relational tests", ints, number_int_points);

    cout << "\f";
    make_points(floats, number_real_points, generator);
    sort_points(floats, number_real_points);
    print_relational_table("FloatPoints relational tests", floats, number_real_points);
}

void
make_points(FloatPoint point_array[], int number_points, ACG& generator)
{
    FloatPoint	make_random_point(int, int, int, ACG&); // dimension, bottom, top, type

    for (int i = 0; i < ( 2 * number_points / 3); i++) 
	point_array[i] = make_random_point(2, -1, +1, generator);
    for (i = ( 2 * number_points / 3); i < number_points;  i++) 
	point_array[i] = make_random_point(1, -1, +1, generator);
}	


void
print_relational_table(char* label, FloatPoint point_array[], int number_points)
{
//  Run all relational ops on an array of points, printing a table

    char first_page = 1;
    
    cout << label << "\n" << "<    <=   ==   >=   >    !=\tArguments\n";
    for (int i = 0; i < number_points; i++) {
        for (int j = 0; j < number_points; j++) {

	    if (((i * number_points + j) % 60) == 0) {
		if (first_page)
		    first_page = 0;
		else
		    cout << "\f" << label << "(continued)\n" << "<    <=   ==   >=   >    !=\tArguments\n";
	    }
	    cout << (int) (point_array[i] <  point_array[j]) << "    ";
	    cout << (int) (point_array[i] <= point_array[j]) << "    ";
	    cout << (int) (point_array[i] == point_array[j]) << "    ";
	    cout << (int) (point_array[i] >= point_array[j]) << "    ";
	    cout << (int) (point_array[i] >  point_array[j]) << "    ";
	    cout << (int) (point_array[i] != point_array[j]) << "\t";
	    cout << point_array[i] << "\t" << point_array[j] << "\n";
	}
    }
}

void
print_relational_table(char* label, IntPoint point_array[], int number_points)
{
//  Run all relational ops on an array of points, printing a table

    char first_page = 1;
    
    cout << label << "\n" << "<    <=   ==   >=   >    !=\tArguments\n";
    for (int i = 0; i < number_points; i++) {
        for (int j = 0; j < number_points; j++) {

	    if (((i * number_points + j) % 60) == 0) {
		if (first_page)
		    first_page = 0;
		else
		    cout << "\f" << label << "(continued)\n" << "<    <=   ==   >=   >    !=\tArguments\n";
	    }
	    cout << (int) (point_array[i] <  point_array[j]) << "    ";
	    cout << (int) (point_array[i] <= point_array[j]) << "    ";
	    cout << (int) (point_array[i] == point_array[j]) << "    ";
	    cout << (int) (point_array[i] >= point_array[j]) << "    ";
	    cout << (int) (point_array[i] >  point_array[j]) << "    ";
	    cout << (int) (point_array[i] != point_array[j]) << "\t";
	    cout << point_array[i] << "\t" << point_array[j] << "\n";
	}
    }
}


FloatPoint
make_random_point(int dimensions, int bottom, int top, ACG& gen)
{
    int   range;

    if (top < bottom) {
	int temp = top;
	top = bottom;
	bottom = temp;
    }
    range = top - bottom;

    switch (dimensions) {
    case 0:
	return FloatPoint();
    case 1:
	return FloatPoint(bottom +  gen.asFloat() * range);
    case 2:
	return FloatPoint(bottom +  gen.asFloat() * range,
			  bottom +  gen.asFloat() * range);
    case 3:
	return FloatPoint(bottom +  gen.asFloat() * range,
			  bottom +  gen.asFloat() * range,
			  bottom +  gen.asFloat() * range);
    case 4:
	return FloatPoint(bottom +  gen.asFloat() * range,
			  bottom +  gen.asFloat() * range,
			  bottom +  gen.asFloat() * range,
			  bottom +  gen.asFloat() * range);
    case 5:
	return FloatPoint(bottom +  gen.asFloat() * range,
			  bottom +  gen.asFloat() * range,
			  bottom +  gen.asFloat() * range,
			  bottom +  gen.asFloat() * range,
			  bottom +  gen.asFloat() * range);
    default:
	return FloatPoint(0.0, 0.0, 0.0, 0.0, 0.0);    // should not happen
    }
}

void
sort_points(FloatPoint points[], int size)
{
    // Very stupid bubble sorter. Please fix (where *is* my copy of Sedgwick?).

    char my_less_than(const FloatPoint&, const FloatPoint&);

    FloatPoint temp;
    for (int i = 0; i < size; i++) {
	for (int j = i; j < size; j++) {
	    if (my_less_than(points[i], points[j])) {
		temp = points[i];
		points[i] = points[j];
		points[j] = temp;
	    }
	}
    }
}


char
my_less_than (const FloatPoint& p0, const FloatPoint& p1)
{
    char bool = Pointcmp(p0, p1);
    if (bool == -1)
	return (char) 1;
    else if (bool == 0) 				// may be equal iff zero extended
	return (p0.dimensions() < p1.dimensions());	// so check
    else
	return (char) 0;
}
