
public class Timeline
{
  PVector posOrigin;
  PVector size;
  
  int textsize=12;
  
  color cborder = color(200,200,200);
  color ctimeslider = color(255,255,255);
  
  private float time_start; //in seconds
  private float time_end;
  
  float[] preview_cmd;
  float[] preview_throttle;
  float[] preview_brake;
  float[] preview_currentAll;
  
  public Timeline(int px, int py, int pw, int ph) {
    this.posOrigin= new PVector(px,py); //lower left corner
    this.size = new PVector(pw,ph); //to the right and up
    
    preview_cmd=new float[(int)this.size.x];
    preview_throttle=new float[(int)this.size.x];
    preview_brake=new float[(int)this.size.x];
    preview_currentAll=new float[(int)this.size.x];
  }
  
  
  
  public void generatePreview(Table logdata) {
    int cID=0; //current ID for generating preview in datalog
    for (int x=0;x<this.size.x;x++) //for every width pixel of timeline
    {
      float t1=xPosToTimeSeconds(x); //time start for this pixel
      float t2=xPosToTimeSeconds(x+1); //time end for this pixel
      while ((cID+1 < logdata.getRowCount()) && ( t1 > (logdata.getRow(cID+1).getFloat("time")))) { //while starttime not reached
        cID++; //next
      }
      int preview_mean_counter=0;
      float preview_mean_cmd=0;
      float preview_mean_brake=0;
      float preview_mean_throttle=0;
      float preview_mean_currentAll=0;
      
      
      while ((cID+1 < logdata.getRowCount()) && ( t2 > (logdata.getRow(cID+1).getFloat("time")))) { //while endtime not reached
        TableRow row = logdata.getRow(cID);
        nextTimeData=(int)(logdata.getRow(cID+1).getFloat("time")*1000); //get time and convert from seconds to ms
        
        lastTimeMillis=nextTimeMillis;
        
        
        preview_mean_cmd += (row.getInt("cmd_FrontL")+row.getInt("cmd_FrontR")+row.getInt("cmd_RearL")+row.getInt("cmd_RearR"))/4.0;
        preview_mean_brake += row.getInt("brake");
        preview_mean_throttle += row.getInt("throttle");
        preview_mean_currentAll += row.getFloat("currentAll"); 
        /*
        current_FrontL=row.getFloat("current_FrontL");
        current_FrontR=row.getFloat("current_FrontR");
        current_RearL=row.getFloat("current_RearL");
        current_RearR=row.getFloat("current_RearR");
        speed_FrontL=row.getInt("speed_FrontL");
        speed_FrontR=row.getInt("speed_FrontR");
        speed_RearL=row.getInt("speed_RearL");
        speed_RearR=row.getInt("speed_RearR");
        temp_Front=row.getFloat("temp_Front");
        temp_Rear=row.getFloat("temp_Rear");
        vbat_Front=row.getFloat("vbat_Front");
        vbat_Rear=row.getFloat("vbat_Rear");
        currentAll=row.getFloat("currentAll");    
        throttle=row.getInt("throttle");
        brake=row.getInt("brake");*/
        
        preview_mean_counter++;
        
        cID++; //next
      }
      preview_mean_cmd/=preview_mean_counter;
      preview_mean_brake/=preview_mean_counter;
      preview_mean_throttle/=preview_mean_counter;
      preview_mean_currentAll/=preview_mean_counter;
      
      
      
      preview_cmd[x]=preview_mean_cmd;
      preview_brake[x]=preview_mean_brake;
      preview_throttle[x]=preview_mean_throttle;
      preview_currentAll[x]=preview_mean_currentAll;
    }//next pixel
    
  }
  
  public void setTimes(float _start,float _end) {
    this.time_start=_start;
    this.time_end=_end;
  }
    
  
  public void drawTL(float _time) {
    //Preview visualization
    for (int x=0;x<this.size.x;x++) //for every width pixel of timeline
    {
      if (!Float.isNaN(preview_cmd[x])) {
        float preview_cmd_scaled=constrain(map(preview_cmd[x],0,1000,0.0,1.0), 0.0,1.0);
        preview_cmd_scaled=sqrt(sqrt(preview_cmd_scaled))+0.1;//more contrast
        
        float preview_currentAll_scaled=constrain(map(preview_currentAll[x],0,10,0.0,1.0), 0.0,1.0);
        preview_currentAll_scaled=sqrt(sqrt(preview_currentAll_scaled));//more contrast
        
        colorMode(HSB, 360, 100, 100);
        stroke(color(200-preview_currentAll_scaled*200,100,preview_cmd_scaled*100));
        line(this.posOrigin.x+x,this.posOrigin.y,this.posOrigin.x+x,this.posOrigin.y+this.size.y); //color gradient background
        
        float preview_throttle_scaled=constrain(map(preview_throttle[x],0,1000,0.0,1.0), 0.0,1.0);
        colorMode(HSB, 360, 100, 100);
        stroke(color(240,100,100));
        line(this.posOrigin.x+x,this.posOrigin.y+this.size.y,this.posOrigin.x+x,this.posOrigin.y+this.size.y*(1-preview_throttle_scaled/2)); //line bottom up
        
        float preview_brake_scaled=constrain(map(preview_brake[x],0,1000,0.0,1.0), 0.0,1.0);
        colorMode(HSB, 360, 100, 100);
        stroke(color(0,100,100));
        line(this.posOrigin.x+x,this.posOrigin.y,this.posOrigin.x+x,this.posOrigin.y+this.size.y*preview_brake_scaled/2); //line top down
      }
    }
    
    //Boarder
    rectMode(CORNERS);
    noFill();
    stroke(this.cborder);
    rect(this.posOrigin.x,this.posOrigin.y,this.posOrigin.x+this.size.x,this.posOrigin.y+this.size.y); //border
    
    //current time
    int timeslider_xpos = (int)( this.posOrigin.x+timeSecondsToXPos(_time) );
    stroke(this.ctimeslider);
    line(timeslider_xpos,this.posOrigin.y-3,timeslider_xpos,this.posOrigin.y+this.size.y+3);
    
    
    
    
    textSize(this.textsize);
    textAlign(CENTER);
    text(int(this.time_start+0.5)+"s", this.posOrigin.x, this.posOrigin.y-1); //starttime
    text(int(this.time_end+0.5)+"s", this.posOrigin.x+this.size.x, this.posOrigin.y-1); //endtime
  }
  
  public float checkMouse(int mx, int my) 
  {
    if (mx>=this.posOrigin.x && mx <=this.posOrigin.x+this.size.x && my>=this.posOrigin.y && my<=this.posOrigin.y+this.size.y) { //mouse whithin timeline boarder
      float mousetime=xPosToTimeSeconds((int)(mx-this.posOrigin.x));
      //float mousetimesliderpercent=(mx-this.posOrigin.x)/this.size.x;
      //float mousetime=mousetimesliderpercent*(this.time_end-this.time_start)+this.time_start;
      return millis()/1000.0-mousetime;
    }
    return 0;
  }
  
  private int timeSecondsToXPos(float _time) {
    float timesliderpercent = (_time-this.time_start)/(this.time_end-this.time_start); //0<= x <=1
    return (int)(timesliderpercent*this.size.x);
  }
  
  private float xPosToTimeSeconds(int _x) {
    float mousetimesliderpercent=_x/this.size.x;
    return mousetimesliderpercent*(this.time_end-this.time_start)+this.time_start;
  }
}
