var directives = angular.module('picard.directives', []);
directives.directive('fadey', function () {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            var duration = 500;
            element = jQuery(element);
            element.hide();
            element.fadeIn(duration);

            scope.destroy = function (complete) {
                element.fadeOut(duration, function () {
                    if (complete) {
                        complete.apply(scope);
                    }
                });
            };

        }
    };
});

directives.directive('ngGrowl', ['growl', '$parse', function (growl, $parse) {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            var options = {
                dismiss_function: attrs["toClose"]
            };
            growl.show(element, scope, options);
        }
    };
}]);

directives.directive('aceEditor', ['$parse', function ($parse) {
    var ACE_EDITOR_CLASS = 'ace-editor';

    function loadAceEditor(element, mode) {
        var editor = ace.edit(element);
        editor.session.setMode("ace/mode/" + mode);
        return editor;
    }


    function valid(editor) {
        return (Object.keys(editor.getSession().getAnnotations()).length == 0);
    }

    return {
        restrict: 'A',
        require: '?ngModel',
        transclude: true,
        template: '<div class="transcluded" ng-transclude></div><div class="' + ACE_EDITOR_CLASS + '"></div>',
        link: function (scope, element, attrs, ngModel) {
            var language = attrs['aceEditor'] || 'markdown',
                editorElement = element.find('.' + ACE_EDITOR_CLASS)[0],
                editor = loadAceEditor(editorElement, language);

            scope['ace'] = editor;
            editor.setTheme('ace/theme/chrome');
            $(editorElement).css("height", "250px");
            $(editorElement).css("border", "1px solid #ddd");
            $(editorElement).css("border-radius", "4px");

            if (!ngModel) return; // do nothing if no ngModel

            var getter = $parse(attrs['ngModel']);
            var setter = getter.assign;

            editor.getSession().setValue(getter(scope));
            scope.$watch(attrs['ngModel'], function (newValue) {
                if (editor.getValue() !== newValue) {
                    editor.getSession().setValue(newValue);
                }
            });

            editor.getSession().on('change', function () {
                if (valid(editor)) {
//                    ngModel.$setViewValue(editor.getValue());
                    setter(scope, editor.getValue());
                    scope.$apply();
                }
            });
        }
    };
}]);

directives.directive('chosen', ['$parse', function ($parse) {
    var linker = function (scope, element, attrs) {
        var model = attrs['ngModel'],
            list = attrs['chosen'],
            createFunction = attrs['createFunction'],
            options = {};

        if (typeof createFunction !== 'undefined') {
            options['create_option'] = function (data) {
                var fn = $parse(attrs['createFunction'] + '("' + data + '")');
                scope.$apply(function () {
                    fn(scope);
                });
            };
        }
        scope.$watch(list, function () {
            element.trigger('liszt:updated');
        }, true);

        /* Added this in so that you could preselect items */
        scope.$watch(model, function () {
            element.trigger("liszt:updated");
        }, true);

        element.chosen(options);
    };

    return {
        restrict: 'A',
        link: linker
    };
}]);

directives.directive('keypress', [function () {
    return function (scope, element, attrs) {
        var attribute = scope.$eval(attrs.keypress || '{}');
        for (var k in attribute) {
            (function (k) {
                Mousetrap.bind(k, function () {
                    return attribute[k](scope, element);
                });
            })(k);
        }
    };
}]);

directives.directive('onReturn', function () {
    return function (scope, elm, attrs) {
        elm.bind("keypress", function (event) {
            if (event.which === 13) {
                scope.$apply(attrs.onReturn);
            }
        });
    };
});

directives.directive('tanSse', ['$parse', function ($parse) {
    return{
        restrict: 'EM',
        link: function ($scope, element, attrs) {
            var url = attrs.url,
                subScope = $scope.$new(),
                statusSetter = $parse($scope.status).assign;
            $scope.$on('$destroy', function () {
                subScope.close();
                subScope.$destroy();
            });

            subScope.source = new EventSource(url);
            subScope.source.onopen = function (e) {
                statusSetter($scope, 'Open');
                subScope.$emit('sse:open');
            };
            subScope.source.onmessage = function (e) {
                var data = JSON.parse(e.data);
                subScope.$emit('sse:message', data);
            };
            subScope.source.onerror = function (e) {
                statusSetter($scope, 'Closed');
                subScope.$emit('sse:error');
            };
            source.addEventListener('message', function (e) {
                console.log(e.data);
            }, false);
        }
    };
}]);

