// General container
var container = $('.visualization');

// Graph container
var divChart = $('<div>').appendTo(container);

// Settings: ways to group data
var groupings = {
    datetime: {
        century: {
            truncate: function(x) {return x.substr(0, 2)},
            next: function(x) {x = new Date(x); x.setFullYear(x.getFullYear()+100); return x;},                
        },
        decade: {
            truncate: function(x) {return x.substr(0, 3)},
            next: function(x) {x = new Date(x); x.setFullYear(x.getFullYear()+10); return x;},                
        },
        year: {
            truncate: function(x) {return x.substr(0, 4)},
            next: function(x) {x = new Date(x); x.setFullYear(x.getFullYear()+1); return x;},                
        },
        month: {
            truncate: function(x) {return x.substr(0, 7)},
            next: function(x) {x = new Date(x); x.setMonth(x.getMonth()+1); return x;},                
        },
        day: {
            truncate: function(x) {return x.substr(0, 10)},
            next: function(x) {x = new Date(x); x.setDate(x.getDate()+1); return x;},                
        },
    },
    numeric: {
        unit: {
            truncate: function(x) {return Math.round(x)},
            next: function(x) {return x+1;},
        },
    },
};



var graphIt = function(corpusId, getDataCollection, groupingKey, smoothing) {

    divChart.empty();

    // Get data from server
    var dimensions;
    var series = [];
    $.each(getDataCollection, function(i, getData) {
        var responseData;
        $.ajax('/api/corpus/' + corpusId + '/data', {
            async: false,
            success: function(response) {responseData = response;},
            data: getData,
        });
        dimensions = responseData.dimensions;
        // add to the series
        series.push({
            name: '#' + i,
            data: responseData.list,
        });
    });

    var grouping = groupings.datetime[groupingKey];

    // generate associative data
    var associativeData = {};
    for (var s=0; s<series.length; s++) {
        var data = series[s].data;
        for (var d=0; d<data.length; d++) {
            var row = data[d];
            var x = grouping.truncate(row[0]);
            var y = row[1];
            if (!associativeData[x]) {
                associativeData[x] = new Array(series.length);
                for (var i=0; i<series.length; i++) {
                    associativeData[x][i] = 0;
                }
            }
            associativeData[x][s] += y;
        }
    };

    // now, flatten this
    var linearData = [];
    for (var x in associativeData) {
        var row = associativeData[x];
        row.unshift(x);
        linearData.push(row);
    }

    // extrema retrieval & scalar data formatting
    for (var d=0; d<dimensions.length; d++) {
        dimensions[d].extrema = {};
    }
    var keys = {};
    for (var r=0; r<linearData.length; r++) {
        var row = linearData[r];
        for (var d=0; d<dimensions.length; d++) {
            var value = row[d];
            var dimension = dimensions[d];
            switch (dimension.type) {
                case 'datetime':
                    value += '2000-01-01 00:00:00'.substr(value.length);
                    value = new Date(value.replace(' ', 'T') + '.000Z');
                    break;
                case 'numeric':
                    value = +value;
                    break;
            }
            if (dimension.extrema.min == undefined || value < dimension.extrema.min) {
                dimension.extrema.min = value;
            }
            if (dimension.extrema.max == undefined || value > dimension.extrema.max) {
                dimension.extrema.max = value;
            }
            row[d] = value;
        }
        keys[row[0]] = true;
    }

    // interpolation
    var xMin = dimensions[0].extrema.min;
    var xMax = dimensions[0].extrema.max;
    for (var x=xMin; x<xMax; x=grouping.next(x)) {
        if (!keys[x]) {
            // TODO: this below is just WRONG
            var row = [x, 0, 0];
            linearData.push(row);
        }
    }
    linearData.sort(function(row1, row2) {
        return row1[0] > row2[0];
    });


    // do the graph!
    // var labels = [dimensions[0].key];
    // for (var k=0; k<keywordsList.length; k++) {
    //     labels.push(keywordsList[k]);
    // }
    // var _chartObject = new Dygraph(container[0], linearData);
    chartObject = new Dygraph(divChart[0], linearData, {
        // legends
        legend: 'always',
        xlabel: dimensions[0].key,
        ylabel: dimensions[1].key,
        // labels: labels,
        axisLabelColor: 'black',

        // appearance
        fillGraph: true,

        // smoothing
        showRoller: false,
        rollPeriod: +smoothing,

        // dimensions
        width: container.width(),
        height: container.width() / 3,
    });

    // console.log(associativeData);
    // console.log(linearData);
    // console.log(dimensions);

};



