#include "graph.h"

int maxx, maxy;
int xoffset=0, yoffset=0;
int maxthick;

static void testbox(void)
{
    /* diagonals */
    Move(rast, 0   , 0   );
    Draw(rast, maxx, maxy);
    Move(rast, 0   , maxy);
    Draw(rast, maxx, 0   );

    /* sides */
    Move(rast, 0, 0   );
    Draw(rast, 0, maxy);
    Move(rast, maxx, 0   );
    Draw(rast, maxx, maxy);

    /* top, bottom */
    Move(rast, 0   , 0);
    Draw(rast, maxx, 0);
    Move(rast, 0   , maxy);
    Draw(rast, maxx, maxy);
}

int biggestx  = -10000;
int biggesty  = -10000;
int smallestx = +10000;
int smallesty = +10000;

void range(int x, int y)
{
    int problem = 0; 

    if (x < 0) {
        printf("Internal error: X too small: %d\n", x);
        problem = 1;
    }
    if (y < 0) {
        printf("Internal error: Y too small: %d\n", y);
        problem = 1;
    }
    if (x >= WIDTH) {
        printf("Internal error: X too big:   %d\n", x);
        problem = 1;
    }
    if (y >= HEIGHT) {
        printf("Internal error: Y too big:   %d\n", y);
        problem = 1;
    }
    if (problem) {
        exit(1);
    }
}

void showmax(void)
{
    printf("X range used: %4d  to %4d\n", smallestx, biggestx);
    printf("Y range used: %4d  to %4d\n", smallesty, biggesty);
}


#define RECORD(x,y) { \
    if (x>biggestx) biggestx=x;   \
    if (y>biggesty) biggesty=y;   \
    if (x<smallestx) smallestx=x; \
    if (y<smallesty) smallesty=y; \
    range(x,y);                   \
    }

#if 1
#define MOVE(r,x,y)   {RECORD(x,y); Move(r,x,y);}
#define DRAW(r,x,y)   {RECORD(x,y); Draw(r,x,y);}
#else
#define MOVE(r,x,y)   Move(r,x,y)
#define DRAW(r,x,y)   Draw(r,x,y)
#endif

static void drawHline(int x1, int x2, int y, int thickness)
{
    int halfwidth = thickness>>1;
    int i;

    /* horizontal */
    y = y - halfwidth;
    for (i=y; i<=y+thickness-1; ++i) {
        MOVE(rast, xoffset+x1,yoffset+i);
        DRAW(rast, xoffset+x2,yoffset+i);
    }
}

static void drawVline(int x, int y1, int y2, int thickness)
{
    int halfwidth = thickness>>1;
    int i;

    /* vertical */
    x = x - halfwidth;
    for (i=x; i<=x+thickness-1; ++i) {
        MOVE(rast, xoffset+i,yoffset+y1);
        DRAW(rast, xoffset+i,yoffset+y2);
    }
}

static void DrawFixedHoriz(float spacing, int thickness)
{
    float i;
    int halfmax = maxthick>>1;

    for (i=halfmax; i<=maxy-halfmax+1; i += spacing) {
        drawHline(0, maxx,(int)i, thickness);
    }
}

static void DrawLogHoriz(float spacing, int thickness, int numcycles)
{
    float i;
    float cycle;
    int halfmax = maxthick>>1;

    for (cycle=halfmax; cycle<=maxy-halfmax-0.5*spacing; cycle += spacing) {
        for (i=2; i < numcycles; i += 1) {
            drawHline(0, maxx, (int)(cycle+(1.-log(i)/log(numcycles))*spacing), thickness);
                                  /* ^^^^^^^^^^^^^ top to bottom */
        }
    }
}

static void DrawFixedVert(float spacing, int thickness)
{
    float i;
    int halfmax = maxthick>>1;

    /* vertical lines */
    for (i=halfmax; i<=maxx-halfmax+1; i += spacing) {
        drawVline((int)i,0, maxy, thickness);
    }
}

static void DrawLogVert(float spacing, int thickness, int numcycles)
{
    float i;
    float cycle;
    int halfmax = maxthick>>1;

    /* vertical lines */
    for (cycle=halfmax; cycle<=maxx-halfmax-0.5*spacing; cycle += spacing) {
        for (i=2; i < numcycles; i += 1) {
            drawVline((int)(cycle+log(i)/log(numcycles)*spacing),0, maxy, thickness);
        }
    }
}


void DrawGraph(void)
{
    float x_Major_Pixel_Spacing, y_Major_Pixel_Spacing;
    float x_Minor_Pixel_Spacing, y_Minor_Pixel_Spacing;

    maxx = WIDTH -FUDGE -1;   /* range: 0..maxx-1 */
    maxy = HEIGHT-FUDGE -1;

    /* testbox(); */

    x_Major_Pixel_Spacing = x_dpi_V * x_size_v;
    x_Minor_Pixel_Spacing = x_Major_Pixel_Spacing / minor_x_v;

    y_Major_Pixel_Spacing = y_dpi_V * y_size_v;
    y_Minor_Pixel_Spacing = y_Major_Pixel_Spacing / minor_y_v;

    xoffset = 0;  /* obsolete */
    yoffset = 0;

    /* all get major axis */
    DrawFixedVert (x_Major_Pixel_Spacing, Major_Thickness_V);
    DrawFixedHoriz(y_Major_Pixel_Spacing, Major_Thickness_V);

    /* minor axis depends on mode */
    /* switch statements don't work with pointers */
         if (MinorMode == &None)   {
            /* nothing to do */
            }
    else if (MinorMode == &Linear) { 
            DrawFixedVert (x_Minor_Pixel_Spacing, Minor_Thickness_V);
            DrawFixedHoriz(y_Minor_Pixel_Spacing, Minor_Thickness_V);
            }
    else if (MinorMode == &LogLog) {
            DrawLogVert   (x_Major_Pixel_Spacing, Minor_Thickness_V, minor_x_v);
            DrawLogHoriz  (y_Major_Pixel_Spacing, Minor_Thickness_V, minor_y_v);
            }
    else if (MinorMode == &LogY)   {
            DrawFixedVert (x_Minor_Pixel_Spacing, Minor_Thickness_V);
            DrawLogHoriz  (y_Major_Pixel_Spacing, Minor_Thickness_V, minor_y_v);
            }
    else if (MinorMode == &LogX)   {
            DrawFixedHoriz(x_Minor_Pixel_Spacing, Minor_Thickness_V);
            DrawLogVert   (y_Major_Pixel_Spacing, Minor_Thickness_V, minor_x_v);
            }
    else {  printf("Error in DrawGraph\n");
            exit(1);
         }
 /* showmax(); */
}
