/* Copyright (c) 2008 Jeremy English <jhe@jeremyenglish.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation.  No representations are made about the suitability of this
* software for any purpose.  It is provided "as is" without express or
* implied warranty.
*
* Created: 30-December-2008
*
* Program that lets you change the period and the update speed of a sine wave.
*/

class Slider{
  private int x;
  private int y;
  private int w;
  private int h;
  private int value;
  private int sx; //slider x
  private int sy; //slider y
  private int sw; //slider width
  private int sh; //slider height;
  private color c;
  private boolean grabbed;
  private float stepper;
  
  //Value should be in the range of 0 to 100. 0 being all the way to the left.
  Slider(int x, int y, int width, int height, int value, color c){
    this.x = x;
    this.y = y;
    this.w = width;
    this.h = height;
    this.value = value;
    this.sw = round(width / 10);
    this.sh = height;
    this.sy = y;
    this.c = c;
    grabbed = false;
    stepper = (this.w - sw) / 100.0;
  }
  
  private void set_sx(){
    sx = round((value * stepper) + x);
//    print(wd);print(",");println(sx);    
  }
  
  void draw(){
    stroke(0);
    fill(0);
    //Paint the end peices
    rect(x,y,1,sh);
    rect(w + x,y,1,sh);
    
    //paint the slot for the slider
    rect(x,y + (h/2),w,1);
    
    //paint the slider
    fill(c);
    set_sx();
    rect(sx,sy,sw,sh);
  }
  
  void mousePress(){
    int mx = mouseX;
    int my = mouseY;
    grabbed = false;
    //Check to see if the mouse is inside the slider
    if (mousePressed && mouseButton == LEFT){
      //Check to see if the mouse is inside the slider
      if (sx < mx && mx < (sx + sw) && my > sy && my < (sy + sh)){
        grabbed = true;
      }
    }
  }
  
  void mouseDragged(){
    int mx = mouseX;
    if (grabbed){
      if(x <= mx && mx <= ((w - sw) + x)){
        int x1 = mx - x;
        value = round(x1/stepper);
      }
    }
  }
  
  int getValue(){
    return value;
  }
  
}

Slider sl, ssl;
PFont font;
int old;
int action_time = 10;
int [] history;
int x;

void setup(){
  size(600,400);
  sl = new Slider(130,300,360,20,100,color(0xff,0x7f,0,75));
  ssl = new Slider(130,50,360,20,50,color(0xff,0,0,75));
  background(0xFAF5C2);
  font = loadFont("ScalaSans-Caps-32.vlw");
  history = new int[20];
  for (int i = 0; i < history.length; i++)
    history[i] = -1;  
}

void push(int n){
  int j = 1;
  int [] tmp;
  tmp = new int[history.length];
  for (int i = 0; i < history.length - 1; i++){
    tmp[j++] = history[i];    
  }
  tmp[0] = n;
  for (int i = 0; i < tmp.length; i++){
    history[i] = tmp[i];
//    print(tmp[i]); print(",");
  }
//  println();
}

void mousePressed(){
  sl.mousePress();
  ssl.mousePress();
}

void mouseDragged(){
  sl.mouseDragged();
  ssl.mouseDragged();
}

void draw(){
  background(0xFAF5C2);
  sl.draw();
  ssl.draw();
  action_time = round(0.40 * ssl.getValue());

  fill(0xff);
  rect(0,200,width,1);
  
  int m = millis();
  int d = m - old;
  if (d > action_time){
    x = (x + 1) % width;
    old = m;
    push(x);
  }
  noStroke();

  float p = sl.getValue()/1000.0;
  int op = 100;
  int op_step = op/history.length;
  for(int i = 0; i < history.length; i++){
    int x = history[i]; 
    if (x < 0) break;
    fill(0xff,0,0xff,op);
    ellipse(x,(sin(x*p)*100)+200,5,5);
   op = op - op_step;    
  }

  textAlign(CENTER);
  textFont(font);
  String cap = "SIN(X * " + p + ")";
  fill(color(0x20));
  text(cap,width/2,height - (height/10));

  textAlign(LEFT);
  cap = "Period";
  text(cap,0,320);
  cap = "Speed";
  text(cap,0,70);
  
}
