angular.module('localytics.directives', []);

angular.module('localytics.directives').directive('chosen', ['$timeout', function ($timeout) {
    var CHOSEN_OPTION_WHITELIST = ['noResultsText', 'allowSingleDeselect', 'disableSearchThreshold', 'disableSearch'],
        NG_OPTIONS_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w\d]*)|(?:\(\s*([\$\w][\$\w\d]*)\s*,\s*([\$\w][\$\w\d]*)\s*\)))\s+in\s+(.*)$/;

    var isEmpty = function (value) {
        var key, i, len;
        if (angular.isArray(value)) {
            return value.length === 0;
        } else if (angular.isObject(value)) {
            for (i = 0, len = value.length; i < len; i++) {
                key = value[i];
                if (value.hasOwnProperty(key)) {
                    return false;
                }
            }
        }
        return true;
    };

    var snakeCase = function (input) {
        return input.replace(/[A-Z]/g, function ($1) {
            return "_" + ($1.toLowerCase());
        });
    };


    return {
        restrict: 'A',
        link: function (scope, element, attr) {
            var match,
                options = scope.$eval(attr.chosen) || {},
                valuesExpr;

            angular.forEach(attr, function (value, key) {
                if (CHOSEN_OPTION_WHITELIST.indexOf(key) > -1) {
                    return options[snakeCase(key)] = scope.$eval(value);
                }
            });
            var startLoading = function () {
                return element.addClass('loading').attr('disabled', true).trigger('liszt:updated');
            };
            var stopLoading = function () {
                return element.removeClass('loading').attr('disabled', false).trigger('liszt:updated');
            };
            var disableWithMessage = function (message) {
                return element.empty().append("<option selected>" + message + "</option>").attr('disabled', true).trigger('liszt:updated');
            };
            $timeout(function () {
                return element.chosen(options);
            });
            if (attr.ngOptions) {
                match = attr.ngOptions.match(NG_OPTIONS_REGEXP);
                valuesExpr = match[7];
                if (angular.isUndefined(scope.$eval(valuesExpr))) {
                    startLoading();
                }
                return scope.$watch(valuesExpr, function (newVal, oldVal) {
                    if (newVal !== oldVal) {
                        stopLoading();
                        if (isEmpty(newVal)) {
                            return disableWithMessage(options.no_results_text || 'No values available');
                        }
                    }
                });
            }
        }
    };
}
]);
