import { Component, OnInit,Input,ViewChild,OnChanges,ChangeDetectorRef,Output, EventEmitter,SimpleChanges } from '@angular/core';
import { DatePipe } from '@angular/common';
import {NgbPopover} from '@ng-bootstrap/ng-bootstrap';

export interface TimeSpan {
  startDate:Date;
  endDate:Date;
}

@Component({
  selector: 'fm-timespan',
  templateUrl: './timespan.component.html',
  styleUrls: ['./timespan.component.css']
})
export class TimespanComponent implements OnInit, OnChanges {

  scale:number = 1000 * 60 * 60 ; // milliseconds / pixel ( 1 hour )
  unitScales:number[] = [1,1000,1000*60,1000*60*60,1000*60*60*24,1000*60*60*24*7,1000*60*60*24*31,1000*60*60*24*31*3,1000*60*60*24*365.25];
  units:string[] = [ 'millisecond','second','minute','hour','day','week','month','quarter','year'];
  quarters:string[] = ['KW1','KW2','KW3','KW4'];
  unitScale = 3;
  viewMinDate:Date;
  viewMaxDate:Date;
  extentMinDate:Date;
  extentMaxDate:Date;
  cursorDate:Date;
  leftGripMove = false;
  rightGripMove = false;
  rangeGripMove = false;
  viewPan = false;
  downX = -1;
  mouseX = -1;
  mouseY = -1;
  elementWidth:number;
  elementHeight:number;
  lastOffsetInPixels=0;
  @ViewChild('timeLine', { static: true }) canvasRef;
  @ViewChild('popoverStart', { static: true }) public popoverStart:NgbPopover;
  @ViewChild('popoverEnd', { static: true }) public popoverEnd:NgbPopover;
  @Input() collapsed = true;
  @Input() startDate: Date = new Date(2018,1,3);
  @Input() endDate: Date = new Date(2018,1,5);
  @Input() unit:string;
  @Input() color = '#000000';
  @Input() background = '#ffffff';
  @Input() hoverColor ='#ffffff';
  @Input() hoverBackground ='#0000ff';
  @Input() lineColor='#000000';
  @Input() lineWidth=1;
  @Input() padding = 4;
  @Output() change:EventEmitter<TimeSpan> = new EventEmitter();
  public caption = "2016/2017";
  public marginLeft = 100;
  public startPopoverLeft=110;
  public endPopoverLeft=120;
  public rangeWidth =75;
  public startCaption={};
  public endCaption={};
  private ratio=1;
  private initialized=false;
  private ctx:CanvasRenderingContext2D;
  public posibleUnits:number[] = [];
  public height = 0;
  public lineHeight = 0;

  constructor(private changeDetectorRef: ChangeDetectorRef,private datePipe: DatePipe) { }

  setCanvasSize() {
    const canvas = this.canvasRef.nativeElement;
    this.elementWidth = canvas.offsetWidth;
    this.elementHeight = canvas.offsetHeight;
    canvas.height = this.elementHeight * this.ratio;
    canvas.width = this.elementWidth * this.ratio;
  }

  getPosibleUnits(scale:number):number[] {
    const posibleUnits = [];
    for(const u of [3,4,6,8]) {
      if((this.unitScale <=u) )
        posibleUnits.push(u);
    }
    return posibleUnits;
  }

  getLineHeight():number {
    return (parseInt(this.ctx.font.match(/\d+/)[0], 10)/ this.ratio) + (2*this.padding) ;
  }

  getHeight():number {
   
     return (this.posibleUnits.length * this.getLineHeight());
  }

