// blimey o'riley
//import processing.opengl.*;

public static final int WIDTH = 480;
public static final int HEIGHT = 480;
public static final int RADIUS = (HEIGHT / 2);
public static final int RADIUS_DELTA = (HEIGHT / 16);

public static final int SECTIONS = 720;
public static final int SEGMENTS = 72;
public static final int CIRCLES = 8;

Circle[] circle = new Circle[CIRCLES];

float[] sint = new float[SECTIONS];
float[] cost = new float[SECTIONS];

void setup() {
  size(HEIGHT, WIDTH);
  int radius = RADIUS;
  for (int i = 0 ; i < CIRCLES ; i++) {
    circle[i] = new Circle(i, radius);
    radius -= RADIUS_DELTA;
  }
  frameRate(25);
}

void draw() {
  background(255);
  translate(WIDTH >> 1, HEIGHT >> 1);
  for (int i = 0 ; i < CIRCLES - 1 ; i++) {
    for (int j = 0 ; j < SEGMENTS ; j++) {
      int outer = i;
      int inner = i + 1;
      int next = (j + 1) % SEGMENTS;
      float x1 = circle[outer].getX(j);
      float y1 = circle[outer].getY(j);
      float x2 = circle[inner].getX(j);
      float y2 = circle[inner].getY(j);
      float x3 = circle[inner].getX(next);
      float y3 = circle[inner].getY(next);
      float x4 = circle[outer].getX(next);
      float y4 = circle[outer].getY(next);
      // alternate black and white
      noStroke();
      if ((j & 1) == 0) {
        fill(0);
      } else {
        fill(255);
      }
      quad(x1, y1, x2, y2, x3, y3, x4, y4);
    }
  }
  // move circles (not outermost)
  for (int i = 1 ; i < CIRCLES ; i++) {
    circle[i].move();
  }

  if (keyPressed) {
    if (key == 'g') {
      println("Grabbing");
      saveFrame("grab_####.png");
    }
  }
}

class Circle {
  private static final float RADIUS = 12;  // radius of centre movement. less than half RADIUS_DELTA
  float radius;
  float angle;
  float delta;
  float centreX;
  float centreY;
  public float[] x = new float[SEGMENTS];
  public float[] y = new float[SEGMENTS];
  
  Circle(int index, float radius) {
    this.radius = radius;
    float twist = 0.0;
    if ((index & 1) == 0) {
      twist = 15.0;
    }
    for (int i = 0 ; i < SEGMENTS ; i++) {
      float a = radians(i * (360 / SEGMENTS) + twist);
      x[i] = radius * sin(a);
      y[i] = radius * cos(a);
    }
    // setup movement (degrees)
    angle = random(360);
    delta = random(-4, 4);
    // don't move outer circle
    if (index != 0) {
      move();
    }
//  println("Circle[" + index + "]: [" + centreX + "," + centreY + "] R:[" + radius + "] t[" + twist + "]");
  }
  
  float getX(int i) {
    return x[i] + centreX;
  }
  
  float getY(int i) {
    return y[i] + centreY;
  }
  
  float getCentreX() {
    return centreX;
  }
  
  float getCentreY() {
    return centreY;
  }
  
  void move() {
    angle += delta;
    centreX = RADIUS * cos(radians(angle));
    centreY = RADIUS * sin(radians(angle));
  }
}
