
/**
 * Enumeration control to show a autocomplete/combobox of all instances of a specific type
 * For example, to show an enumeration of all US Presidents:
 *
 * $("input").suggesttype({type:"/government/us_president"});
 */
;(function($) {
        if (!$.suggest) {
            alert("$.suggest required");
        }

        var base = {
            _init: $.suggest.suggest.prototype._init,
            _destroy: $.suggest.suggest.prototype._destroy,
            response: $.suggest.suggest.prototype.response
        };

        $.suggest("suggesttype",
                  $.extend(true, {}, $.suggest.suggest.prototype, {
                          _init: function() {
                              var self = this,
                                  o = this.options;
                              // call super._init()
                              base._init.call(self);

                              this.result = null;

                              // add drop down button
                              this.input.next(".fbs-list-dropdown").remove();
                              this.dropdown =
                                  $('<button type="button" class="fbs-list-dropdown">&#9660;</button>')
                                       // we do the following instead of listening for a single
                                      // click event because we don't always get a click event
                                      // due to other event handlers (usually blur)
                                      .bind("mouseup.suggest", function(e) {
                                                self.request();
                                                self.input.focus();
                                                return false;
                                            })
                                      .bind("keypress.suggest", function(e) {
                                              if (e.keyCode === 13) {
                                                  self.request();
                                                  self.input.focus();
                                                  return false;
                                              }
                                            });
                              this.input.after(this.dropdown);

                              if (o.mql_query && typeof o.mql_query === "object") {
                                  if (typeof JSON === "undefined") {
                                      init_JSON();
                                  }
                                  o.mql_query = JSON.stringify(o.mql_query);
                              }
                          },

                          _destroy: function() {
                              base._destroy.call(this);
                              this.dropdown.remove();
                          },

                         // jquery.suggest clears list on focus if input is empty
                         // override not to do this
                         focus: function(e) {
                           this.focus_hook();
                         },

                         textchange: function() {
                           this.input.removeData("data.suggest");
                           this.input.trigger("fb-textchange", this);
                           window.clearTimeout(this.textchange.timeout);
                           var self = this;
                           this.textchange.timeout = window.setTimeout(function(){self.textchange_delay();}, 200);
                         },

                         textchange_delay: function() {
                           var val = $.trim(this.input.val());
                           this.request(val);
                         },

                         request: function(val) {
                           if (this.result) {
                             this.response(val);
                             return;
                           }

                           if (this.ac_xhr) {
                             this.ac_xhr.abort();
                             this.ac_xhr = null;
                           }

                           var self = this,
                               o = this.options,
                               data = {
                                   query: o.mql_query || '{"query":[{"id":null,"name":null,"optional":true,"/common/topic/alias":[{"optional":true,"value":null}],\"sort":"name","type":"'+o.type+'","limit":'+o.limit+'}],"lang":"'+o.lang+'"}'
                               };

                           window.clearTimeout(this.request.timeout);
                           this.request.timeout =
                               window.setTimeout(function() {
                                       self.ac_xhr = $.ajax({
                                               url: o.service_url + o.service_path,
                                               data: data,
                                               beforeSend: function() {
                                                   var calls = self.input.data("request.count.suggest") || 0;
                                                   if (!calls) {
                                                       self.trackEvent(self.name, "start_session");
                                                   }
                                                   calls += 1;
                                                   self.trackEvent(self.name, "request", "count", calls);
                                                   self.input.data("request.count.suggest", calls);
                                               },
                                               success: function(data, status) {
                                                   if (data.code === "/api/status/ok") {
                                                       self.result = data.result;
                                                       self.response(val, true);
                                                   }
                                               },
                                               error: function(xhr, s, ex) {
                                                   self.trackEvent(self.name, "request", "error", {url:this.url, response: xhr ? xhr.responseText : null});
                                               },
                                               complete: function(xhr) {
                                                   if (xhr) {
                                                       self.trackEvent(self.name, "request", "tid", xhr.getResponseHeader("X-Metaweb-TID"));
                                                   }
                                               },
                                               dataType: self.jsonp ? "jsonp" : "json",
                                               cache: true
                                           });
                                       }, 200);
                         },

                         build: function() {
                           var self = this;
                           this.list.empty();
                           $.each(this.result, function() {
                                    var data = this;
                                    if (!data.alias && "/common/topic/alias" in data) {
                                      // map data["/common/topic/alias"] to alias
                                      data.alias = $.map(data["/common/topic/alias"], function(n,i) {
                                                           return n.value;
                                                         });
                                    }

                                    var $li = self.create_item(data)
                                      .bind("mouseover.suggest", function(e) {
                                              self.mouseover_item(e);
                                            })
                                      .data("data.suggest", data);
                                      self.list.append($li);
                                    });
                         },

                         response: function(val, build) {
                           var self = this;
                           // check if list has been built?
                           if (build) {
                             this.build();
                           }

                           var $items = $(">li", this.list);
                           if (val === null || val === "") {
                             // show all items
                             $items.show();
                           }
                           else {
                             var prefix = new RegExp("\\b" + val, "i");
                             $.each($items, function() {
                                      var $this = $(this);
                                      var data = $(this).data("data.suggest");
                                      if (prefix.test(data.name)) {
                                        $this.show();
                                      }
                                      else {
                                        var alias = false;
                                        if (data.alias) {
                                            $.each(data.alias, function(i,n) {
                                                if (prefix.test(n)) {
                                                    alias = true;
                                                    return false;
                                                }
                                            });
                                        }
                                        if (alias) {
                                          $this.show();
                                        }
                                        else {
                                          $this.hide();
                                        }
                                      }
                                    });
                             if (!$(">li:visible", this.list).length) {
                               $items.show();
                             }
                           }

                           this.input.data("original.suggest", this.input.val());

                           this.position();
                           this.pane.show();
                         },

                         check_response: function(response_data) {
                           return true;
                         },

                         create_item: function(data) {
                             var css = this.options.css;
                             li = $("<li>").addClass(css.item);
                             var label = $("<label>").text(data.name);
                             data.name = label.text();
                             li.append($("<div>").addClass(css.item_name).append(label));
                             return li;
                         }

                       }));



     $.extend($.suggest.suggesttype, {
         defaults:  $.extend(true, {}, $.suggest.suggest.defaults, {
             type: "/location/country",
             mql_query: null,
             limit: 500,
             service_url: "http://www.freebase.com",
             service_path: "/api/service/mqlread",
             lang: "/lang/en",
             status: null
         })
     });

})(jQuery);