var ulDatasets = $('<ul>').prependTo(container);
var inputSmoothing = $('<input>').prependTo(container).blur(function() {
    var val = $(this).val();
    if (isNaN(val)) {
        val = 1;
    }
    val = Math.round(val);
    if (val < 1) {
        val = 1;
    }
    $(this).val(val);
}).val(1);
container.prepend(' with a smoothing of ');
var selectGrouping = $('<select>').prependTo(container);
container.prepend(', view by publication ');
var selectCorpus = $('<select>').prependTo(container);
container.prepend(', corpus ');
var selectProject = $('<select>').prependTo(container);
container.prepend('In the project ');

var hyperdataCollection;
var corpusId;

// how shall we group the data?
$.each(groupings.datetime, function(text, grouping) {
    $('<option>').text(text).val(text).appendTo(selectGrouping);
});
selectGrouping.val('year');


var emWait = $('<em>').text('Loading, please wait...').insertAfter(ulDatasets);
var buttonAddDataset = $('<button>').text('Add a dataset').insertAfter(ulDatasets).hide();
var buttonView = $('<button>').text('Graph it!').click(function(e) {
    var getDataCollection = [];
    ulDatasets.children().filter('li').each(function(i, liDataset) {
        liDataset = $(liDataset);
        var getData = {
            mesured:      liDataset.find('*[name]').first().val(),
            parameters:   ['hyperdata.publication_date'],
            filters:      [],
            format:       'json',
        };
        liDataset.find('li *[name]:visible').each(function(i, field){
            field = $(field);
            var filter = field.attr('name') + '.' + field.val();
            getData.filters.push(filter);
        });
        getDataCollection.push(getData);
    });
    graphIt(
        selectCorpus.val(),
        getDataCollection,
        selectGrouping.val(),
        inputSmoothing.val()
    );
}).insertAfter(ulDatasets).hide();


// Load hyperdata
selectCorpus.change(function() {
    corpusId = selectCorpus.val();
    emWait.show();
    ulDatasets.empty();
    $.get('/api/corpus/' + corpusId + '/hyperdata', function(collection) {
        // Unleash the power of the filter!
        emWait.hide();
        buttonAddDataset.show();
        buttonView.show();
        hyperdataCollection = collection;
        buttonAddDataset.click();
    });
});

// Load corpora
selectProject.change(function() {
    var projectId = selectProject.val();
    selectCorpus.empty();
    $.get('/api/nodes', {type:'Corpus', parent:projectId}, function(collection) {
        $.each(collection, function(i, node) {
            $('<option>').val(node.id).text(node.text).appendTo(selectCorpus);
        });
        selectCorpus.change();
    });
});

// Load projects
$.get('/api/nodes', {type:'Project'}, function(collection) {
    selectProject.empty();
    for (var i=0; i<collection.length; i++) {
        var node = collection[i];
        $('<option>').val(node.id).text(node.text).appendTo(selectProject);
    }
    selectProject.change();
});

