import processing.serial.*;

Serial myPort;
float[] sensorVals = {0, 0, 0};
int threshold = 500;         // adjust to your sensors

ArrayList<Drop> drops;
float zoneWidth;

void setup() {
  size(600, 400);
  smooth();
  background(0);

  zoneWidth = width / 3.0;

  drops = new ArrayList<Drop>();

  // Start with some base rain
  for (int i = 0; i < 150; i++) {
    drops.add(new Drop(-1));     // -1 = anywhere
  }

  // ---- SERIAL SETUP ----
  printArray(Serial.list());     // check console and pick correct port index
  myPort = new Serial(this, Serial.list()[0], 9600);
  myPort.bufferUntil('\n');
}

void draw() {
  // faint fade to leave trails
  noStroke();
  fill(0, 40);
  rect(0, 0, width, height);

  // update & draw all drops
  for (int i = drops.size()-1; i >= 0; i--) {
    Drop d = drops.get(i);
    d.update();
    d.show();

    if (d.offscreen()) {
      drops.remove(i);            // recycle offscreen drops
    }
  }

  // --- spawn base light rain everywhere ---
  for (int i = 0; i < 3; i++) {
    drops.add(new Drop(-1));      // random zone
  }

  // --- increase rain in zones that are touched ---
  for (int z = 0; z < 3; z++) {
    if (sensorVals[z] > threshold) {
      // more touch ⇒ more rain density
      int extra = 25;              // tweak to control intensity
      for (int i = 0; i < extra; i++) {
        drops.add(new Drop(z));   // spawn in that zone only
      }
    }
  }
}

// receive "v1,v2,v3" from Arduino
void serialEvent(Serial p) {
  String in = p.readStringUntil('\n');
  if (in == null) return;

  in = trim(in);
  String[] parts = split(in, ',');
  if (parts.length == 3) {
    for (int i = 0; i < 3; i++) {
      sensorVals[i] = float(parts[i]);
    }
  }
}

// ----------------- DROP CLASS -----------------

class Drop {
  float x, y;
  float z;        // depth
  float speed;
  float len;

  Drop(int zoneIndex) {          // zoneIndex: 0,1,2 or -1 for anywhere
    reset(zoneIndex);
  }

  void reset(int zoneIndex) {
    if (zoneIndex < 0) {
      x = random(width);
    } else {
      float x0 = zoneIndex * zoneWidth;
      x = random(x0, x0 + zoneWidth);
    }

    // start slightly above the top
    y = random(-height, 0);

    // depth between near and far
    z = random(0.5, 3.0);

    // map depth to speed and length (closer = faster + longer)
    speed = map(z, 0.5, 3.0, 1.0, 8.0);
    len   = map(z, 0.5, 3.0, 6.0, 20.0);
  }

  void update() {
    y += speed;
  }

  void show() {
    // nearer drops are a bit brighter and thicker
    float alpha = map(z, 0.5, 3.0, 60, 180);
    float w = map(z, 0.5, 3.0, 1, 2.5);

    stroke(200, 220, 255, alpha);
    strokeWeight(w);
    // you can use ellipses if you prefer, but short lines look rainy:
    line(x, y, x, y + len);
    // OR: ellipse(x, y, w+1, len);  // if you want droplet ellipses instead
  }

  boolean offscreen() {
    return y > height + 20;
  }
}
