 /* 取得核心元件檔案：/DJJSLib/CanvasChartSVC/plugin/HPB/HPB.js */ 
(function($,undefined){

//HoldPressBar,壓力支撐水平柱狀圖
window.HPB=function(selector,option){
    return new UI(selector,option);
};

//[private]

//constant
var C={
    //string
    sDvgName:'dvg',
    sDvgValue:'發散',
    sCvgName:'cvg',
    sCvgValue:'聚集',
    //css
    cssHpb:'hbp',
    //head
    cssHead:'hpb_head',
    cssTitle_left:'hpb_tt_left',
    cssTitle_leftL1:'hpb_tt_L1',
    cssTitle_leftL2:'hpb_tt_L2',
    cssBtn_dvg:'hpb_btn_dvg',
    cssBtn_cvg:'hpb_btn_cvg',
    cssTitle_right:'hpb_tt_right',
    //body
    cssBody:'hpb_body',
    cssView:'hpb_view',
    //foot
    cssFoot:'hpb_foot',
    cssLegend_left:'hpb_lg_left',
    cssLegend_right:'hpb_lg_right',
    //canvas
    cssCanvasFoot:'opsFoot'
},
DIV_='<div ',_DIV='</div>',
SPAN='<span>',SPAN_='<span ',_SPAN='</span>';

//utility
var Util={
    ext:$.extend,
    map:$.map,
    each:function(o, fn){
        if(!o) return;
        $.each(o, fn);
    },
    trim:$.trim,
    isA:$.isArray,
    isF:$.isFunction,
    isO:function(o){ return (o && typeof o=='object'); },
    isStr:function(str){ return (typeof str=='string'); },
    isNum:function(v){ return (typeof v=='number'); },
    toAry:function(val){
        if(Util.isA(val)) return val;
        else if(Util.isStr(val)) return Util.trim(val.toString()).split(' ');
        return [val];
    },
    round: function(value, DP) {//@value:Number
      if (!DP) return Math.round(value);
      var dp = Math.pow(10, DP),
          dp2 = Math.pow(10, DP*2);
      //因為相乘會有尾數99999的問題,必須要先round一次,之後再round四捨五入的部分
      return Math.round( Math.round( value*dp2 )/dp )/dp;
    },
    parseQueryStringUpper: function(params){
        var obj={};
        if(typeof params=='object'){
            Util.each(params,function(key,val){
                obj[key.toString().toUpperCase()]=(Util.isStr(val))?Util.trim(val):val;
            });
        } else if(isStr(params)) {
            Util.each(params.split('&'), function(i, param) {
                var pair = Util.trim(param.toString()).split('='),val;
                if(pair.length>1) {
                    obj[Util.trim(pair[0].toUpperCase())] = Util.trim(pair.slice(1).join('='));
                }
            });
        }
        return obj;
    },
    getDP:function(v){
        var a=v.toString().split('.');
        if(a.length==2) return a[1].length;
        return 0;
    },
    get$s:function(selector){
        return (typeof selector=='object' && selector.jquery)?selector:$(selector);
    }
};

//template
var Tmpl={
    div:function(aCss,isEnd){
        aCss=(Util.isA(aCss))?aCss.join(' '):(aCss)?aCss:'';
        isEnd=(isEnd)?'/>':'>';
        var sb=[DIV_,'class="',aCss,'" ',isEnd];
        return sb.join('');
    },
    spanCr:function(color,txt){
        var sb=[SPAN_,'style="color:',color,'">',txt,_SPAN];
        return sb.join('');
    },
    btn:function(aCss,sname,value){
        aCss=(Util.isA(aCss))?aCss.join(' '):(aCss)?aCss:'';
        var sb=['<input type="button" name="',sname,'" value="',value,'" class="',aCss,'" />'];
        return sb.join('');
    },
    main:function(option){
        var me=this,
            opt={
                isCmd:1,//是否要執行[發散/聚集]的功能
                isLegend:1 //是否要有查價功能
            },
            sb=[me.div(C.cssHpb)];
        Util.ext(opt,option);
        //head
        sb.push(me.div(C.cssHead));
        sb.push(me.div(C.cssTitle_left));
        if(opt.isCmd){
            sb.push(me.div(C.cssTitle_leftL1),
                me.btn(C.cssBtn_dvg,C.sDvgName,C.sDvgValue),
                me.btn(C.cssBtn_cvg,C.sCvgName,C.sCvgValue),
            _DIV);
        }
        sb.push(me.div(C.cssTitle_leftL2,1),
            _DIV);//end cssTitle_left
        sb.push(me.div(C.cssTitle_right,1),
        _DIV);//end cssHead
        //body
        sb.push(me.div(C.cssBody),
            me.div(C.cssView,1),
        _DIV);
        //foot
        sb.push(me.div(C.cssFoot));
        if(opt.isLegend){
            sb.push(me.div(C.cssLegend_left,1),me.div(C.cssLegend_right,1));
        }
        sb.push(_DIV,_DIV);
        return sb.join('');
    }
};

//使用者介面,整合template與canvasView
function UI(selector,option){
    var me=this;
    me._$s=Util.get$s(selector);
    me.opt=Util.ext({},me.opt,option);
    me._init();
};
UI.prototype={
    opt:{
        sUnit:'單位:@U',
        sT:'價:',
        sV:'量:',
        isCmd:1,
        isLegend:1
    },

    //data Object
    _L:null,//group of Labels,Array<Labels_List>
    _T:null,//價格
    _V:null,//量
    _$s:null,
    _view:null,

    //color Object: @cr:color, @v:value, @s:legend
    _colorUp:null,//{cr:,v:,s:}
    _colorDn:null,//{cr:,v:,s:}
    _colorPrice:null,//{cr:,v:,s:}
    _colorFirst:null,//{cr:,v:,s:}
    _colorLast:null,//{cr:,v:,s:}

    _priceVol:0,//參考用,如果bcd裡面有傳現價的量,會優先參考bcd的
    _maxLv:0,
    _groupLv:0,
    _step:2,
    _dpT:0,//價格的digit point
    _unit:'',
    _legend:'',
    _delay:100,
    _timer:null,
    _tipIdx:0,
    _tipTick:0,
    _tipCr:'',
    _tipMoveBegin:false,//判定使用者觸發查價的依據
    _draw:function(){
        var me=this, i,
            //tip
            tipT=me._tipTick,
            //壓力支撐
            price = (me._colorPrice)?me._colorPrice.v : NaN,
            priceIdx = -1,
            up = NaN,
            upIdx = -1,
            dn = NaN,
            dnIdx = -1,
            //group
            level=me._groupLv,
            cursor=-1,
            group=1+me._step*level,
            T=[],
            V=[],
            L=[],//labels
            t=0,
            v=0,
            lbl=[],
            dpT = me._dpT;
        //group T & V
        if(group>1){
            for(i=0;i<me._T.length;i++){
                cursor++;
                if(price==me._T[i]) priceIdx = T.length;//假設這份group之後會被add到T內
                t+=me._T[i];
                v+=me._V[i];
                lbl.push(me._T[i]);
                if(i%group==group-1){//adding
                    t=Util.round(t/group,dpT);
                    T.push(t);
                    v = Util.round(v,4);//format累計量
                    V.push(v);//累計量
                    L.push(lbl);
                    //reset
                    t=0;
                    v=0;
                    lbl=[];
                }
            }
            if(cursor%group!==group-1) {
                t=Util.round(t/(1+cursor%group),dpT);
                T.push(t);
                V.push(v);
                L.push(lbl);
            }
        } else {
            T=me._T;
            V=me._V;
            Util.each(T,function(i,tick){
                L.push([tick]);
            });
            if(!isNaN(price)) for(i=0; i<T.length; i++){
                if(price==T[i]){ priceIdx = i; break; }
            }
        }
        //find tipIdx
        for(i=0;i<L.length;i++){
            var a=L[i],L1=a[0],L2=a[a.length-1];
            if(tipT>=L1&&tipT<=L2){ me._tipIdx=i; break; }
        }
        //調整壓力區,支撐區的價格
        if(priceIdx>=0){
            //壓力區,現價上方最大根
            for(i=priceIdx+1; i<V.length; i++){
                if(isNaN(up) || V[i]>up) { up=V[i]; upIdx=i; }
            }
            //支撐區,現價下方最大根
            for(i=0; i<priceIdx; i++){
                if(isNaN(dn) || V[i]>dn ) { dn=V[i]; dnIdx = i; }
            }
            if(me._colorUp && upIdx>=0){
                me._colorUp.v = L[upIdx][0];//拿所有價格的第一個
                if(me._tipCr==me._colorUp.cr) me._tipIdx = upIdx;
            } 
            if(me._colorDn && dnIdx>=0){
                me._colorDn.v = L[dnIdx][0];//拿所有價格的第一個
                if(me._tipCr==me._colorDn.cr) me._tipIdx = dnIdx;
            } 
        }
        //setting
        me._L = L;
        me._view.setBCD(T.join(',')+' '+V.join(','));
        me._tipMoveBegin=false;
        
    },
    _delayDraw:function(){
        var me=this;
        if(me._timer) clearTimeout(me._timer);
        me._timer=setTimeout(function(){
            clearTimeout(me._timer);
            me._draw();
        },me._delay);
    },
    _evt_cvg:function(e){
        var me=this,level=me._groupLv;
        if(me._groupLv+1<me._maxLv){
            me._groupLv++;
        }
        if(level!==me._groupLv) me._delayDraw();
    },
    _evt_dvg:function(e){
        var me=this,level=me._groupLv;
        if(me._groupLv>0){
            me._groupLv--;
        }
        if(level!==me._groupLv) me._delayDraw();
    },
    _color_dele: function(o, lbls){
        var cr, start, end;
        if(Util.isO(o)){
            //判斷是否在範圍內
            start = +lbls[0];
            end = +lbls[lbls.length-1];
            if(o.v>=start && o.v<=end) cr = o.cr;
            //Util.each(lbls,function(i,lbl){ if(o.v==+lbl){ cr=o.cr; return false; } });
        }
        return cr;
    },
    _legend_dele:function(tipIdx, src){
        var me=this,cr,o,sb=[],s,
            vUnit=me._unit,
            lbls=me._L[tipIdx];
        if(!vUnit) vUnit='';
        if(me._tipMoveBegin) me._tipTick=+src.title;
        me._tipMoveBegin=true;
        if(Util.isA(me._L)&&tipIdx<me._L.length){
            var labels = me._L[tipIdx];
            //src.title = (Util.isA(labels))?(labels.length>1)?labels[0]+'~'+labels[labels.length-1]:labels[0]:labels;
            src.title = (labels.length>1)?labels[0]+'~'+labels[labels.length-1]:labels[0];
        }
        sb.push(SPAN,me.opt.sT,src.title,_SPAN,SPAN,me.opt.sV);
        s = sb.join('');
        src.content = Util.map(src.content,function(c){ return s+c+vUnit+_SPAN; });
        src.title = '';
        //crBox, Last > First > Up > Down > Price
        cr = me._color_dele(me._colorLast, lbls) || cr;
        cr = me._color_dele(me._colorFirst, lbls) || cr;
        cr = me._color_dele(me._colorUp, lbls) || cr;
        cr = me._color_dele(me._colorDn, lbls) || cr;
        cr = me._color_dele(me._colorPrice, lbls) || cr;

        me._tipCr = '';
        if(cr) { src.crBox = [cr]; me._tipCr = cr; }
        return src;
    },
    _barColor_dele:function(tipIdx,lineIdx,tick,value){
        var me=this,cr,o,
            lbls=me._L[tipIdx];
        //Last > First > Up > Down > Price
        cr = cr || me._color_dele(me._colorLast, lbls);
        cr = cr || me._color_dele(me._colorFirst, lbls);
        cr = cr || me._color_dele(me._colorUp, lbls);
        cr = cr || me._color_dele(me._colorDn, lbls);
        cr = cr || me._color_dele(me._colorPrice, lbls);
        return cr;
    },
    _after_draw:function(){
        var me=this,a,
            sPx='px',
            sLeft='left',
            sRight='right';
        me._tipMoveBegin=false;
        if(me.opt.isLegend) me._view.moveTip(me._tipIdx);
        a = me._view.getViewLnR();
        if(Util.isA(a)&&a.length==2){
            if(a[0]){
                me._$s.find('.'+C.cssTitle_left).css(sLeft,a[0]+sPx);
            }
            if(a[1]) me._$s.find('.'+C.cssTitle_right).css(sRight,a[1]+sPx);
        }
    },
    _init:function(){//template & view init
        var me=this;
        me._$s.html(Tmpl.main(me.opt));
        me._view = MbChart.FlashView(me._$s.find('.'+C.cssView));
        me._view.deleHorzBarColor(function(){ return me._barColor_dele.apply(me,arguments); });
        me._view.setDrawCall(function(){ me._after_draw.apply(me,arguments); });
        //head
        if(me.opt.isCmd){
            me._$s.find('.'+C.cssBtn_dvg).click(function(e){ me._evt_dvg.apply(me,arguments); });
            me._$s.find('.'+C.cssBtn_cvg).click(function(e){ me._evt_cvg.apply(me,arguments); });
        } else {
            me._$s.find('.'+C.cssTitle_leftL1).hide();
        }
        //foot
        if(me.opt.isLegend){
            me._view.setLegendCall(function(){ return me._legend_dele.apply(me,arguments); });
        } else {
            me._view.tipMoveCall(function(){ return false; });
            me._$s.find('.'+C.cssFoot).hide();
        }
    },
    _addTitleList: function(sb, o){
        if(Util.isO(o)){
            s=o.s.replace('@V',o.v);
            sb.push(Tmpl.spanCr(o.cr,s));
        }
        return sb;
    },
    _setTitle:function(){
        var me=this,s,o,
            sUnit=me.opt.sUnit,
            $ttR=me._$s.find('.'+C.cssTitle_right),
            $ttL2=me._$s.find('.'+C.cssTitle_leftL2),
            sb=[];
        //title left L2
        me._addTitleList(sb, me._colorFirst);
        me._addTitleList(sb, me._colorLast);
        me._addTitleList(sb, me._colorUp);
        me._addTitleList(sb, me._colorDn);
        me._addTitleList(sb, me._colorPrice);
        if(sb.length){
            $ttL2.html(sb.join(''));
        }else {
            $ttL2.empty();
        }
        //unit
        if(me._unit){
            sUnit=sUnit.replace('@U',me._unit);
            $ttR.html(sUnit);
        } else {
            $ttR.empty();
        }
    },
    _setLegend:function(){
        var me=this,
            $lgR=me._$s.find('.'+C.cssLegend_right);
        if(me._legend){
            $lgR.html(me._legend);
        } else {
            $lgR.empty();
        }
    },
    setParams:function(params){
        var me=this,o,a,
            p=Util.parseQueryStringUpper(params),
            FIRST=p['HPB_FIRST'],
            LAST=p['HPB_LAST'],
            UNIT=p['HPB_UNIT'],
            PRICEVALUE = p['HPB_PRICEVALUE'],
            PRICEVOL = p['HPB_PRICEVOLUME'],
            PRICE = p['HPB_PRICE'],
            UP = p['HPB_UP'],
            DOWN = p['HPB_DOWN'],
            WIDTH=p['WIDTH'],
            LEGEND=p['HPB_LEGEND'];
        if(Util.isA(FIRST)){
            a = Util.toAry(FIRST);
            if(a.length==3) me._colorFirst={cr:a[1],v:a[0],s:a[2]};
            me._tipTick=a[0];
        }
        if(Util.isA(LAST)){
            a = Util.toAry(LAST);
            if(a.length==3) me._colorLast={cr:a[1],v:a[0],s:a[2]};
            me._tipTick=a[0];
        }
        if(+PRICEVALUE>0){
            a = (Util.isA(PRICE)) ? Util.toAry(PRICE) : [];
            me._colorPrice = { cr:a[0], v:+PRICEVALUE, s:a[1]};
            me._tipTick=+PRICEVALUE;
        }
        if(+PRICEVOL>0){
            me._priceVol = +PRICEVOL;
        }
        if(Util.isA(UP)){
            a = Util.toAry(UP);
            me._colorUp = { cr:a[0], v:NaN, s:a[1] };
        }
        if(Util.isA(DOWN)){
            a = Util.toAry(DOWN);
            me._colorDn = { cr:a[0], v:NaN, s:a[1] };
        }
        if(WIDTH) me._$s.css('width',parseInt(WIDTH));
        if(Util.isStr(UNIT)) me._unit=UNIT;
        if(Util.isStr(LEGEND)) me._legend=LEGEND;
        //set
        me._setTitle();
        if(me.opt.isLegend) me._setLegend();
        //set view params
        p['TOP']=0;
        p['TYPE']='HorzBar';
        p['DATATYPE']='number';
        if(!me.opt.isLegend) p['NOTIP']=1;
        me._view.setParams(p);
    },
    setBCD:function(bcd){
        var me=this,dp,ary=[], T, V, hasPrice,
        currentPrice = me._colorPrice?+me._colorPrice.v:0;
        me._dpT=0;
        if(Util.isStr(bcd)){
            bcd=bcd.split(' ');
            T = bcd[0].split(',');
            V = bcd[1].split(',');
            Util.each(T,function(i, price){
                if(!hasPrice&&currentPrice==price){
                    hasPrice=1;
                }
                ary.push({ t:+price, v:+V[i] });
            });
            if(currentPrice&&!hasPrice){//如果有現價,但是資料裡面沒有
                ary.push({ t:currentPrice, v:me._priceVol });
            }
            ary.sort(function(a, b){ return a.t-b.t; });
            T=[];
            V=[];
            Util.each(ary, function(i, o){
                dp=Util.getDP(o.t);
                if(dp>me._dpT) me._dpT=dp;
                T.push(o.t);
                V.push(o.v);
            });
            me._T=T;
            me._V=V;
        }
        //find level max
        var g=1,lv=0,limit=20,cnt=0;
        while(Math.floor(me._T.length/g)>2){
            cnt++;
            if(cnt>limit) break;
            lv++;
            g=1+me._step*lv;
        }
        me._maxLv=lv;
        //set bcd
        me._groupLv=0;
        me._draw();
    },
    setGroupBCD: function(bcd){
        var me=this, ary=[], currentPrice, upMax=0, downMax=0, cIdx=NaN, upIdx=NaN, dnIdx=NaN,
            o = me._colorPrice,
            T=[],
            V=[],
            L=[];
        if(o){
            if(!o.value) o.value = o.v;
            currentPrice = o.value;
        }
        bcd = bcd.split(' ');
        Util.each(bcd, function(i, s){
            var a = s.split(',');
            if(a.length==3) ary.push(a);
        });
        ary.sort(function(a,b){ return +a[0]-b[0]; });//價格由小到大
        Util.each(ary, function(i, a){
            var start, end, vol, t;
            if(a.length==3){
                start = +a[0];
                end = +a[1];
                vol = +a[2];
                if(start>0 && end>0 && vol>=0){
                    t = Util.round((start+end)/2,4);
                    if(currentPrice>=start && currentPrice<=end){ o.v = t; cIdx=i; }
                    else if(isNaN(cIdx) && vol>downMax){ downMax = vol; dnIdx=i; }
                    else if(!isNaN(cIdx) && vol>upMax){ upMax = vol; upIdx=i; }
                    T.push(t);
                    V.push(vol);
                    L.push([start,end]);
                }
            }
        });
        if(me._colorDn && !isNaN(dnIdx)) me._colorDn.v = T[dnIdx];
        if(me._colorUp && !isNaN(upIdx)) me._colorUp.v = T[upIdx];
        me._T = T;
        me._V = V;
        me._L = L;
        if(!isNaN(cIdx)) me._tipIdx = cIdx;
        me._view.setBCD(T.join(',')+' '+V.join(','));
        me._tipMoveBegin=false;
    },
    setDrawCall:function(){
        this._view.setDrawCall.apply(this._view,arguments);
    },
    resize:function(){
        var me=this;
        me._view.resize(true);
    }
};


})(jQuery);