  ngOnInit() {        
    this.ratio = 2;
    this.unitScale = this.getUnitScale(this.unit);
    const canvas:HTMLCanvasElement = this.canvasRef.nativeElement;
    this.ctx = canvas.getContext('2d');
    this.elementWidth = canvas.offsetWidth;
    this.elementHeight = canvas.offsetHeight;
    this.ctx.font=`normal ${this.ratio*10}pt Sans-serif`;
    this.startDate = new Date(this.startDate.getTime() + this.getUnitDateOffset(this.startDate,this.unitScale,0));
    this.endDate = new Date(this.endDate.getTime() + this.getUnitDateOffset(this.endDate,this.unitScale,1));
    this.change.emit({startDate:this.startDate,endDate:this.endDate});
    const rangeInMilliseconds = this.endDate.getTime() - this.startDate.getTime();
    this.scale = this.getFitScale(rangeInMilliseconds,this.elementWidth);
    this.posibleUnits=this.getPosibleUnits(this.scale);
    this.height=this.getHeight();
    this.lineHeight= this.getLineHeight();
    this.setCanvasSize();    
    const center = (this.startDate.getTime()+this.endDate.getTime())/2;
    this.viewMinDate = new Date(center - (this.elementWidth/2* this.scale));
    this.viewMaxDate = new Date(center + (this.elementWidth/2* this.scale));    
    this.updateStyle(this.startDate,this.endDate);
    this.startCaption={popoverCaption:this.getStartCaption(this.startDate,this.unitScale,true)};
    this.endCaption={popoverCaption:this.getEndCaption(this.endDate,this.unitScale,true)};  
    this.redraw();
    this.initialized=true;
  }

  getStartEndCaption(date:Date,otherDate:Date,unitScale:number,suffix = false,extended=true):string {    
    const showSuffix = false;
    otherDate=new Date(otherDate.getTime()-1); // fix year edge case
    if(unitScale == 3) { 
      let format="HH:00";
      if(extended) {
        if(suffix || date.getFullYear() != otherDate.getFullYear()) 
          format="d MMM yyyy:HH:00";
        else if(date.getMonth() !== otherDate.getMonth()) 
          format="d MMM HH:00";
      }
      return this.datePipe.transform(date,format);       
    
    }
    if(unitScale == 4) { 
      let format="d";
      if(extended) {
        if(suffix || date.getFullYear() != otherDate.getFullYear()) 
        format="d MMM yyyy";
      else if(date.getMonth() !== otherDate.getMonth()) 
        format="d MMM"     
      }
      return this.datePipe.transform(date,format);       
    
    }
    if(unitScale == 6) {
      let format = "MMM";
      if(extended) {
        if(suffix || date.getFullYear() != otherDate.getFullYear())
        format="MMM yyyy";
      }
      return  this.datePipe.transform(date,format);
    }
    if(unitScale == 7) {
      const q = Math.trunc(date.getMonth() /3 );
      return  this.quarters[q]; 
    }
    if(unitScale == 8) {
      return  this.datePipe.transform(date,"yyyy");
    }
    return "";
  }

  getStartCaption(startDate:Date,unitScale:number,suffix=false,extended=true):string {
    return this.getStartEndCaption(new Date(startDate.getTime() + (this.unitScales[unitScale]/2)), this.endDate,unitScale,suffix,extended);
  }

  getEndCaption(endDate:Date,unitScale:number,suffix=true):string {
    return this.getStartEndCaption(new Date(endDate.getTime() - (this.unitScales[unitScale]/2)),this.startDate, unitScale,suffix);
  }

  getCaption(startDate:Date,endDate:Date,unitScale:number):string {
    const startCaption=this.getStartCaption(startDate,unitScale);
    const endCaption=this.getEndCaption(endDate,unitScale);
    if((endDate.getTime() - startDate.getTime()) < (1.5*this.unitScales[this.unitScale]))
      return endCaption;
    return `${startCaption}-${endCaption}`;
  }

  public updatePopoverText(popover:NgbPopover, text:string): void {
    const isOpen = popover.isOpen();
    if (isOpen) {
      popover.close();      
      popover.open({popoverCaption:text});
    }
  }  

  getFitScale(rangeInMilliSeconds:number,elementWidth:number):number {
      const width = elementWidth*0.33;
      return rangeInMilliSeconds/width;
  }

  getUnitScale(unit:string):number {
    if(!unit) return 3; // hour
    for(let _i=0;_i<this.units.length;_i++) {
      if(this.units[_i]==unit.toLowerCase()) return _i;
    }
    throw new Error(`Invalid unit : {{unit}} `);
  } 

