class Slider {

  public static final int ORIENTATION_HORIZONTAL = 0;
  public static final int ORIENTATION_VERTICAL = 1;
  private int ORIENTATION = ORIENTATION_HORIZONTAL;
  
  public static final int NUMBER_MODE_FLOAT = 0;
  public static final int NUMBER_MODE_INT = 1;
  public static final int NUMBER_MODE_BOOLEAN = 2;
  private int NUMBER_MODE = NUMBER_MODE_FLOAT;
  
  private String BOOLEAN_STRING1 = "off";
  private String BOOLEAN_STRING2 = "on";
  
  public static final int SLIDE_MODE_LINEAR = 0;
  public static final int SLIDE_MODE_SQUARE = 1;
  public static final int SLIDE_MODE_SQUARE_ROOT = 2;
  private int SLIDE_MODE = SLIDE_MODE_LINEAR;
  
  public static final int STEP_SIZE_CONTINUOUS = 0;
  private float stepSize = 0.0;
  
  private float OPACITY = 255;
  private float SLIDE_SIZE = 11.0;
  
  private PFont font;
  private String name = "Slide", prename = "";
  private int PRE_DIGITS = 0;
  private int POST_DIGITS = 3;
  
  private float x, y, size;
  private float slideMin, slideRange;
  private float val=0.0, valMin, valRange, oldVal=0.0;
  private boolean pressing = false;
  
  Slider(float _x, float _y,float _size,float _valMin,float _valMax,float _val,int _orientation) {
    x = _x;
    y = _y;
    size = _size;
    valMin = _valMin;
    valRange = (_valMax-_valMin);
    val = _val;
    if (val<valMin) val=valMin;
    if (val>_valMax) val=_valMax;
    oldVal = val;
    ORIENTATION = _orientation;
    slideRange = size-SLIDE_SIZE;
    
    if (ORIENTATION==ORIENTATION_HORIZONTAL) {
      slideMin = x+SLIDE_SIZE/2.0;
    } else {
      slideMin = y+SLIDE_SIZE/2.0;
    }
    
    font = loadFont("BookmanOldStyle-Bold-11.vlw");
  }
  
  Slider(float _x, float _y,float _size,float _valMin,float _valMax,float _val,int _orientation, String n) {
    this(_x,_y,_size,_valMin,_valMax,_val,_orientation);
    name = n;
  }
  
  public void move(float ox, float oy) {
    x+=ox;
    y+=oy;
    if (ORIENTATION==ORIENTATION_HORIZONTAL) {
      slideMin = x+SLIDE_SIZE/2.0;
    } else {
      slideMin = y+SLIDE_SIZE/2.0;
    }
  }
  
  public float getX() {
    return x;
  }
  
  public float getY() {
    return y;
  }
  
  public float getSize() {
    return size;
  }
  
  public float getSlideSize() {
    return SLIDE_SIZE;
  }
  
  public int getOrientation() {
    return ORIENTATION;
  }
  
  public void setNumberMode(int nm) {
    NUMBER_MODE = nm;
    
    if (NUMBER_MODE==NUMBER_MODE_BOOLEAN) {
      valMin = 0;
      valRange = 1;
      oldVal = val;
      stepSize = 1;
    }
  }
  
  public void setBooleanStrings(String s1, String s2) {
    BOOLEAN_STRING1 = s1;
    BOOLEAN_STRING2 = s2;
  }
  
  public void setSlideMode(int sm) {
    SLIDE_MODE = sm;
  }
  
  public void setName(String n) {
    name = n;
  }
  
  public void addPreName(String n) {
    prename = n+"  ";
  }
  
  public void setStepSize(float ss) {
    stepSize = ss;
  }
  
  public String getName() {
    return name;
  }
  
  public void setDigits(int d1, int d2) {
    PRE_DIGITS = d1;
    POST_DIGITS = d2;
  }
  
  public boolean mouseIsOver() {
    if (ORIENTATION==ORIENTATION_HORIZONTAL) {
      if (mouseX>=x&&mouseY>=y&&mouseX<=x+size&&mouseY<=y+SLIDE_SIZE) return true;
    } else {
      if (mouseX>=x&&mouseY>=y&&mouseX<=x+SLIDE_SIZE&&mouseY<=y+size) return true;
    }
    return false;
  }
  
  public void startManipulating() {
    pressing = true;
  }
  public void stopManipulating() {
    pressing = false;
  }
  
  public boolean getBoolean() {
    return (val!=0);
  }
  
  public boolean isManipulated() {
    return pressing;
  }
  
