//Cpde for PCS 6th grade coding - Hicks + Wood
//Add more regions to make a pattern


void draw() {

  background(255);
  drawCoordinateSystem();

  //coomand to draw the region above a line - note line defined by "change in X" (run), "change in Y" (rise), "Y intercept"
  //drawGreaterThanSlopedLine(2, 1, 40, color(0, 255, 0), 30);
  
  //TODO - add more lines - you can also do:
  //drawLessThanSlopedLine(2, 1, -40, color(0, 0, 255), 30);

  fill(128);
  ellipse(centeredX(0), centeredY(40), 10, 10);
  //TODO: Add more circles for each y - intercept
  
  
  /* Also try this: 
  for (int i=0; i < 10; i++) {
    drawGreaterThanSlopedLine(2, 1, 40*i, color(0, 0, 255), 30);
    drawGreaterThanSlopedLine(2, -1, 40*i, color(0, 0, 255), 30);
  }
  */
}

void setup() {
  size(400, 400);
  prevTime = second();
  drawOption = 0;
}

public final int UNION = 0;
public final int INTERSECTION = 1;
public final int COMPLEMENT = 2;

int maxDegree = 0;
int prevTime;
int drawOption;




private class Inequality {
  public boolean isVertical;
  public float xIntercept;

  public float deltaX;
  public float deltaY;
  public int yIntercept;
  public color col;
  public boolean shadeGreaterThan;

  public Inequality(float deltaX, float deltaY, int yIntercept, int alpha, color col, boolean shadeGreaterThan) {
    this.isVertical = false;
    this.xIntercept = 0;
    this.deltaX = deltaX;
    this.deltaY = deltaY;
    this.yIntercept = yIntercept;
    this.col = color(red(col), green(col), blue(col), alpha);
    this.shadeGreaterThan = shadeGreaterThan;
  }

  public Inequality(int xIntercept, int alpha, color col, boolean shadeGreaterThan) {
    this.isVertical = true;
    this.xIntercept = xIntercept;
    this.deltaX = 0;
    this.deltaY = 0;
    this.yIntercept = 0;
    this.col = color(red(col), green(col), blue(col), alpha);
    this.shadeGreaterThan = shadeGreaterThan;
  }


  boolean isValidPoint(int x, int y) {
    if (!this.isVertical && this.deltaX == 0) return false;
    else if (this.isVertical) {
      //vertical line
      if (this.shadeGreaterThan) {
        if (x >= this.xIntercept) return true;
        return false;
      } else {
        if (x <= this.xIntercept) return true;
        return false;
      }
    } else {
      float slope = this.deltaY / this.deltaX;
      if (this.shadeGreaterThan) {
        if (y >= x * slope + this.yIntercept) return true;
        return false;
      } else {
        if (y <= x * slope + this.yIntercept) return true;
        return false;
      }
    }
  }
}

void drawInequality(Inequality i) {
  float slope1X, slope1Y, slope2X, slope2Y;
  stroke(i.col);
  strokeWeight(1);

  int incAmt = 1;
  if (!i.shadeGreaterThan) {
    incAmt *= -1;
  }

  if (!i.isVertical && abs(i.deltaX) < 0.0001) return;
  else if (i.isVertical) {
    int x = (int)min(i.xIntercept, width);

    while ((i.shadeGreaterThan && x < width) ||
      (!i.shadeGreaterThan && x > -width)) {
      line(centeredX(x), 0, centeredX(x), height);
      x += incAmt;
      if (incAmt == 2 || incAmt == -2) {
        int lineWeight = 10;
        incAmt = (lineWeight + 1) * incAmt;
        strokeWeight(lineWeight);
      }
    }
  } else {
    float slope = (float)i.deltaY / (float)i.deltaX;
    int curYInt = (int)i.yIntercept;

    while ((i.shadeGreaterThan && curYInt < height) ||
      (!i.shadeGreaterThan && curYInt > -height)) {
      slope1X = centeredX(height/2);
      slope1Y = centeredY(slope * height/2 + curYInt);
      slope2X = centeredX(-height/2);
      slope2Y = centeredY(slope * -height/2 + curYInt);
      line(slope1X, slope1Y, slope2X, slope2Y);
      curYInt += incAmt;

      if (incAmt == 2 || incAmt == -2) {
        int lineWeight = 400;
        curYInt += lineWeight * incAmt;
        incAmt = (lineWeight + 1) * incAmt;
        strokeWeight(lineWeight);
      }
    }
  }
}

