#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <math.h>
#include "window.h"

#define X 1024
#define Y 768

double zoom = 0.5;

/*

assume y = lambda x

x^2 + y^2 = 1 + d x^2 y^2
x^2 + lambda^2 x^2 = 1 + d lambda^2 x^2 x^2
(1 + lambda^2) x^2 = 1 + d lambda^2 x^4
0 = d lambda^2 x^4 - (1 + lambda^2) x^2 + 1

x^2 = ((1 + lambda^2) +- sqrt((1 + lambda^2)^2 - 4 d lambda^2)) / 2 d lambda^2
x^2 = ((1 + lambdasq) +- sqrt((1 + lambdasq)^2 - 4 d lambdasq)) / 2 d lambdasq
x^2 = ((1 + lambdasq) +- sqrt(disc)) / 2 d lambdasq
*/

double d = -30;

char line[1000];

void redraw(void)
{
  double lambda;
  double lambdasq;
  double disc;
  double x2;
  double x;
  double y;
  double oldx;
  double oldy;
  int sign;
  int octant;

  sprintf(line,"d = %.1lf; to adjust, press J j k K",d);
  window_drawstring(20,20,line,0);

  sprintf(line,"zoom = %lf; to adjust, press a z",zoom);
  window_drawstring(20,40,line,0);

  for (octant = 0;octant < 8;++octant) {
    for (sign = -1;sign <= 1;sign += 2) {
      oldx = 0;
      oldy = 0;
      for (lambda = 0.01;lambda < 1;lambda += 0.001) {
	if (d * d < 0.001) {
          lambdasq = lambda * lambda;
	  x2 = 1 / (1 + lambdasq);
	} else {
          lambdasq = lambda * lambda;
          disc = (1 + lambdasq) * (1 + lambdasq) - 4 * d * lambdasq;
          if (disc < 0) goto bad;
          x2 = (1 + lambdasq + sign * sqrt(disc)) / (2 * d * lambdasq);
          if (x2 < 0) goto bad;
	}
        x = sqrt(x2);
        y = lambda * x;
        if ((oldx != 0) || (oldy != 0)) {
	  switch(octant) {
	    case 0: window_drawline(X/2 + oldx * 100 * zoom,Y/2 + oldy * 100 * zoom,X/2 + x * 100 * zoom,Y/2 + y * 100 * zoom,0); break;
	    case 1: window_drawline(X/2 - oldx * 100 * zoom,Y/2 + oldy * 100 * zoom,X/2 - x * 100 * zoom,Y/2 + y * 100 * zoom,0); break;
	    case 2: window_drawline(X/2 + oldx * 100 * zoom,Y/2 - oldy * 100 * zoom,X/2 + x * 100 * zoom,Y/2 - y * 100 * zoom,0); break;
	    case 3: window_drawline(X/2 - oldx * 100 * zoom,Y/2 - oldy * 100 * zoom,X/2 - x * 100 * zoom,Y/2 - y * 100 * zoom,0); break;
	    case 4: window_drawline(X/2 + oldy * 100 * zoom,Y/2 + oldx * 100 * zoom,X/2 + y * 100 * zoom,Y/2 + x * 100 * zoom,0); break;
	    case 5: window_drawline(X/2 - oldy * 100 * zoom,Y/2 + oldx * 100 * zoom,X/2 - y * 100 * zoom,Y/2 + x * 100 * zoom,0); break;
	    case 6: window_drawline(X/2 + oldy * 100 * zoom,Y/2 - oldx * 100 * zoom,X/2 + y * 100 * zoom,Y/2 - x * 100 * zoom,0); break;
	    case 7: window_drawline(X/2 - oldy * 100 * zoom,Y/2 - oldx * 100 * zoom,X/2 - y * 100 * zoom,Y/2 - x * 100 * zoom,0); break;
	  }
        }
        oldx = x;
        oldy = y;
        continue;
        bad:
        oldx = 0;
        oldy = 0;
      }
    }
  }
}

int keypress(long long k)
{
  if (k == 'q') return -1;
  if (k == 'j') { d = d - 0.1; return 1; }
  if (k == 'k') { d = d + 0.1; return 1; }
  if (k == 'j' + 1000000) { d = d - 1; return 1; }
  if (k == 'k' + 1000000) { d = d + 1; return 1; }
  if (k == 'a') { zoom *= 2; return 1; }
  if (k == 'z') { zoom *= 0.5; return 1; }
  return 0;
}

int background(void)
{
}

int main(int argc,char **argv)
{
  window_exec(argc,argv,redraw,keypress,background);
}