  public boolean hasChanged() {
    boolean out = (oldVal!=val);
    oldVal = val;
    return out;
  }
  
  public float getValue() {
    return val;
  }
  
  public void setValue(float v) {
    val = v;
    if (stepSize!=STEP_SIZE_CONTINUOUS) val = stepSize*round(val/stepSize);
  }
  
  public void invertValue() {
    float p = getPercentageFromValAndValMin();
    p = 1.0 - p;
    setValFromPercentage(p);
  }
  
  public void randomize() {
    oldVal = val;
    float p = random(1.0);
    setValFromPercentage(p);
    //val = valMin + p*valRange;
    //if (stepSize!=STEP_SIZE_CONTINUOUS) val = stepSize*round(val/stepSize);
  }
  
  private void setValFromPercentage(float p) {
    p = min(max(p,0.0),1.0); // restrain to 0..1
    if (SLIDE_MODE == SLIDE_MODE_LINEAR) {
      val = valMin + p*valRange;
    } else if (SLIDE_MODE == SLIDE_MODE_SQUARE) {
      val = valMin + sq(p)*valRange;
    } else if (SLIDE_MODE == SLIDE_MODE_SQUARE_ROOT) {
      val = valMin + sqrt(p)*valRange;
    }
    if (stepSize!=STEP_SIZE_CONTINUOUS) val = stepSize*round(val/stepSize);
  }
  
  private float getPercentageFromValAndValMin() {
    float out = 0;
    if (SLIDE_MODE == SLIDE_MODE_LINEAR) {
      out = (val-valMin)/valRange;
    } else if (SLIDE_MODE == SLIDE_MODE_SQUARE) {
      out = sqrt((val-valMin)/valRange);
    } else if (SLIDE_MODE == SLIDE_MODE_SQUARE_ROOT) {
      out = sq((val-valMin)/valRange);
    }
    return out;
  }
  
  void update() {
    if (pressing) {
      if (ORIENTATION==ORIENTATION_HORIZONTAL) {
        float p = (mouseX-x-SLIDE_SIZE/2.0)/(size-SLIDE_SIZE);
        setValFromPercentage(p);
      } else {
        float p = (mouseY-y-SLIDE_SIZE/2.0)/(size-SLIDE_SIZE);
        p = 1.0-p;
        setValFromPercentage(p);
      }
      if (stepSize!=STEP_SIZE_CONTINUOUS) val = stepSize*round(val/stepSize);
      if (NUMBER_MODE==NUMBER_MODE_INT) val=int(round(val));
    }
  }
  
  void draw() {
    rectMode(CORNERS);
    stroke(0,0,0,OPACITY);
    fill(128,128,128,OPACITY);
    textFont(font,11);
    
    float p = getPercentageFromValAndValMin();
    if (ORIENTATION==ORIENTATION_HORIZONTAL) {
      rect(x,y,x+size,y+SLIDE_SIZE);
      fill(64,64,64,OPACITY);
      rectMode(CORNER);
      rect(slideMin+p*slideRange-SLIDE_SIZE/2.0,y,SLIDE_SIZE,SLIDE_SIZE);
      fill(64,64,64,OPACITY);
      textAlign(LEFT);
      if (NUMBER_MODE==NUMBER_MODE_BOOLEAN) {
        text(prename+name+": "+(val==0?BOOLEAN_STRING1:BOOLEAN_STRING2),x+size+SLIDE_SIZE,y+SLIDE_SIZE-2);
      } else {
        text(prename+name+": "+nf(val,PRE_DIGITS,POST_DIGITS),x+size+SLIDE_SIZE,y+SLIDE_SIZE-2);
      }
    } else {
      rect(x,y,x+SLIDE_SIZE,y+size);
      fill(64,64,64,OPACITY);
      rectMode(CORNER);
      rect(x,slideMin+(1.0-p)*slideRange-SLIDE_SIZE/2.0,SLIDE_SIZE,SLIDE_SIZE);
      fill(64,64,64,OPACITY);
      textAlign(CENTER);
      text(prename+name+": ",x+SLIDE_SIZE/2.0,y+size+SLIDE_SIZE);
      if (NUMBER_MODE==NUMBER_MODE_BOOLEAN) {
        text(val==0?"off":"on",x+SLIDE_SIZE/2.0,y+size+SLIDE_SIZE+14);
      } else {
        text(nf(val,PRE_DIGITS,POST_DIGITS),x+SLIDE_SIZE/2.0,y+size+SLIDE_SIZE+14);
      }
    }
  }

}
