function NavBar(set, source) {
    /**
    * chartset
    */
    this._parent = set;
    
    /**
    * source
    */
    this._source = source;
    this._context = set._getContext();
    /**
    * size
    */
    this._size = 0;
    
    /**
    * position
    */
    this._position = 0;
    
    this._scrollOffset = [0,0];
    this._dragging = false;
    this._hover = false;
    this._dragX = 0;
    this._dragM = 0;
    this._interval = 60;
    
    //==========================================================
    // internal functions
    //==========================================================
    /**
    * redraw
    */
    this.redraw = function() {
       //this._draw();
       this._parent.redraw();
    }
    /**
    * draw the bar
    */
    this._draw = function() {
        var c = this._context;
        
        if(!this._source.buffer) {
            return;
        }
        
        c.save();
        c.translate(0, this._position);
      
        // draw axes
        var y = ((this._size-1)|0)+0.5;
        var x = ((this._parent._size[0]-1)|0)+0.5;
        
        c.strokeStyle = this._parent._style.axisColor;
        // x
        c.beginPath();
        c.moveTo(0.5,y);
        c.lineTo(x,y);
        c.stroke();
        c.beginPath();
        c.moveTo(0.5,0.5);
        c.lineTo(x,0.5);
        c.stroke();
        // y
        c.beginPath();
        c.moveTo(x,0.5);
        c.lineTo(x,y);
        c.stroke();
        c.beginPath();
        c.moveTo(0.5,0.5);
        c.lineTo(0.5,y);
        c.stroke();
        
        
        
        var buffer = this._source.source.getBuffer(this._interval);
        
       
        // draw active area
        c.fillStyle = this._parent._style.navBarAreaColor;
        c.strokeStyle = this._parent._style.navBarHandleColor;
        var s = this._source.span[0];
        var e = this._source.span[1];
        
        if(this._source.buffer.size == 1) {
            x = 0;
            w = this._parent._size[0];
        } else {
            x = 1+(s.index/(this._source.buffer.size-1))*(this._parent._size[0]-2);
            w = ((e.index-s.index)/(this._source.buffer.size-1))*(this._parent._size[0]-2);
        }
        c.fillRect(x,0,w,this._size);
        
        // draw dragging handle   
        var l = this._dragging?this._dragging:this._hover;
        if(l == 2 || l == 3) {
            if(l == 3) {
                x += w;
            }
            c.lineWidth = 2;
            c.beginPath();
            c.moveTo(x,0);
            c.lineTo(x,this._size);
            c.stroke();
            c.lineWidth = 1;
        }
        // draw line
        c.strokeStyle = this._parent._style.navBarLineColor;
        
        s = buffer.begin;
        e = buffer.end;
        c.beginPath();
        
        var cur = s;
        var range = buffer.high.high - buffer.low.low;
        var low = buffer.low.low - range*0.1;
        var high = buffer.high.high + range*0.1;
        if(low < 0) {
            low = 0;
        }
        
        var tw = (this._parent._size[0]-3)/(buffer.size-1);
        y = ((( 1 - ( ( cur.close - low ) / ( high - low) ) )*this._size)|0)+0.5;
        x = 1;
        c.moveTo(0.5,y);
        while(cur) {
            y = ((( 1 - ( ( cur.close - low ) / ( high - low) ) )*this._size)|0)+0.5;
            c.lineTo((x|0)+0.5,y);
            cur = cur.next;
            x += tw;
        } 
        
        c.stroke();
        
        c.restore();
    }
    
    this._getArea = function(x) {
        if(!this._source.buffer || !this._source.span) {
            return false;
        }
             
        var left = (this._source.span[0].index/(this._source.buffer.size-1))*this._parent._size[0];
        var right = (this._source.span[1].index/(this._source.buffer.size-1))*this._parent._size[0];
        var o = x - left;
        var o2 = right - x;
        if( o > -5 && o < 5) {
            return 2;
        } else if(o2 > -5 && o2 < 5){
            return 3;
        } else if(x > left && x < right){
            return 1;
        }   
        
        return false;
    }
    
    this._updateStyle = function() {
        
    }
    
    this._updateHover = function(x) {
        var a = this._getArea(x);
        if(a != this._hover) {
            var cursor = '';
            if(a == 1) {
                cursor = 'move';
            } else if(a == 2) {
                cursor = 'w-resize';
            } else if(a == 3) {
                cursor = 'e-resize';
            }
            this._parent._setCursor(cursor);
            
            this._hover = a;
            this.redraw();
        }            
    }
    
    /**
    * handle events
    */
    this.handleEvent = function(e, button, layerX, layerY) {
        if(this._parent.isLocked()) {
            return;
        }
        
        switch(e.type) {
            case 'mouseover':
                this._updateHover(layerX);
                break;
            case 'mouseout':
                this._parent._setCursor('');
                this._hover = null;
                this._parent._toggleMove(false); 
                this._dragging = false;
                break;
            case 'mouseup':
                this._dragging = false;
                this._updateHover(layerX);
                this._parent._toggleMove(false); 
                break;
            case 'mousemove':
                if(!this._source.buffer || !this._source.span) {
                    return;
                }
                
                if(!this._dragging) {
                    this._updateHover(layerX);
                } else {
                    // calculate movement width
                    var x = layerX - this._dragX;
                    var w = this._parent._size[0]/(this._source.buffer.size-1);
                    this._dragM += (x/w);
                    var m = this._dragM|0;
                    this._dragX = layerX;
                    
                    if(m != 0) {
                        this._dragM -= m;
                        var begin = this._source.span[0], end = this._source.span[1];
                                
                        // move beginning
                        if(this._dragging == 2) {
                            begin = mv(begin, m);
                        // move end
                        } else if(this._dragging == 3) {
                            end = mv(end, m);
                        // move whole span    
                        } else {
                            begin = mv(begin, m);
                            end = mv(end, m);
                        }
                        this._parent._adjustSpan(begin, end);
                    }
                }
                break;
            case 'mousedown':
                if(!this._source.buffer || !this._source.span) {
                    return;
                }
                
                this._dragX = layerX;
                if(button == 1) {
                    var a = this._getArea(layerX);
        
                    if(!a) {
                        this._dragging = 1;
                        
                        var i = (layerX/this._parent._size[0])*(this._source.buffer.size-1);
                        var w = this._source.span[1].index - this._source.span[0].index;
                        
                        var s = (i - w/2)|0
                        var e = (i + w/2)|0;
                        
                        var cur = this._source.buffer.begin, begin = null, end = null;
                        while(cur) {
                            if(cur.index == s || (!begin && cur.index > s)) {
                                begin = cur;
                            }
                            if(cur.index == e || (!end && !cur.next)) {
                                end = cur;
                            }
                            cur = cur.next;
                        }
                        
                        if(begin && end) {
                            this._parent._adjustSpan(begin, end);
                        }
                    }
                    this._dragging = a;
                    this._parent._toggleMove(true); 
                }
               
            break;
        }
    }
    
    this.OnSourceChanged = function() {
    }
    
    this.OnDataUpdated = function() {  
        this._detectInterval();
        if(this._interval < ESpans.DAY && this._source.buffer.interval >= ESpans.DAY) {
            this._interval = ESpans.DAY;
        }
        return true;
    }
    
    this._detectInterval = function() {
        var w = 5;
        var span = ((this._source.buffer.end.index-this._source.buffer.begin.index)+this._source.offsetL+this._source.offsetR)*this._source.buffer.interval;
        var intervals = [ESpans.MONTH, ESpans.WEEK, ESpans.DAY, ESpans.HOUR, ESpans.THIRTY_MINUTES, ESpans.FIFTEEN_MINUTES, ESpans.FIVE_MINUTES, ESpans.MINUTE];
        var n = 0;
        for(var i = intervals.length;i>=0;i--) {
            n = span/intervals[i];
            if(this._parent._size[0]/n >= w) {
                this._interval = intervals[i];
                return;
            }
        }
        if(this._source.buffer.interval >= 86400) {
            this._interval = 86400;
        } else {
            this._interval = 60;
        }
    }
    //==========================================================
    // public functions
    //==========================================================
    /**
    * set size
    */
    this.setSize = function(w,h) {
        this._size = [w,h];
    }
    
    /**
    * set position
    */
    this.setPosition = function(x,y) {
        this._position = [x,y];
    }
};