void drawIntersection(Inequality unionIneq[], int size, color col) {
  int operation = INTERSECTION;
  drawSet(operation, unionIneq, size, col);
}

void drawComplement(Inequality unionIneq[], int size, color col) {
  int operation = COMPLEMENT;
  drawSet(operation, unionIneq, size, col);
}

void drawUnion(Inequality unionIneq[], int size, color col) {
  int operation = UNION;
  drawSet(operation, unionIneq, size, col);
}

void drawSet(int operation, Inequality unionIneq[], int size, color col) {
  stroke(col);
  for (int y = -height/2; y < height/2; y++) {
    for (int x = -width/2; x < width/2; x++) {
      int numValidPoint = 0;
      boolean isFirstColor = true;

      for (int i = 0; i < size; i++) {
        if (unionIneq[i].isValidPoint(x, y)) {
          numValidPoint++;
        }
      }

      if ((operation == UNION && numValidPoint > 0) ||
        (operation == COMPLEMENT && numValidPoint == 0) ||
        (operation == INTERSECTION && numValidPoint == size)) {
        point(centeredX(x), centeredY(y));
      }
    }
  }
}

void drawXLessThan(int value, color col, int alpha) {
  drawInequality(xLessThan(value, col, alpha));
}

void drawYLessThan(int value, color col, int alpha) {
  drawInequality(yLessThan(value, col, alpha));
}

void drawXGreaterThan(int value, color col, int alpha) {
  drawInequality(xGreaterThan(value, col, alpha));
}

void drawYGreaterThan(int value, color col, int alpha) {
  drawInequality(yGreaterThan(value, col, alpha));
}

void drawGreaterThanSlopedLine(float changeInX, float changeInY, 
  int yIntercept, color col, int alpha) {
  drawInequality(greaterThanSlopedLine(changeInX, changeInY, yIntercept, col, alpha));
}

void drawLessThanSlopedLine(float changeInX, float changeInY, 
  int yIntercept, color col, int alpha) {
  drawInequality(lessThanSlopedLine(changeInX, changeInY, yIntercept, col, alpha));
}

Inequality xLessThan(int value, color col, int alpha) {
  return new Inequality(value, alpha, col, false);
}

Inequality xGreaterThan(int value, color col, int alpha) {
  return new Inequality(value, alpha, col, true);
}

Inequality yLessThan(int value, color col, int alpha) {
  return new Inequality(1, 0, value, alpha, col, false);
}

Inequality yGreaterThan(int value, color col, int alpha) {
  return new Inequality(1, 0, value, alpha, col, true);
}

Inequality greaterThanSlopedLine(float changeInX, float changeInY, 
  int yIntercept, color col, float alpha) {
  return new Inequality(changeInX, changeInY, yIntercept, (int)alpha, col, true);
}

Inequality lessThanSlopedLine(float changeInX, float changeInY, 
  int yIntercept, color col, float alpha) {
  return new Inequality(changeInX, changeInY, yIntercept, (int)alpha, col, false);
}

float centeredX(float x) {
  return x + width/2.0;
}

float centeredY(float y) {
  // inverted y
  return -1 * y + height/2.0;
}

void drawCoordinateSystem() {
  stroke(0);
  strokeWeight(1);
  int lineLength;

  int tickMark = 0;
  for (int x = (int) 0; x < (int)width / 2; x += 10, tickMark++) {
    lineLength = 2;
    if (tickMark == 5) {
      lineLength = 5;
      tickMark = 0;
    }
    if (width/2 - x > 0) {
      line(width/2 - x, height/2 - lineLength, 
        width/2 - x, height/2 + lineLength);
    }
    if (width/2 + x < width) {
      line(width/2 + x, height/2 - lineLength, 
        width/2 + x, height/2 + lineLength);
    }
  }

  tickMark = 0;
  for (int y = (int) 0; y < (int)height / 2; y += 10, tickMark++) {
    lineLength = 2;
    if (tickMark == 5) {
      lineLength = 5;
      tickMark = 0;
    }
    if (height/2 - y > 0) {
      line(width/2 - lineLength, height/2 - y, 
        width/2 + lineLength, height/2 - y);
    }
    if (height/2 + y < height) {
      line(width/2 - lineLength, height/2 + y, 
        width/2 + lineLength, height/2 + y);
    }
  }

  line(0, height/2.0, width, height/2.0);
  line(width/2.0, 0, width/2.0, height);
  noStroke();
}