// Add a dataset
buttonAddDataset.click(function() {

    var liDataset = $('<li>').appendTo(ulDatasets);
    // Can we remove this please?
    $('<button>').appendTo(liDataset).text('x').click(function() {
        liDataset.remove();
    });
    // What do we count?
    liDataset.append(' Count ');
    var selectCounted = $('<select>')
        .attr('name', 'mesured')
        .appendTo(liDataset);
    $('<option>')
        .text('documents')
        .val('documents.count')
        .appendTo(selectCounted);
    $('<option>')
        .text('ngrams')
        .val('ngrams.count')
        .appendTo(selectCounted);
    liDataset.append(' ');
    var buttonFilter = $('<button>')
        .text('(add a filter)')
        .appendTo(liDataset);
    // Add a filter when asked
    var ulFilters = $('<ul>').appendTo(liDataset);
    var addFilter = function(hyperdataCollection) {
        var liFilter = $('<li>').appendTo(ulFilters);
        liFilter.append('...where the ');
        // Type of filter: ngrams
        var selectType = $('<select>').appendTo(liFilter);
        $('<option>').text('ngrams').appendTo(selectType);
        var spanNgrams = $('<span>').appendTo(liFilter).hide();
        spanNgrams.append(' contain ');
        var inputNgrams = $('<input>')
            .attr('name', 'ngrams.in')
            .appendTo(spanNgrams);
        spanNgrams.append(' (comma-separated ngrams)')
        // Type of filter: hyperdata
        $('<option>').text('hyperdata').appendTo(selectType);
        var spanHyperdata = $('<span>').appendTo(liFilter).hide();
        var selectHyperdata = $('<select>').appendTo(spanHyperdata);
        var spanHyperdataValue = $('<span>').appendTo(spanHyperdata);
        $.each(hyperdataCollection, function(i, hyperdata) {
            $('<option>')
                .appendTo(selectHyperdata)
                .text(hyperdata.text)
                .data(hyperdata);
        });
        // How do we present the hyperdata?
        selectHyperdata.change(function() {
            var hyperdata = selectHyperdata.find(':selected').data();
            spanHyperdataValue.empty();
            if (hyperdata.type == 'datetime') {
                spanHyperdataValue.append(' is between ');
                $('<input>').appendTo(spanHyperdataValue)
                    .attr('name', 'hyperdata.' + hyperdata.key + '.gt')
                    .datepicker({dateFormat: 'yy-mm-dd'})
                    .blur(function() {
                        var input = $(this);
                        var date = input.val();
                        date += '2000-01-01'.substr(date.length);
                        input.val(date);
                    });
                spanHyperdataValue.append(' and ');
                $('<input>').appendTo(spanHyperdataValue)
                    .attr('name', 'hyperdata.' + hyperdata.key + '.lt')
                    .datepicker({dateFormat: 'yy-mm-dd'})
                    .blur(function() {
                        var input = $(this);
                        var date = input.val();
                        date += '2000-01-01'.substr(date.length);
                        input.val(date);
                    });
            } else if (hyperdata.values) {
                $('<span>').text(' is ').appendTo(spanHyperdataValue);
                var selectHyperdataValue = $('<select>')
                    .attr('name', 'hyperdata.' + hyperdata.key + '.eq')
                    .appendTo(spanHyperdataValue);
                $.each(hyperdata.values, function(i, value) {
                    $('<option>')
                        .text(value)
                        .appendTo(selectHyperdataValue);
                });
                selectHyperdataValue.change().focus();
            } else {
                spanHyperdataValue.append(' contains ');
                $('<input>')
                    .attr('name', 'hyperdata.' + hyperdata.key + '.contains')
                    .appendTo(spanHyperdataValue)
                    .focus();
            }
        }).change();
        // Ngram or hyperdata?
        selectType.change(function() {
            var spans = liFilter.children().filter('span').hide();
            switch (selectType.val()) {
                case 'ngrams':
                    spanNgrams.show().find('input').focus();
                    break;
                case 'hyperdata':
                    spanHyperdata.show();
                    break;
            }
        }).change();
    };

    buttonFilter.click(function(e) {
        addFilter(hyperdataCollection);
    });
});




/*
 $('.tree').jstree({
     'core' : {
         'data' : {
             'url' : function(node) {
                 var url = '/api/nodes?' + ((node.id === '#')
                     ? 'type=Project'
                     : ('parent=' + node.id)
                 );
                 console.log(url);
                 return url;
             },
         },
     },
     "plugins" : ["types"],
     "types" : {
         "#" : {
           "max_children" : 1, 
           "max_depth" : 4, 
           "valid_children" : ["root"]
         },
         "Project" : {
           "icon" : "http://www.jstree.com/static/3.0.8/assets/images/tree_icon.png",
           "valid_children" : ["default"]
         },
         "Corpus" : {
           "valid_children" : ["default","file"]
         },
         "Document" : {
           "icon" : "glyphicon glyphicon-file",
           "valid_children" : []
         }
   },
 });
*/
var graph = $('.graph-it').graphIt(640, 480);