  getUnitDateOffset(date:Date, unitScale:number,tick:number):number {
    let offsetDate:Date;
    if(unitScale==0) 
      offsetDate = new Date(date.getFullYear(),date.getMonth(),date.getDate() ,date.getHours() ,date.getMinutes(),date.getSeconds(),date.getMilliseconds()+ tick);
    if(unitScale==1) 
      offsetDate = new Date(date.getFullYear(),date.getMonth(),date.getDate() ,date.getHours() ,date.getMinutes(),date.getSeconds() + tick,0);
    if(unitScale==2) 
      offsetDate = new Date(date.getFullYear(),date.getMonth(),date.getDate() ,date.getHours() ,date.getMinutes() + tick,0,0);
    if(unitScale==3) 
      offsetDate = new Date(date.getFullYear(),date.getMonth(),date.getDate() ,date.getHours()+ tick ,0,0,0);
    if(unitScale==4) 
      offsetDate = new Date(date.getFullYear(),date.getMonth(),date.getDate() + tick ,0,0,0,0);
    if(unitScale==6) 
      offsetDate = new Date(date.getFullYear(),date.getMonth()+tick,1,0,0,0,0);
    if(unitScale==7)  {      
      const month = (tick * 3);
      offsetDate = new Date(date.getFullYear(),month,1,0,0,0,0);
    }      
    if(unitScale==8) 
      offsetDate = new Date(date.getFullYear()+tick,0,1,0,0,0,0);
    return offsetDate.getTime()-date.getTime();
  }

  getUnitTextWidth(unitScale:number):number {
    switch(unitScale) {
      case 3:return this.ctx.measureText("88:88").width/this.ratio;
      case 4:return this.ctx.measureText("88").width/this.ratio;
      case 5:return this.ctx.measureText("WWW").width/this.ratio;
      case 6:return this.ctx.measureText("WW").width/this.ratio;
      case 7:return this.ctx.measureText("WW").width/this.ratio;
      case 8:return this.ctx.measureText("8888").width/this.ratio;
      default: return this.ctx.measureText("WW").width/this.ratio;
    }
  }

  getNextTick(viewStartDate:Date, tick:number,step:number,unitScale:number):number {    
    const unitTextWidth = this.getUnitTextWidth(unitScale);
    const dateOffset =this.getUnitDateOffset(viewStartDate,unitScale,tick);
    const date = new Date(viewStartDate.getTime() + dateOffset);
    let nextTick=tick+step+Math.trunc(step/2);
    const nextDateOffset =this.getUnitDateOffset(viewStartDate,unitScale,nextTick);
    const nextDate = new Date(viewStartDate.getTime() + nextDateOffset);    
    let n=1;
    switch(unitScale) {
       case 4:n=nextDate.getDate()-1;break;
       case 6:n=nextDate.getMonth();break;
       case 8:n=nextDate.getFullYear();break;
       default: n = 1;break;
    }
    const a = Math.trunc(n / step)*step;
    nextTick=nextTick-n+a;     
    if(nextTick<=tick) return tick+step;
    return nextTick;
  }

  getSteps(unitScale:number):number[] {
    if(unitScale==4) 
      return [1,14];
    if(unitScale==6) 
      return [1,3,6];
    return [1,2,3,4,5];
  }

