#include "library.h"

struct complex
{ double real, imag; };

void print(complex x)
{ cout << x.real << " + " << x.imag << "i "; }

complex mk_complex(double r, double i)
{ complex result;
  result.real = r;
  result.imag = i;
  return result; }

complex add(complex x, complex y)
{ complex result;
  result.real = x.real + y.real;
  result.imag = x.imag + y.imag;
  return result; }

complex sub(complex x, complex y)
{ complex result;
  result.real = x.real - y.real;
  result.imag = x.imag - y.imag;
  return result; }

complex mul(complex x, complex y)
{ complex result;
  result.real = x.real*y.real - x.imag*y.imag;
  result.imag = x.real*y.imag + x.imag*y.real;
  return result; }

complex div(complex x, complex y)
{ const double bottom = y.real*y.real + y.imag*y.imag;
  if (bottom == 0.0)
  { cout << "division vby zero!\n";
    exit(1); }
  complex result;
  result.real = (x.real*y.real + x.imag*y.imag) / bottom;
  result.imag = (y.real*x.imag - y.imag*x.real) / bottom;
  return result; }

complex read_complex()
{ complex result;
  cout << "enter real part: ";
  cin >> result.real;
  cout << "enter imaginary part: ";
  cin >> result.imag;
  return result; }

double magnitude(complex a)
{ return sqrt(a.real*a.real + a.imag*a.imag); }

const int screenw = 600, screenh = 600;
const double maxreal = 2.0, maximag = 2.0;

double imag_to_y(double im)
{ return (im + maximag) / (2 * maximag) * screenh; }

double real_to_x(double re)
{ return (re + maxreal) / (2 * maxreal) * screenw; }

double x_to_real(double x)
{ return x / screenw * 2 * maxreal - maxreal; }

double y_to_imag(double y)
{ return y / screenh * 2 * maximag - maximag; }

complex click_to_complex()
{ wait_for_mouse_click();
  double x = get_click_x(), y = get_click_y();
  return mk_complex(x_to_real(x), y_to_imag(y)); }

void move_to(complex c)
{ double x = real_to_x(c.real);
  double y = imag_to_y(c.imag);
  move_to(x, y); }

void draw_to(complex c)
{ double x = real_to_x(c.real);
  double y = imag_to_y(c.imag);
  draw_to(x, y); }

void draw_complex(complex a)
{ double x = real_to_x(a.real);
  double y = imag_to_y(a.imag);
  move_to(x, y);
  move_relative(-10, -10);
  draw_relative(20, 20);
  move_relative(0, -20);
  draw_relative(-20, 20); }

void draw_axes()
{ move_to(screenw/2, 0);
  draw_to(screenw/2, screenh);
  move_to(0, screenh/2);
  draw_to(screenw, screenh/2); }

void main()
{ make_window(screenw, screenh);
  draw_axes();
  complex z, c;
  for (double re = -maxreal; re < maxreal; re += 0.01)
    for (double im = -maximag; im < maximag; im += 0.01)
  { z = mk_complex(0, 0);
    c = mk_complex(re, im);
    move_to(c);
    bool unstable = false;
    for (int i = 0; i < 1000; i += 1)
    { z = add(mul(z, z), c); 
      if (magnitude(z) > 10)
      { unstable = true; 
        break; } }
    set_pen_width(5);
    if (unstable)
      set_pen_color(color::red);
    else
      set_pen_color(color::blue);
    draw_point(); } } 

/*
void main()
{ make_window(screenw, screenh);
  draw_axes();
  complex z, c;
  while (true)
  { z = mk_complex(0, 0);
    c = click_to_complex();
    move_to(c);
    for (int i = 0; i < 100; i += 1)
    { z = add(mul(z, z), c);
      draw_to(z); } } }
*/
/*
void main()
{ make_window(screenw, screenh);
  draw_axes();
  complex a, b, c;
  a = click_to_complex();
  draw_complex(a);
  b = click_to_complex();
  draw_complex(b);
  c = add(a, b);
  draw_complex(c); write_string("+");
  c = sub(a, b);
  draw_complex(c); write_string("-");
  c = mul(a, b);
  draw_complex(c); write_string("*");
  c = div(a, b);
  draw_complex(c); write_string("/");
}
*/