/* *********************************************************************
   rrdGraphCtrl - control panel for rrdGraphPng charts

   Copyright:
     2015 OETIKER+PARTNER AG http://www.oetiker.ch

   License:
     Gnu GPL Version 2

   Version: #VERSION#, #DATE#

   Authors:
     * Tobias Oetiker (oetiker)

* **********************************************************************/

/**
 * The rrdGraphCtrl control turns attaches to a rrdGraphPng object and lets
 * select start time and range of the graphs.
 */

qxWeb.define('rrdGraphCtrl',{
    extend: qxWeb.$$qx.ui.website.Widget,
    statics: {
        _config : {
            timeRanges: {
                "Last 60 Minutes":  { order: 0, len: 60, end: 'minute' },
                "Last 24 Hours":    { order: 1, len: 24, end: 'hour' },
                "Last 7 Days":      { order: 2, len: 7,  end: 'day' },
                "Last 31 Days":     { order: 3, len: 31, end: 'day' },
                "Last 12 Months":   { order: 4, len: 12, end: 'month' },
                "Today":            { order: 5, len: 1,  end: 'day' },
                "This Week":        { order: 6, len: 1,  end: 'week' },
                "This Month":       { order: 7, len: 1,  end: 'month' },
                "This Year":        { order: 8, len: 1,  end: 'year' },
                "60 Minutes":       { order: 9, len: 3600},
                "12 Hours":         { order: 10, len: 12*3600},
                "24 Hours":         { order: 11, len: 24*3600},
                "7 Days":           { order: 12, len: 7*24*3600},
                "4 Weeks":          { order: 13, len: 4*7*24*3600},
                "12 Months":        { order: 13, len: 365*24*3600}
            },
            initialTimeRange: 'Today',
            rangeMatchPrecision: 0.05,
            showTimeBox: true,
            resetTimeOnDateChange: false,
            switchToCustomOnStartChange: true,
            momentTz: null
        },
        rrdGraphCtrl: function(rrdGraphPng,cfg){
            var ctrl = new rrdGraphCtrl(this);

            ctrl.init(rrdGraphPng,cfg);
            return ctrl;
        }
    },

    construct : function(selector, context) {
        this.base(arguments, selector, context);
    },

    members : {
        init: function(rrdGraphPng,cfg){
            if (!this.base(arguments)) {
                return false;
            };
            if (cfg){
                for (var key in cfg){
                    this.setConfig(key,cfg[key])
                }
            }
            this._forEachElementWrapped(function(div,idx) {
                div.setProperty('rrdGraphPng',rrdGraphPng);
                div.__addDatePicker();
                div.__addRangePicker();
            });
            return true;
        },
        rebind: function(rrdGraphPng){
            this._forEachElementWrapped(function(div,idx) {
                div.setProperty('rrdGraphPng',rrdGraphPng);
                div.emit('rebindRrdGraphPng');
                rrdGraphPng.setStartRange(div.getProperty('start'),div.getProperty('range'));
            });
        },
        __addDatePicker: function(){
            var rrdGraphPng = this.getProperty('rrdGraphPng');
            var start = qxWeb.create('<input  type="text"/>');
            start.appendTo(this);
            var picker = start.datepicker().setConfig('format', function(date) {
                return date.toDateString();
            });
            var calendar = picker.getCalendar();
            calendar.setValue(new Date());

            var timeBox = qxWeb.create('<input class="qx-datepicker" size="10" type="text" value="00:00:00" />');
            if (! this.getConfig('showTimeBox')){
                timeBox.hide();
            }
            timeBox.appendTo(this);
            var that = this;
            var propagateDateTime = function(){
                var time = timeBox.getValue().split(':');
                [0,1,2].forEach(function(i){
                    time[i] = parseInt(time[i]);
                    if (isNaN(time[i])){
                        time[i] = 0;
                    }
                });
                timeBox.setValue([0,1,2].map(function(i){return ('0'+time[i]).slice(-2)}).join(':'));
                var start;
                var momentTz = that.getConfig('momentTz');
                if (momentTz){
                    start = parseInt(moment.tz(moment(calendar.getValue()).format("YYYY-MM-DD"),momentTz).format('X'));
                }
                else {
                    start = calendar.getValue().getTime()/1000
                }
                start += time[0]*3600+time[1]*60+time[2];
                rrdGraphPng.setStart(start);
                that.setProperty('start',start);
                that.emit('syncRrdGraphCtrlRange',start);
            };

            var blockDate = false;
            var onChangeValueCal = function(){
                if (blockDate){
                    blockDate = false;
                    return;
                }
                if (this.getConfig('resetTimeOnDateChange')){
                    timeBox.setValue('00:00:00');
                }
                propagateDateTime();
            };
            calendar.on('changeValue',onChangeValueCal,this);

            var blockTime = false;
            timeBox.on('change',propagateDateTime,this);
            var onKeyPressTbox = function(e){
                if (e.key == "Enter") {
                    propagateDateTime();
                }
            };
            timeBox.on('keypress',onKeyPressTbox,this);

            var lastDate;
            var that = this;
            var onChangeStartRange = function(e){
                var start = e.start;
                var range = e.range;
                if (isNaN(start)) return;
                var momentTz = this.getConfig('momentTz');
                var date;

                if (momentTz){
                    date = new Date(moment.tz(start * 1000,momentTz).format("YYYY/MM/DD HH:mm:ss"));
                }
                else {
                    date = new Date(start * 1000);
                }
                if (date != lastDate){
                    blockDate = true;
                    calendar.setValue(new Date(date.getTime()));
                    var newTime = date.getHours()+':'+('0'+date.getMinutes()).slice(-2)+':'+('0'+date.getSeconds()).slice(-2);
                    timeBox.setValue(newTime);
                    lastDate = date;
                }
                that.setProperty('start',start);
            };
            rrdGraphPng.eq(0).on('changeStartRange',onChangeStartRange,this);

            var onRebindRrdGraphPng = function(){
                rrdGraphPng.eq(0).off('changeStartRange',onChangeStartRange,this);
                rrdGraphPng = this.getProperty('rrdGraphPng');
                rrdGraphPng.eq(0).on('changeStartRange',onChangeStartRange,this);
            };
            this.on('rebindRrdGraphPng',onRebindRrdGraphPng,this);

            this.once('qxRrdDispose',function(){
                this.off('rebindRrdGraphPng',onRebindRrdGraphPng,this);
                rrdGraphPng.eq(0).off('changeStartRange',onChangeStartRange,this);
                timeBox.off('change',propagateDateTime,this);
                timeBox.off('keypress',onKeyPressTbox,this);
                timeBox.remove();
                calendar.off('changeValue',onChangeValueCal,this);
                picker.dispose();
                picker.remove();
            },this);
        },
        __getRangeMoment: function(item){
            var l = item.len;
            var end = moment().tz(this.getConfig('momentTz'));
            if (item.end) {
                end.endOf(item.end).add(1,'second');
            }
            var start = end.clone().subtract(item.len,item.end ? item.end : 'second');
            return {
              end: end.unix(),
              range: end.unix() - start.unix()
            };
        },
        __getRange: function(item){
            if (this.getConfig('momentTz')){
              return this.__getRangeMoment(item)
            }
            var d = item.end;
            var l = item.len;
            var now = new Date;
            var start;
            now.setMilliseconds(0);
            now.setSeconds(0);
            if (d == 'minute'){
                now.setMinutes(now.getMinutes()+1)
                start = new Date(now.getTime());
                start.setMinutes(start.getMinutes()-l);
            }
            else {
                now.setMinutes(0);
                if (d == 'hour'){
                    now.setHours(now.getHours()+1)
                    start = new Date(now.getTime());
                    start.setHours(start.getHours()-l);
                }
                else {
                    now.setHours(0);
                    if (d == 'day'){
                        now.setDate(now.getDate()+1)
                        start = new Date(now.getTime());
                        start.setDate(start.getDate()-l);
                    }
                    else {
                        if (d == 'week'){
                            now.setDate(now.getDate()-now.getDay()+8);
                            start = new Date(now.getTime());
                            start.setDate(start.getDate()-l*7);
                        }
                        else {
                            now.setDate(1);
                            if (d == 'month'){
                                now.setMonth(now.getMonth()+1);
                                start = new Date(now.getTime());
                                start.setMonth(start.getMonth()-l);
                            }
                            else {
                                now.setMonth(0);
                                if (d == 'year'){
                                    now.setYear(now.getFullYear()+1);
                                    start = new Date(now.getTime());
                                    start.setYear(start.getFullYear()-l);
                                }
                            }
                        }
                    }
                }
            }
            var end = now.getTime()/1000;
            return {
                range: Math.round(end-start.getTime()/1000),
                end: Math.round(end)
            };
        },

        __addRangePicker: function(){
            var rrdGraphPng = this.getProperty('rrdGraphPng');

            var rangeSelector = qxWeb.create('<select class="qx-widget qx-selectbox"/>');
            this.setProperty('rangeSelector',rangeSelector);
            rangeSelector.appendTo(this);
            var keys = [];
            var tr =  this.getConfig('timeRanges');
            for (var prop in tr){
                keys.push(prop);
            }
            keys.sort(function(a,b){ return tr[a].order - tr[b].order })
            .forEach(function(x){
                rangeSelector.append(
                    qxWeb.create('<option/>')
                    .setProperties({
                        value: x,
                        text: x
                    })
                );
            });
            var custom = qxWeb.create('<option value="0">Custom</option>');
            rangeSelector.append(custom);
            var blockStart = false;
            var that = this;
            var onRangeSelectorChange = function(e){
                var item = tr[rangeSelector.getValue()];
                if (item){
                    if (item.end){
                        var info = that.__getRange(item);
                        if (info){
                            var range = info.range;
                            var start = info.end - range;
                            that.setProperty('range',range);
                            rrdGraphPng.setStartRange(start,range);
                            rrdGraphPng.emit('changeStartRange',{start:start,range:null});
                        }
                        else {
                            console.log("unknown end type "+item.end);
                            return;
                        }
                    }
                    else {
                        rrdGraphPng.setStartRange(rrdGraphPng.getStart(),item.len);
                        that.setProperty('range',item.len);
                    }
                }
            };
            rangeSelector.setValue(this.getConfig('initialTimeRange'));
            rangeSelector.on('change',onRangeSelectorChange,this);

            onRangeSelectorChange();

            var precision = this.getConfig('rangeMatchPrecision');
            var that = this;
            var onChangeStartRange = function(e){
                var start = e.start;
                var range = e.range;
                if (range == null) return;
                that.setProperty('range',range);
                for (var key in tr){
                    var item = tr[key];
                    if (item.end){
                        var info = that.__getRange(item);
                        if (info){
                            var newRange = info.range;
                            var newStart = info.end - range;
                            if (Math.abs(newRange - range) / range <= precision
                                && Math.abs(newStart - start) / range <= precision ) {
                                rangeSelector.setValue(key);
                                return;
                            }
                        }
                        else {
                            console.log("unknown end type "+item.end);
                            break;
                        }
                    }
                    else {
                        var newRange = item.len;
                        if (Math.abs(newRange - range) / range < 0.05){
                            rangeSelector.setValue(key);
                            return;
                        }
                    }
                }
                rangeSelector.setValue("0");
            };

            var onSyncRange = function(start){
                onChangeStartRange({start:start,range:this.getProperty('range')});
            };

            this.on('syncRrdGraphCtrlRange',onSyncRange,this);


            rrdGraphPng.eq(0).on('changeStartRange',onChangeStartRange,this);

            var onRebindRrdGraphPng =  function(){
                rrdGraphPng.eq(0).off('changeStartRange',onChangeStartRange,this);
                rrdGraphPng = this.getProperty('rrdGraphPng');
                rrdGraphPng.eq(0).on('changeStartRange',onChangeStartRange,this);
                rrdGraphPng.setRange(this.getProperty('range'));
            };
            this.on('rebindRrdGraphPng',onRebindRrdGraphPng,this);

            this.once('qxRrdDispose',function(){
                this.off('rebindRrdGraphPng',onRebindRrdGraphPng,this);
                this.off('syncRrdGraphCtrlRange',onSyncRange,this);
                rangeSelector.off('change',onRangeChange,this);
                rrdGraphPng.eq(0).off('changeStartRange',onChangeStartRange,this);
                rangeSelector.remove();
            },this);
        },
        dispose: function(){
            this._forEachElementWrapped(function(ctrl) {
                ctrl.emit('qxRrdDispose');
            });
            return this.base(arguments);
        }
    },

    defer : function(statics) {
        qxWeb.$attach({rrdGraphCtrl : statics.rrdGraphCtrl});
    },

});