'use strict';

var overlord_directive = angular.module('overlord.directive', []);
overlord_directive.directive('ngAutocomplete', ['$q', '$parse', 'DeepLabel', function ($q, $parse, DeepLabel) {
    return {
        restrict: 'A',
        link: function (scope, element, attrs, ngModel) {
            var mappedCache = {},
                labels = [],
                mapped = {},
                deepLabel = DeepLabel,
                count = 20;
            element.typeahead({
                source: function (query, process) {
                    var Entity = angular.injector(['overlord.service']).get(attrs.resource),
                        options = {term: query, count: count};
                    Entity.autocomplete(options, function (result) {
                        labels = [];
                        mapped = {};
                        $.each(result, function (i, item) {
                            var label = deepLabel(item, attrs.label);
                            mapped[label] = item
                            labels.push(label)
                        })
                        mappedCache[query] = mapped;
                        process(labels)
                    });
                },
                minLength: 1,
                items: count,
                matcher: function (item) {
                    return true;
                },
                updater: function (item) {
                    var model = $parse(attrs.model);
                    var modelSetter = model.assign;
                    modelSetter(scope, mapped[item]);
                    scope.$apply();
                    return item;
                }
            });
        }
    };
}]);

overlord_directive.directive('datepicker', ['$parse', function ($parse) {
    return {
        restrict: 'E',
        replace: true,
        transclude: true,
        template: '<input type="text" />',
        link: function (scope, element, attrs) {
            element.datepicker({
                dateFormat: 'dd-M-yy',
                showOtherMonths: true,
                selectOtherMonths: true,
                onSelect: function (dateText, inst) {
                    var model = $parse(attrs.model);
                    var modelSetter = model.assign;
                    modelSetter(scope, dateText);
                    scope.$apply();
                }
            });
        }
    };
}]);

overlord_directive.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);
                    }
                });
            };

        }
    };
});

overlord_directive.directive('ngConfirm', ['modal', '$parse', function (modal, $parse) {
    return {
        restrict: 'A',
        link: function postLink(scope, element, attrs) {
            // Could have custom or boostrap modal options here
            var options = {};
            if (typeof attrs.url !== 'undefined') {
                element.bind("click", function () {
                    if (typeof attrs.before !== 'undefined') {
                        var fn = $parse(attrs.before);
                        scope.$apply(function () {
                            fn(scope);
                        });
                    }
                    modal.template(attrs.url, attrs.onAction, attrs.onCancel, scope, options);
                });
            } else {
                element.bind("click", function () {
                    var actionButton = {text: attrs["actionButtonText"], click: attrs["actionFunction"], class: attrs['class']};
                    var cancelButton = {text: attrs["cancelButtonText"], click: attrs["cancelFunction"]};
                    modal.confirm(attrs["title"], attrs["actionText"], actionButton, cancelButton, scope, options);
                });
            }
        }
    };

}]);

(function (angular) {
    /*
     * Defines the ng:if tag. This is useful if jquery mobile does not allow
     * an ng-switch element in the dom, e.g. between ul and li.
     */
    var ngIfDirective = {
        transclude: 'element',
        priority: 1000,
        terminal: true,
        compile: function (element, attr, transclude) {
            return function (scope, iterStartElement, attr) {
                iterStartElement[0].doNotMove = true;
                var expression = attr.ngmIf;
                var lastElement;
                var lastScope;
                scope.$watch(expression, function (newValue) {
                    if (lastElement) {
                        lastElement.remove();
                        lastElement = null;
                    }
                    lastScope && lastScope.$destroy();
                    if (newValue) {
                        lastScope = scope.$new();
                        transclude(lastScope, function (clone) {
                            lastElement = clone;
                            iterStartElement.after(clone);
                        });
                    }
                    // Note: need to be parent() as jquery cannot trigger events on comments
                    // (angular creates a comment node when using transclusion, as ng-repeat does).
                    iterStartElement.parent().trigger("$childrenChanged");
                });
            };
        }
    };
    overlord_directive.directive('ngmIf', function () {
        return ngIfDirective;
    });
})(angular);


overlord_directive.directive('journal-edit', function () {
    return {
        restrict: 'A',
        replace: true,
        transclude: true,
        templateUrl: '/partial/journal-modal.html',
        link: function (scope, element, attrs) {
            element.bind("click", function () {
                var actionButton = {text: attrs["actionButtonText"], click: attrs["actionFunction"], class: attrs['class']};
                var cancelButton = {text: attrs["cancelButtonText"], click: attrs["cancelFunction"]};
                modal.confirm(attrs["title"], attrs["actionText"], actionButton, cancelButton, scope, options);
            });
        }
    };
});

overlord_directive.directive('ngEditRepeat', ['modal', '$parse', function (modal, $parse) {
    return {
        restrict: 'E',
        template: '' +
            '<div class="btn-group">' +
            '    <a class="btn btn-danger" ng-click="removeJournal(journal)"><i class="icon-trash icon-white"></i> Delete</a>' +
            '    <a class="btn btn-danger dropdown-toggle" data-toggle="dropdown" href="#"><span class="caret"></span></a>' +
            '    <ul class="dropdown-menu">' +
            '        <li><a ng-confirm url="/partial/journal-modal.html" before="toggleEdit(journal)" on-action="toggleEdit(journal, true)" on-cancel="toggleEdit(journal, false)"><i class="icon-pencil"></i> Edit</a></li>' +
            '    </ul>' +
            '</div>',

        link: function postLink(scope, element, attrs) {
            // Could have custom or boostrap modal options here
            var options = {};
            if (typeof attrs.url !== 'undefined') {
                element.bind("click", function () {
                    if (typeof attrs.before !== 'undefined') {
                        var fn = $parse(attrs.before);
                        scope.$apply(function () {
                            fn(scope);
                        });
                    }
                    modal.template(attrs.url, attrs.onAction, attrs.onCancel, scope, options);
                });
            } else {
                element.bind("click", function () {
                    var actionButton = {text: attrs["actionButtonText"], click: attrs["actionFunction"], class: attrs['class']};
                    var cancelButton = {text: attrs["cancelButtonText"], click: attrs["cancelFunction"]};
                    modal.confirm(attrs["title"], attrs["actionText"], actionButton, cancelButton, scope, options);
                });
            }
        }
    };
}]);

overlord_directive.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);
        }
    };
}]);


overlord_directive.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)) {
                    setter(scope, editor.getValue());
                    scope.$apply();
                }
            });
        }
    };
}]);

overlord_directive.directive('markdown', function () {
    var converter = new Showdown.converter();
    return {
        restrict: 'E',
        require: '?ngModel',
        link: function (scope, element, attrs, ngModel) {
            if (!ngModel) return; // do nothing if no ngModel
            ngModel.$render = function () {
                var value = ngModel.$viewValue || '';
                var html = converter.makeHtml(value || '');
                element.html(html);
            };
        }
    };
});

overlord_directive.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
    }
}])