/**
 * BreakbeatEvent class
 * 
 * Specialized visualization for breakbeats, jungle, and deconstructed rhythms
 * Designed specifically for d8 track in ParVagues performances
 */
class BreakbeatEvent extends SoundEvent {
  // Slice visualization properties
  int numSlices;
  ArrayList<Slice> slices;
  float rotation;
  float originalSize;
  boolean isReversePattern;
  float beatPhase;
  
  BreakbeatEvent(int orbit, String sound, float gain, float pan, float delta) {
    super(orbit, sound, gain, pan, delta);
    
    // Extended lifespan for breakbeats
    lifespan = 800 + (gain * 500);
    originalSize = size;
    
    // Determine number of slices based on the sound name and gain
    if (sound.contains("jungle")) {
      numSlices = 16;
    } else if (sound.contains("break")) {
      numSlices = 8;
    } else {
      numSlices = int(random(4, 12));
    }
    
    // Check if this might be a reversed sample
    isReversePattern = sound.contains("rev") || random(100) < 20;
    
    // Random rotation for variety
    rotation = random(TWO_PI);
    
    // Initialize slices
    createSlices();
    
    // Beat phase for animation
    beatPhase = random(TWO_PI);
  }
  
  void createSlices() {
    slices = new ArrayList<Slice>();
    
    // Create slices in a circle
    for (int i = 0; i < numSlices; i++) {
      float angle = map(i, 0, numSlices, 0, TWO_PI);
      float distance = originalSize * 0.7;
      
      // Randomized slice properties
      float sliceWidth = originalSize * 0.3 * random(0.5, 1.5);
      float sliceHeight = originalSize * 0.2 * random(0.5, 1.5);
      float fadeOffset = random(0, lifespan * 0.5);
      
      // Calculate position
      float x = cos(angle) * distance;
      float y = sin(angle) * distance;
      
      // Add the slice
      slices.add(new Slice(x, y, sliceWidth, sliceHeight, angle, fadeOffset));
    }
  }
  
  @Override
  void update() {
    super.update();
    
    // Calculate age as a percentage
    float age = millis() - birthTime;
    float progress = constrain(age / lifespan, 0, 1);
    
    // Update each slice
    for (Slice slice : slices) {
      slice.update(progress, age);
    }
  }
  
  @Override
  void display() {
    if (alpha <= 0) return;
    
    float age = millis() - birthTime;
    float progress = constrain(age / lifespan, 0, 1);
    
    // Display core only at the beginning
    if (progress < 0.2) {
      // Draw core with fading alpha
      float coreAlpha = map(progress, 0, 0.2, alpha, 0);
      fill(red(eventColor), green(eventColor), blue(eventColor), coreAlpha);
      noStroke();
      
      pushMatrix();
      translate(position.x, position.y);
      rotate(rotation + (progress * PI * (isReversePattern ? -2 : 2)));
      ellipse(0, 0, size * (1-progress), size * (1-progress));
      popMatrix();
    }
    
    // Display slices
    pushMatrix();
    translate(position.x, position.y);
    
    // Apply global rotation
    float rotationSpeed = isReversePattern ? -1 : 1;
    rotate(rotation + (progress * rotationSpeed * PI * 0.5));
    
    // Draw each slice
    for (Slice slice : slices) {
      slice.display(eventColor, alpha);
    }
    popMatrix();
    
    // Draw rhythmic rings
    drawRhythmicRings(progress, age);
  }
  
  void drawRhythmicRings(float progress, float age) {
    // Number of rings depends on the track energy
    int numRings = int(3 + (gain * 3));
    
    for (int i = 0; i < numRings; i++) {
      // Each ring has its own phase and timing
      float ringPhase = (beatPhase + (i * TWO_PI / numRings)) % TWO_PI;
      float ringPulse = sin(ringPhase + (age * 0.01 * (isReversePattern ? -1 : 1))) * 0.5 + 0.5;
      
      // Ring size increases with progress and pulses with rhythm
      float ringSize = originalSize * (0.5 + progress * 1.5) * (0.8 + ringPulse * 0.4);
      
      // Ring opacity fades with progress and pulses
      float ringAlpha = alpha * (1 - progress) * ringPulse * 0.7;
      
      if (ringAlpha > 5) {
        noFill();
        stroke(red(eventColor), green(eventColor), blue(eventColor), ringAlpha);
        strokeWeight(1 + ringPulse * 2);
        
        // Draw a slightly distorted ring for glitchy effect
        beginShape();
        for (int j = 0; j < 24; j++) {
          float angle = j * TWO_PI / 24;
          float distortion = 1.0 + (sin(angle * 3 + age * 0.01) * 0.1 * ringPulse);
          float x = position.x + cos(angle) * ringSize * distortion;
          float y = position.y + sin(angle) * ringSize * distortion;
          vertex(x, y);
        }
        endShape(CLOSE);
      }
    }
  }
  
  /**
   * Slice inner class
   * Represents a single slice of the breakbeat visualization
   */
  class Slice {
    PVector position;
    float width, height;
    float angle;
    float fadeOffset;
    float jitterX, jitterY;
    float originalX, originalY;
    float pulsePhase;
    
    Slice(float x, float y, float w, float h, float a, float offset) {
      originalX = x;
      originalY = y;
      position = new PVector(x, y);
      width = w;
      height = h;
      angle = a;
      fadeOffset = offset;
      
      // Random phase for pulse animation
      pulsePhase = random(TWO_PI);
    }
    
    void update(float progress, float age) {
      // Apply movement based on progress
      float expansionFactor = 1.0 + (progress * 2.0);
      
      // Add rhythmic jitter (more for jungle/break patterns)
      jitterX = sin(age * 0.03 + pulsePhase) * width * 0.3 * progress;
      jitterY = cos(age * 0.02 + pulsePhase) * height * 0.3 * progress;
      
      // Update position with expansion and jitter
      position.x = originalX * expansionFactor + jitterX;
      position.y = originalY * expansionFactor + jitterY;
    }
    
    void display(color sliceColor, float baseAlpha) {
      // Calculate individual alpha with offset fading
      float age = millis() - birthTime;
      float individualProgress = constrain((age - fadeOffset) / (lifespan - fadeOffset), 0, 1);
      float sliceAlpha = baseAlpha * (1 - individualProgress);
      
      if (sliceAlpha <= 0) return;
      
      // Apply a pulsing effect
      float pulse = sin(age * 0.01 + pulsePhase) * 0.5 + 0.5;
      float pulseSize = 0.8 + (pulse * 0.4);
      
      // Draw the slice
      pushMatrix();
      translate(position.x, position.y);
      rotate(angle + (individualProgress * PI * (isReversePattern ? -1 : 1)));
      
      // Main slice
      fill(red(sliceColor), green(sliceColor), blue(sliceColor), sliceAlpha);
      noStroke();
      rect(-width/2 * pulseSize, -height/2 * pulseSize, 
           width * pulseSize, height * pulseSize, 2);
      
      // Inner detail
      fill(255, sliceAlpha * 0.5 * pulse);
      rect(-width/4 * pulseSize, -height/4 * pulseSize, 
           width/2 * pulseSize, height/2 * pulseSize, 1);
      
      popMatrix();
    }
  }
}