  drawUnits(yOffset:number,width:number,viewStartDate:Date,unitScale:number):number {    
    const oneUnit = (this.getUnitDateOffset(viewStartDate,unitScale,1)- this.getUnitDateOffset(viewStartDate,unitScale,0)) / this.scale;   
    this.ctx.font=`normal ${this.ratio*10}pt Sans-serif`;
    const lineHeight = this.getLineHeight();
    let dateOffset = this.getUnitDateOffset(viewStartDate,unitScale,0);
    let pixelOffset =  (dateOffset / this.scale);
    let caption = this.getStartCaption(new Date(viewStartDate.getTime()+dateOffset),unitScale,false,false);
    const unitTextWidth=this.getUnitTextWidth(unitScale);
    this.ctx.beginPath();
    this.ctx.strokeStyle=this.lineColor;  
    const steps=this.getSteps(unitScale);
    let s=0;
    let step=steps[s];
    let steppedOneUnit=oneUnit*step;
    while(unitTextWidth > (steppedOneUnit-(2*this.padding)) && s < steps.length -1) {
      step=steps[++s];
      steppedOneUnit=oneUnit*step;
    }   
    if(steppedOneUnit - (2*this.padding) < unitTextWidth) return yOffset;  
    this.ctx.moveTo(0,yOffset*this.ratio);
    this.ctx.lineTo(width*this.ratio,yOffset*this.ratio);
    this.ctx.stroke();
    let x:number = pixelOffset;
    let nextDateOffset = this.getUnitDateOffset(viewStartDate,unitScale,1);
    let nextX:number = (nextDateOffset / this.scale);
    let n=0;
    while(x < width) {
      this.ctx.fillStyle=this.color;
      //mouseover
      if(this.mouseX> x && this.mouseX <nextX && this.mouseY > yOffset && this.mouseY <( yOffset + lineHeight) && !this.leftGripMove && !this.rightGripMove && !this.rangeGripMove&& !this.viewPan) {
        this.ctx.fillStyle=this.hoverBackground;
        this.ctx.fillRect((x+0.5)*this.ratio,(yOffset+0.5)*this.ratio,(nextX-x)*this.ratio,lineHeight*this.ratio);
        this.ctx.fillStyle=this.hoverColor;
      }

      this.ctx.moveTo((x+0.5)*this.ratio,(yOffset+0.5)*this.ratio);
      this.ctx.lineTo((x+0.5)*this.ratio,(yOffset+lineHeight+0.5)*this.ratio);
      this.ctx.stroke();
     
      if(unitTextWidth < steppedOneUnit - (2*this.padding) && x > 0) {
        this.ctx.fillText(caption,(x+this.padding)*this.ratio,(yOffset+lineHeight-this.padding)*this.ratio);
      } else if((unitTextWidth < (steppedOneUnit - (2*this.padding) +pixelOffset)) && (unitTextWidth < (steppedOneUnit-(2*this.padding)))) {
        this.ctx.fillText(caption, (this.padding*this.ratio),(yOffset+lineHeight-this.padding)*this.ratio);
      } else if(x < 0 && (unitTextWidth <steppedOneUnit - (2*this.padding))) {
        this.ctx.fillText(caption, ((x+steppedOneUnit-this.padding-unitTextWidth) *this.ratio),(yOffset+ lineHeight-this.padding)*this.ratio);
      }
      n=this.getNextTick(viewStartDate,n,step,unitScale);
      dateOffset = this.getUnitDateOffset(viewStartDate,unitScale,n);
      nextDateOffset = this.getUnitDateOffset(viewStartDate,unitScale,this.getNextTick(viewStartDate,n,step,unitScale));
      nextX = (nextDateOffset / this.scale);
      pixelOffset =  (dateOffset / this.scale);
      caption= this.getStartCaption(new Date(viewStartDate.getTime()+dateOffset),unitScale,false,false);
      x=pixelOffset;
    }
    return lineHeight;
  }

  redraw() {   
    let yOffset=0;
    const canvas = this.canvasRef.nativeElement;
    const height = canvas.offsetHeight;
    const width = canvas.offsetWidth;
    this.ctx.lineWidth = this.lineWidth;// *this.ratio;
    this.ctx.clearRect(0,0,width *this.ratio,height*this.ratio);
    for(const unit of this.posibleUnits) {
      if(this.unitScale <=unit) yOffset+=this.drawUnits(yOffset,width,this.viewMinDate,unit);
    }    
  }  

  handleClick() {
    this.collapsed = !this.collapsed;
  }  

  updateStyle(startDate:Date,endDate:Date) {
    const rangeInMilliseconds = endDate.getTime() - startDate.getTime();
    const range = rangeInMilliseconds / this.scale;
    const left = (startDate.getTime() - this.viewMinDate.getTime()) / this.scale;
    this.startPopoverLeft=(left-10);
    this.endPopoverLeft=(left+range+10);
    this.marginLeft = (left - 15);
    this.rangeWidth = range;
    this.updatePopoverText(this.popoverStart,this.getStartCaption(startDate,this.unitScale,true));
    this.updatePopoverText(this.popoverEnd,this.getEndCaption(endDate,this.unitScale,true));
    this.caption=this.getCaption(startDate,endDate,this.unitScale);
  }

  snapToUnit(date:Date,unitScale:number):Date {
    const d = new Date(date.getTime() + (this.unitScales[this.unitScale]/2));
    const offsetInMilliseconds =this.getUnitDateOffset(d,this.unitScale,0)
    return new Date(d.getTime()+offsetInMilliseconds);
  }

