/*! UIkit 2.27.2 | www.getuikit.com | © 2014 YOOtheme | MIT License */ (function(addon) {

var component;

if (window.UIkit) {
    component = addon(UIkit);
}

if (typeof define == 'function' && define.amd) {
    define('uikit-autocomplete', ['uikit'], function(){
        return component || addon(UIkit);
    });
}

})(function(UI){

"use strict";

var active;

UI.component('autocomplete', {

    defaults: {
        minLength: 3,
        param: 'search',
        method: 'post',
        delay: 300,
        loadingClass: 'uk-loading',
        flipDropdown: false,
        skipClass: 'uk-skip',
        hoverClass: 'uk-active',
        source: null,
        renderer: null,

        // template

        template: '<ul class="uk-nav uk-nav-autocomplete uk-autocomplete-results">{{~items}}<li data-value="{{$item.value}}"><a>{{$item.value}}</a></li>{{/items}}</ul>'
    },

    visible  : false,
    value    : null,
    selected : null,

    boot: function() {

        // init code
        UI.$html.on('focus.autocomplete.uikit', '[data-uk-autocomplete]', function(e) {

            var ele = UI.$(this);

            if (!ele.data('autocomplete')) {
                UI.autocomplete(ele, UI.Utils.options(ele.attr('data-uk-autocomplete')));
            }
        });

        // register outer click for autocompletes
        UI.$html.on('click.autocomplete.uikit', function(e) {
            if (active && e.target!=active.input[0]) active.hide();
        });
    },

    init: function() {

        var $this   = this,
            select  = false,
            trigger = UI.Utils.debounce(function(e) {

                if (select) {
                    return (select = false);
                }

                $this.handle();
            }, this.options.delay);

        this.dropdown = this.find('.uk-dropdown');
        this.template = this.find('script[type="text/autocomplete"]').html();
        this.template = UI.Utils.template(this.template || this.options.template);
        this.input    = this.find("input:first").attr("autocomplete", "off");

        if (!this.dropdown.length) {
           this.dropdown = UI.$('<div class="uk-dropdown"></div>').appendTo(this.element);
        }

        if (this.options.flipDropdown) {
            this.dropdown.addClass('uk-dropdown-flip');
        }

        this.dropdown.attr('aria-expanded', 'false');

        this.input.on({

            keydown: function(e) {

                if (e && e.which && !e.shiftKey && $this.visible) {

                    switch (e.which) {
                        case 13: // enter
                            select = true;

                            if ($this.selected) {
                                e.preventDefault();
                                $this.select();
                            }
                            break;
                        case 38: // up
                            e.preventDefault();
                            $this.pick('prev', true);
                            break;
                        case 40: // down
                            e.preventDefault();
                            $this.pick('next', true);
                            break;
                        case 27:
                        case 9: // esc, tab
                            $this.hide();
                            break;
                        default:
                            break;
                    }
                }

            },

            keyup: trigger
        });

        this.dropdown.on('click', '.uk-autocomplete-results > *', function(){
            $this.select();
        });

        this.dropdown.on('mouseover', '.uk-autocomplete-results > *', function(){
            $this.pick(UI.$(this));
        });

        this.triggercomplete = trigger;
    },

    handle: function() {

        var $this = this, old = this.value;

        this.value = this.input.val();

        if (this.value.length < this.options.minLength) return this.hide();

        if (this.value != old) {
            $this.request();
        }

        return this;
    },

    pick: function(item, scrollinview) {

        var $this    = this,
            items    = UI.$(this.dropdown.find('.uk-autocomplete-results').children(':not(.'+this.options.skipClass+')')),
            selected = false;

        if (typeof item !== "string" && !item.hasClass(this.options.skipClass)) {
            selected = item;
        } else if (item == 'next' || item == 'prev') {

            if (this.selected) {
                var index = items.index(this.selected);

                if (item == 'next') {
                    selected = items.eq(index + 1 < items.length ? index + 1 : 0);
                } else {
                    selected = items.eq(index - 1 < 0 ? items.length - 1 : index - 1);
                }

            } else {
                selected = items[(item == 'next') ? 'first' : 'last']();
            }

            selected = UI.$(selected);
        }

        if (selected && selected.length) {
            this.selected = selected;
            items.removeClass(this.options.hoverClass);
            this.selected.addClass(this.options.hoverClass);

            // jump to selected if not in view
            if (scrollinview) {

                var top       = selected.position().top,
                    scrollTop = $this.dropdown.scrollTop(),
                    dpheight  = $this.dropdown.height();

                if (top > dpheight ||  top < 0) {
                    $this.dropdown.scrollTop(scrollTop + top);
                }
            }
        }
    },

    select: function() {

        if(!this.selected) return;

        var data = this.selected.data();

        this.trigger('selectitem.uk.autocomplete', [data, this]);

        if (data.value) {
            this.input.val(data.value).trigger('change');
        }

        this.hide();
    },

    show: function() {

        if (this.visible) return;

        this.visible = true;
        this.element.addClass('uk-open');

        if (active && active!==this) {
            active.hide();
        }

        active = this;

        // Update aria
        this.dropdown.attr('aria-expanded', 'true');

        return this;
    },

    hide: function() {
        if (!this.visible) return;
        this.visible = false;
        this.element.removeClass('uk-open');

        if (active === this) {
            active = false;
        }

        // Update aria
        this.dropdown.attr('aria-expanded', 'false');

        return this;
    },

    request: function() {

        var $this   = this,
            release = function(data) {

                if(data) {
                    $this.render(data);
                }

                $this.element.removeClass($this.options.loadingClass);
            };

        this.element.addClass(this.options.loadingClass);

        if (this.options.source) {

            var source = this.options.source;

            switch(typeof(this.options.source)) {
                case 'function':

                    this.options.source.apply(this, [release]);

                    break;

                case 'object':

                    if(source.length) {

                        var items = [];

                        source.forEach(function(item){
                            if(item.value && item.value.toLowerCase().indexOf($this.value.toLowerCase())!=-1) {
                                items.push(item);
                            }
                        });

                        release(items);
                    }

                    break;

                case 'string':

                    var params ={};

                    params[this.options.param] = this.value;

                    UI.$.ajax({
                        url: this.options.source,
                        data: params,
                        type: this.options.method,
                        dataType: 'json'
                    }).done(function(json) {
                        release(json || []);
                    });

                    break;

                default:
                    release(null);
            }

        } else {
            this.element.removeClass($this.options.loadingClass);
        }
    },

    render: function(data) {

        this.dropdown.empty();

        this.selected = false;

        if (this.options.renderer) {

            this.options.renderer.apply(this, [data]);

        } else if(data && data.length) {

            this.dropdown.append(this.template({items:data}));
            this.show();

            this.trigger('show.uk.autocomplete');
        }

        return this;
    }
});

return UI.autocomplete;

});