directives.directive('tanClick', ['$parse', '$timeout', function ($parse, $timeout) {
    return {
        compile: function ($element, attr) {
            var fn = $parse(attr.tanClick);
            return function (scope, element, attr) {
                element.on('click', function (event) {
                    scope.$apply(function () {
                        var disabled = attr.ngDisabled ? $parse(attr.ngDisabled) : angular.noop;
                        attr.$set('disabled', true);
                        var v = fn(scope, {$event: event}) || angular.noop;
                        if (v && v.then) {
                            v.finally(function () {
                                attr.$set('disabled', !!disabled(scope) || false);
                            });
                        } else {
                            $timeout(function () {
                                attr.$set('disabled', !!disabled(scope) || false);
                            }, 5000);
                        }
                    });
                });
            };
        }
    };
}]);

directives.directive('chartDiscreteBar', ['$parse', function ($parse) {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            nv.addGraph(function () {
                var chart = nv.models.discreteBarChart()
                    .x(function (d) {return d.label;})
                    .y(function (d) {return d.value;})
                    .staggerLabels(true)
                    .tooltips(false)
                    .showValues(true);

                var data = $parse(attrs.chartDiscreteBar)(scope);
                d3.select('#' + attrs.id + ' svg')
                    .datum(data)
                    .transition().duration(500)
                    .call(chart);

                nv.utils.windowResize(chart.update);

                return chart;
            });
        }
    };
}]);

directives.directive('chartMultiBar', ['$parse', function ($parse) {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            nv.addGraph(function () {
                var chart = nv.models.multiBarChart();

                var data = $parse(attrs.chartMultiBar)(scope);
                d3.select('#' + attrs.id + ' svg')
                    .datum(data)
                    .transition().duration(500)
                    .call(chart);

                nv.utils.windowResize(chart.update);

                return chart;
            });
        }
    };
}]);

directives.directive('chartLine', ['$parse', function ($parse) {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            nv.addGraph(function () {
                var chart = nv.models.lineChart();
                chart.xAxis.axisLabel('Date').tickFormat(function (d) {
                    return d3.time.format('%b %d')(new Date(d));
                });
                var data = $parse(attrs.chartLine)(scope);
                d3.select('#' + attrs.id + ' svg')
                    .datum(data)
                    .transition().duration(500)
                    .call(chart);

                nv.utils.windowResize(chart.update);

                return chart;
            });
        }
    };
}]);

directives.directive('chartPie', ['$parse', function ($parse) {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            var chart;
            scope.$watch(attrs.chartPie, function (data) {
                if (!angular.isUndefined(chart)) {
                    d3.select('#' + attrs.id + ' svg')
                        .datum(data)
                        .transition().duration(1200)
                        .call(chart);
                    return chart;
                }

                nv.addGraph(function () {
                    chart = nv.models.pieChart()
                        .x(function (d) {return d.label;})
                        .y(function (d) {return d.value;})
                        .showLabels(true);
//                    var data = $parse(attrs.chartPie)(scope);
                    d3.select('#' + attrs.id + ' svg')
                        .datum(data)
                        .transition().duration(1200)
                        .call(chart);

                    nv.utils.windowResize(chart.update);

                    return chart;
                });
            });
        }
    };
}]);

directives.directive('chartLinePlusBar', ['$parse', function ($parse) {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            var chart;
            scope.$watch(attrs.chartLinePlusBar, function (data) {
                if (!angular.isUndefined(chart)) {
                    d3.select('#' + attrs.id + ' svg')
                        .datum(data)
                        .transition().duration(500)
                        .call(chart);
                    return chart;
                }
                nv.addGraph(function () {
                    chart = nv.models.linePlusBarChart()
                        .x(function (d) {return d.label;})
                        .y(function (d) {return d.value;});
                    chart.xAxis.axisLabel('Date').tickFormat(function (d) {
                        return d3.time.format('%b %d')(new Date(d));
                    });
                    chart.bars.forceY([0]);
//                    var data = $parse(attrs.chartLinePlusBar)(scope);
                    d3.select('#' + attrs.id + ' svg')
                        .datum(data)
                        .transition().duration(500)
                        .call(chart);

                    nv.utils.windowResize(chart.update);

                    return chart;
                });
            });
        }
    };
}]);