  getEndDate(offsetInPixels:number):Date {
    const oneUnit = this.unitScales[this.unitScale];
    const offsetInMilliseconds = offsetInPixels * this.scale;   
    if(this.leftGripMove) {
      if(this.startDate.getTime() + offsetInMilliseconds > this.endDate.getTime() - oneUnit) {
        return this.snapToUnit(new Date(this.startDate.getTime() + offsetInMilliseconds + oneUnit),this.unitScale);
      } 
    } else if(this.rightGripMove || this.rangeGripMove) {
      return this.snapToUnit(new Date(this.endDate.getTime() + offsetInMilliseconds),this.unitScale);
    } 
    return this.endDate;
  }

  getStartDate(offsetInPixels:number):Date {
    const oneUnit = this.unitScales[this.unitScale];
    const offsetInMilliseconds = offsetInPixels * this.scale;
    if(this.leftGripMove || this.rangeGripMove) {
      return this.snapToUnit(new Date(this.startDate.getTime() + offsetInMilliseconds),this.unitScale);     
    } else if(this.rightGripMove) {
      if(this.endDate.getTime() + offsetInMilliseconds < this.startDate.getTime() + oneUnit) {
        return this.snapToUnit(new Date(this.endDate.getTime() + offsetInMilliseconds - oneUnit),this.unitScale);
      } 
    } 
    return this.startDate;
  }

  updateControl(event:MouseEvent|TouchEvent) {
    const offsetInPixels = this.getClientX(event) - this.downX;
     if(this.leftGripMove || this.rightGripMove || this.rangeGripMove) {      
       const startDate = this.getStartDate(offsetInPixels);
       const endDate = this.getEndDate(offsetInPixels);
       this.updateStyle(startDate,endDate)
       this.changeDetectorRef.detectChanges();
     }  else if(this.viewPan) {
        const offsetInMilliseconds = offsetInPixels*this.scale;
        this.viewMinDate = new Date(this.viewMinDate.getTime()-offsetInMilliseconds);
        this.viewMaxDate = new Date(this.viewMaxDate.getTime()-offsetInMilliseconds);
        this.updateStyle(this.startDate,this.endDate);
        this.redraw();
        this.changeDetectorRef.detectChanges();
        this.downX=this.getClientX(event);
     }
     this.lastOffsetInPixels=offsetInPixels
  }

  isMouseEvent(arg: any): arg is MouseEvent {
    return arg.clientX !== undefined;
  }

  getClientX(event:MouseEvent|TouchEvent) {
    if(this.isMouseEvent(event)) {
      return (event as MouseEvent).clientX;
    } else {
      return (event as TouchEvent).touches[0].clientX;
    }
  }

  handleRightGripMouseDown(event:MouseEvent) {
    this.rightGripMove=true;
    this.downX = this.getClientX(event);
    this.popoverEnd.open(this.endCaption);
    event.preventDefault();
  }

  handleRightGripMouseEnter(event:MouseEvent) {
    this.mouseX=-1;
    this.mouseY=-1;
    this.redraw();    
    if(!this.rangeGripMove && !this.leftGripMove && !this.rightGripMove)  this.popoverEnd.open(this.endCaption);
  }

  handleRightGripMouseLeave(event:MouseEvent) {
    if(!this.rightGripMove) this.popoverEnd.close();
  }

  handleLeftGripMouseDown(event:MouseEvent|TouchEvent) {
    this.leftGripMove=true;
    this.downX = this.getClientX(event);
    this.popoverStart.open(this.startCaption);
    event.preventDefault();
  }

  handleLeftGripMouseEnter(event:MouseEvent|TouchEvent) {
    this.mouseX=-1;
    this.mouseY=-1;
    this.redraw();
    if(!this.rangeGripMove && !this.leftGripMove && !this.rightGripMove) this.popoverStart.open(this.startCaption);
  }

  handleLeftGripMouseLeave(event:MouseEvent) {
    if(!this.leftGripMove) this.popoverStart.close();
  }

  handleRangeGripMouseEnter(event:MouseEvent) {
    this.mouseX=-1;
    this.mouseY=-1;
    this.redraw();    
  }

  handleRangeGripMouseDown(event:MouseEvent|TouchEvent) {
    this.rangeGripMove=true;
    this.downX = this.getClientX(event);
    event.preventDefault();
  }
 
  handleViewPanMouseDown(event:MouseEvent|TouchEvent) {
    this.viewPan=true;
    this.downX =this.getClientX(event);
    event.preventDefault();
  }

  handleMouseUp(event:MouseEvent|TouchEvent) {
    //this.updateControl(event);
    this.startDate = this.getStartDate(this.lastOffsetInPixels);
    this.endDate = this.getEndDate(this.lastOffsetInPixels);
    this.popoverStart.close();
    this.popoverEnd.close();
    this.startCaption={popoverCaption:this.getStartCaption(this.startDate,this.unitScale,true)};
    this.endCaption={popoverCaption:this.getEndCaption(this.endDate,this.unitScale,true)};
    if(this.leftGripMove || this.rightGripMove || this.rangeGripMove) {
      this.change.emit({ startDate:this.startDate,endDate:this.endDate});    
    }
    this.rightGripMove=false;
    this.leftGripMove=false;
    this.rangeGripMove=false;
    this.viewPan = false;   
    this.lastOffsetInPixels=0;
  }

  handleMouseMove(event:MouseEvent) {   
    this.mouseX = -1;
    this.mouseY = -1;
    if(!this.leftGripMove && ! this.rightGripMove && !this.rangeGripMove && !this.viewPan) {           
      return;  
    } else {
     this.updateControl(event);         
    }
  }

  handleCanvasMouseMove(event:MouseEvent) {
    this.mouseX = event.offsetX;
    this.mouseY = event.offsetY;
    this.redraw();
  }

  handleCanvasMouseLeave(event:MouseEvent) {
    this.mouseX = -1;
    this.mouseY = -1;
    this.redraw();
  }

  canZoom(currentScale:number, direction:number):boolean {
    let nextScale=currentScale;
    if(direction<0 ) {
      return true;
    } else {
      nextScale*=1.1;
      const canZoom=false;
      const oneUnit = (this.getUnitDateOffset(this.viewMinDate,8,1)- this.getUnitDateOffset(this.viewMinDate,8,0)) / nextScale;   
      const unitTextWidth=this.getUnitTextWidth(8);
      const steps=this.getSteps(8);
      let s=0;
      let step=steps[s];
      let steppedOneUnit=oneUnit*step;
      while(unitTextWidth > (steppedOneUnit-(2*this.padding)) && s < steps.length -1) {
        step=steps[++s];
        steppedOneUnit=oneUnit*step;
      }   
      return unitTextWidth < (steppedOneUnit-(2*this.padding)) && s < steps.length;
    }
  }

  handleMouseWheel(event:WheelEvent) {
    if(!this.canZoom(this.scale,event.deltaY)) return;
    const oldOffsetInMilliseconds = event.clientX * this.scale;
    if(event.deltaY>=0) 
      this.scale*=1.1;
    else
      this.scale/=1.1;
    this.posibleUnits=this.getPosibleUnits(this.scale);
    this.height=this.getHeight();
    this.changeDetectorRef.detectChanges();
    this.setCanvasSize();
    const newOffsetInMilliseconds = event.clientX * this.scale;
    const offsetInMilliseconds = newOffsetInMilliseconds-oldOffsetInMilliseconds;
    this.viewMinDate = new Date(this.viewMinDate.getTime()-offsetInMilliseconds);
    this.viewMaxDate = new Date(this.viewMaxDate.getTime()-offsetInMilliseconds);
    this.updateStyle(this.startDate,this.endDate);
    this.redraw();
    this.changeDetectorRef.detectChanges();
  }

  handleZoomOut() {
    if(!this.canZoom(this.scale,1)) return;
    this.scale*=1.1;
    this.posibleUnits=this.getPosibleUnits(this.scale);
    this.height=this.getHeight();
    this.setCanvasSize();
    this.redraw();
    this.updateStyle(this.startDate,this.endDate);
  }

  handleZoomIn() {
    if(!this.canZoom(this.scale,-1)) return;
    this.scale/=1.1;
    this.posibleUnits=this.getPosibleUnits(this.scale);
    this.height=this.getHeight();
    this.setCanvasSize();
    this.redraw();  
    this.updateStyle(this.startDate,this.endDate);
  }

  handleResize(event:any) {
    if(this.initialized) {
      this.setCanvasSize();
      this.updateStyle(this.startDate,this.endDate);
      this.redraw();
    }   
  }

  ngOnChanges (changes: SimpleChanges) {
    if(this.initialized) {
      this.setCanvasSize();
      this.updateStyle(this.startDate,this.endDate);
      this.redraw();
    }   
  }
}
