(function($) {
   $.widget("ui.combobox", {
      _create: function() {
         var self = this;
         var select = this.element.hide();
         var input = $("<input>")
         .css('min-width', select.innerWidth())
         .insertAfter(select)
         .val(select.find('option:selected').text()  )
         .autocomplete({
            source: function(request, response) {
               var matcher = new RegExp(request.term, "i");
               response(select.children("option").map(function() {
                  var text = $(this).text();
                  if (!request.term || matcher.test(text))
                     return {
                        id: $(this).val(),
                        label: text.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + request.term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>"),
                        value: text
                     };
               }));
            },
            delay: 0,
            select: function(e, ui) {
               if (!ui.item) {
                  // remove invalid value, as it didn't match anything
                  $(this).val("");
                  return false;
               }
               $(this).focus();
               select.val(ui.item.id);
               self._trigger("selected", null, {
                  item: select.find("[value='" + ui.item.id + "']")
               });

            },
            change: function(e, ui){
               if(!ui.item){
                  $(this).blur(function() {
                     $(this).val(select.find('option:selected').text());
                  });
               }
            },
            minLength: 0
         })
         .removeClass("ui-corner-all")
         .addClass("ui-widget ui-widget-content ui-corner-left ui-combobox");
         $("<a>&nbsp;</a>")
         .insertAfter(input)
         .button({
            icons: {
               primary: "ui-icon-triangle-1-s"
            },
            text: false
         }).removeClass("ui-corner-all")
         .addClass("ui-corner-right ui-button-icon")
         .position({
            my: "left center",
            at: "right center",
            of: input,
            offset: "-1 0"
         }).css("top", "")
         .click(function() {
            // close if already visible
            if (input.autocomplete("widget").is(":visible")) {
               input.autocomplete("close");
               return;
            }
            // pass empty string as value to search for, displaying all results
            input.autocomplete("search", "");
            input.focus();
         });
      }
   });

   $.widget("ui.advselect", {
      options:{
         minLength: 0,
         delay: 300,
         value:{
            id: 0,
            value: ''
         },
         url: 'index.php',
         params: {},
         dataType: 'jsonp',
         limit: 50,
         searchOptions:[],
         quickAdd: null,
         clearButton: false
      },
      _create: function() {
         var self = this;
         var input = this.element.val(this.options.value.id);
        
         var wrapper = $("<div />")
         .addClass('ui-corner-all ui-widget-content ui-helper-clearfix')
         .css('border', '1px solid #eee')
         .css('background', '#fefefe')
         .css('padding', '1em .1em')
         .css('float', 'left');

         this._initSource();

         this.text = this.options.value.value;

         var filter = $("<input>")
         .css('min-width', 300)
         .insertAfter(input)
         .val(this.options.value.value)
         .autocomplete({
            source: this.source,
            delay: 300,
            select: function(event, ui) {
               self._select(event, ui);
            },
            minLength: 0
         })
         .removeClass("ui-corner-all")
         .addClass("ui-widget ui-widget-content ui-corner-left ui-combobox")
         .wrap(wrapper)
         .bind('blur', function() {
            self._blur();
            self._trigger('blur')
         });

         this.filter = filter;

         var browseToggle = $("<a>&nbsp;</a>")
         .insertAfter(filter)
         .attr('title', 'Browse')
         .button({
            icons: {
               primary: "ui-icon-triangle-1-s"
            },
            text: false
         }).removeClass("ui-corner-all")
         .addClass("ui-button-icon")
         .position({
            my: "left center",
            at: "right center",
            of: filter,
            offset: "-1 0"
         }).css("top", "")
         .click(function() {
            // close if already visible
            if (filter.autocomplete("widget").is(":visible")) {
               filter.autocomplete("close");
               return;
            }
            // pass empty string as value to search for, displaying all results
            filter.autocomplete("search", "");
            filter.focus();
         });

         var lastButton = browseToggle;
         this.searchOptInputs = [];


         if(this.options.searchOptions && this.options.searchOptions.length > 0){


            var searchOpts = $("<div />")
            .insertBefore(filter)
            .addClass('ui-searchoptions')
            .css('padding', '4px 8px 16px')
            .css('font-size', '.7em')
            .hide();
         

            var optMaxWidth = 0;

            for (i in this.options.searchOptions) {
               var opt = $('<input>')
               .attr('type', 'hidden')
               .appendTo(searchOpts)
               .searchoption($.extend({
                  change: function() {
                     if(searchOpts.is(':visible')){
                        filter.autocomplete("search", "");
                        filter.focus();
                     }
                  }
               }, this.options.searchOptions[i]));

               this.searchOptInputs.push(opt);

               if(opt.outerWidth() > optMaxWidth){
                  optMaxWidth = opt.outerWidth();
               }                         
            }

            if(optMaxWidth){
               searchOpts.css('width',optMaxWidth+20);
            }

            var searchToggle = $("<a>&nbsp;</a>")
            .insertAfter(browseToggle)
            .attr('title', 'Search Options')
            .button({
               icons: {
                  primary: "ui-icon-search"
               },
               text: false
            }).removeClass("ui-corner-all")
            .addClass("ui-button-icon")
            .position({
               my: "left center",
               at: "right center",
               of: browseToggle,
               offset: "-1 0"
            }).css("top", "")
            .click(function() {
               searchOpts.toggle('slide', {}, 300, function(){
                  if(searchOpts.is(':hidden')){
                     //clear search opts
                     searchOpts.find('input').each(function(){
                        $(this).searchoption("reset");
                     });
                  }
               });
            });
            
            lastButton = searchToggle;

         }

         if(this.options.clearButton){
            var clearButton = $("<a>&nbsp;</a>")
            .insertAfter(lastButton)
            .attr('title', 'Clear Selection')
            .button({
               icons: {
                  primary: "ui-icon-cancel"
               },
               text: false
            }).removeClass("ui-corner-all")
            .addClass("ui-button-icon")
            .position({
               my: "left center",
               at: "right center",
               of: lastButton,
               offset: "-1 0"
            }).css("top", "")
            .click(function() {
               self._clear();
            });

            lastButton = clearButton;
         }
         
         if(this.options.quickAdd){
            $("<a>&nbsp;</a>")
            .insertAfter(lastButton)
            .attr('title', 'Quick Add')
            .button({
               icons: {
                  primary: "ui-icon-plus"
               },
               text: false
            }).removeClass("ui-corner-all")
            .addClass("ui-corner-right ui-button-icon")
            .position({
               my: "left center",
               at: "right center",
               of: lastButton,
               offset: "-1 0"
            }).css("top", "")
            .click(function() {
               if($.isFunction(self.options.quickAdd)){
                  self._trigger('quickAdd');
               }
            });
         }else{
            lastButton.addClass('ui-corner-right');
         }
      },
      _select: function(event, ui) {
         var self = this;
         if(ui.item.id){
            self.element.val(ui.item.id);
            if(ui.item.value){
               self.text = ui.item.value;
            }
            self._trigger('change');
         }
      },
      _clear: function() {
         this.element.val(0);
         this.filter.val('');
         this.text = '';
         this._trigger('change');
      },
      _initSource: function() {
         var self = this;

         self.source = function(request, response){
            var params = {
               q: request.term,
               limit: self.options.limit
            };

            self.params = $.extend(params, self.options.params);
           
            for (i in self.searchOptInputs){
               params[$(self.searchOptInputs[i]).attr('name')] = $(self.searchOptInputs[i]).val();
            }

            $.ajax({
               url: self.options.url,
               dataType: self.options.dataType,
               data: self.params,
               success: function(data) {
                  response($.map(data.results, function(item) {
                     return {
                        label: item.string,
                        value: item.string,
                        id: item.id
                     }
                  }))
               }
            })
         }
      },
      _blur: function(){
         if(this.filter.val() == ''){
            this._clear();
         }else{
            this.filter.val(this.text);
         }
      },
      reset: function(){
         this._clear();
      }
   });


   

   $.widget("ui.searchoption", {
      options:{
         label: '',
         source: null,
         name: null,
         hierarchical: false,
         noselection: {
            id: 0,
            text: '(Select One)'
         }
      },
      _create: function() {
         var self = this;
         var wrapper = $("<div />").addClass( "ui-searchoption ui-widget" )
         .css('margin', '0 0 8px');

         var input = this.element
         .attr('name', this.options.name)
         .addClass('ui-searchoption-value')
         .wrap(wrapper);


         if(!this.options.hierarchical){

            this.select = $('<select></select>')
            .attr('name', this.options.name)
            .css('display', 'block')
            .insertAfter(input)
            .change(function(){
               input.val($(this).val());
               self._trigger('change');
            });

            this._initSource();
         }else{
            input.hierarchicalselect(this.options);
         }

         $("<label>"+this.options.label+"</label>").insertBefore(input)
         .css('display', 'block');
      },
      _initSource: function() {
         var self = this;
         var url;
         if ( $.isArray(this.options.source) ) {
            this._populateSelect(this.options.source);
         } else if ( typeof this.options.source === "string" ) {
            url = this.options.source;
            $.ajax({
               url: url,
               dataType: 'jsonp',
               success: function(data) {
                  self._response($.map(data.results, function(item) {
                     return {
                        id: item.id,
                        text: item.text
                     }
                  }));
               }
            })

         } else {
            this.source = this.options.source;
         }
      },
      _response: function(content) {
         if ( content.length ) {
            content = this._normalize(content);
            this._populateSelect(content);
         }
      },
      _populateSelect: function(data){
         $('<option>')
         .val(this.options.noselection.id)
         .html(this.options.noselection.text)
         .attr('selected', 'selected')
         .appendTo(this.select);

         for (j in data) {
            $('<option value="'+data[j].id+'">'+data[j].text+'</option>')
            .appendTo(this.select);
         }
      },
      _normalize: function( items ) {
         // assume all items have the right format when the first item is complete
         if ( items.length && items[0].id && items[0].text ) {
            return items;
         }
         return $.map( items, function(item) {
            if ( typeof item === "string" ) {
               return {
                  id: item,
                  text: item
               };
            }
            return $.extend({
               id: item.id || item.value,
               text: item.value || item.text
            }, item );
         });
      },
      reset: function() {
         this.element.next('select').val(this.options.noselection.id);
         this.element.next('select').change();

      }
   });



   $.widget("ui.selecttree", {
      options:{
         url: null,
         params: {},
         value:{
            id: 0,
            text: ''
         },
         canceltext: "Cancel",
         applytext: "Apply"
      },
      _create: function() {
         var self = this;
         var wrapper = $("<div />").addClass( "ui-selecttree ui-widget" );
         if(this.element.val() && !this.options.value.id){
            this.options.value.id = this.element.val();
         }

         var input = this.element.val(this.options.value.id)
         .wrap(wrapper);
         var display = $("<div />")
         .addClass('ui-corner-left ui-widget-content ui-selecttree-display')
         .insertAfter(input);

         this.dialogButton = $("<a>&nbsp;</a>")
         .insertAfter(display)
         .button({
            icons: {
               primary: "ui-icon-pencil"
            },
            text: false
         })
         .removeClass('ui-corner-all')
         .addClass('ui-corner-right ui-button-icon')
         .position({
            my: "left center",
            at: "right center",
            of: display,
            offset: "-1 0"
         }).css("top", "")
         .click(function() {

            if(!$(this).button('option', 'disabled')){

               // close if already visible
               if (tree.dialog('isOpen')) {
                  tree.dialog('close');
               }else{
                  tree.dialog('open');
               }
            }
         });


         this.display = display;

         this._initValue();


         var tree = $("<div />").hide()
         .insertAfter(display);
         this.treeDialog = tree;


         var pending = $("<div />")
         .text(this.options.value.text)
         .addClass('ui-corner-all ui-widget-content ui-selecttree-pending')
         .hide()
         .appendTo(tree);

         this.pendingDisplay = pending;

         

         this._initTree();

         this.treeDialog.bind('click', function(e){
            var node = $(e.target);
            if(node.is('span')){
               if(node.parent('li').hasClass('selected')){
                  node.removeClass('ui-state-active');
                  node.parent('li').removeClass('selected');

                  self.pendingDisplay.attr('data-id', '');
                  self.pendingDisplay.text('');
                  self.treeDialog.dialog('option', 'title', '');

               }else{
                  self.treeDialog.find('li').removeClass('selected');
                  self.treeDialog.find('li span').removeClass('ui-state-active');

                  self.pendingDisplay.attr('data-id',(node.parent('li').attr('id')));
                  var text = node.text();
                  var currNode = node;
                  while(currNode.closest('ul').prev().is('span')){
                     currNode = currNode.closest('ul').prev('span');
                     text = currNode.text() + ' » ' + text;
                  }

                  node.addClass('ui-state-active');
                  node.parent('li').addClass('selected');

                  self.pendingDisplay.text(text);
                  self.treeDialog.dialog('option', 'title', text);
               }
            }
         });
        
         
         
      },
      _initTree: function(){
         var self = this;

         this.treeview = $("<ul></ul>")
         .insertAfter(this.pendingDisplay)
         .css('overflow', 'auto');


         this.treeview.bind('treeinit', function() {
            if(self.treeview.children().length){
               self.enable();
            }else{
               self.disable();
            }
         });

         this.treeview.treeview({
            url:this.options.url,
            id:this.options.value.id,
            params: this.options.params
         });

         this.treeview.delegate('.treenode','hover', function() {
            $(this).toggleClass('ui-state-hover');
         })



         var btns = {};
         btns[this.options.applytext] = function() {
            self._setValue(self.pendingDisplay.attr('data-id'), self.pendingDisplay.text());
            self.treeDialog.dialog('close');
         };
         btns[this.options.canceltext] = function() {
            self.treeDialog.dialog('close');
         };
         this.treeDialog.dialog({
            modal:true,
            autoOpen: false,
            width: 580,
            minHeight: 400,
            title: this.options.value.text,
            buttons: btns
         });

  

      },
      _refreshTree: function(){
         this.treeview.treeview({
            remove: 'all'
         });
         this.treeview.remove();
         this.treeDialog.dialog('destroy');
         this._initTree();
      },
      _setOption: function( key ) {
         $.Widget.prototype._setOption.apply( this, arguments );
         if ( key === "value" ) {
            this._initValue();
         }
      },
      _initValue: function(){
         this.element.val(this.options.value.id);
         var t = (this.options.value.text) ? this.options.value.text : '&nbsp;';
         this.display.html(t);
      },
      _setValue: function(id, text) {
         this.element.val(id);
         this.options.value.id = id;
         this.options.value.text = text;
         var t = (this.options.value.text) ? this.options.value.text : '&nbsp;';
         this.display.html(t);
      },
      enable: function(){
         this.display.removeClass('ui-state-disabled');
         this.dialogButton.button('enable');
      },
      disable: function(){
         this.display.addClass('ui-state-disabled');
         this.dialogButton.button('disable');
      },
      refresh: function (){
         this._refreshTree();
      }
   });


   $.widget("ui.hierarchicalselect", {
      options:{
         url: null,
         params: null,
         data: null,
         value: null,
         idname: 'parentid',
         noselection: {
            id: 0,
            text: '(Select One)'
         }
      },
      _create: function() {
         var self = this;
         var input = this.element;
         this.selects = [];
         var wrapper = $('<div />')
         .addClass('hierarchicalselect-wrapper')
         .bind('change', function(e) {
            if($(e.target).hasClass('hierarchicalselect')){
               var hIndex = parseInt($(e.target).attr("hierarchy-index"));
               var value = $(e.target).val();
               if(value != self.options.noselection.id){
                  input.val(value);
                  self._trigger('change');
                  self._getData(value, hIndex);
               }else{
                  self._destroySelect(hIndex+1);

                  if(hIndex != 0){
                     input.val(self.selects[hIndex-1].val());
                     self._trigger('change');
                  }else{
                     input.val(value)
                     self._trigger('change');
                  }
               }
            }
         });

         input.wrap(wrapper);
         


         this._createSelect(0)
         .insertAfter(input);
         this.data = this.options.data;
         this.response = function() {
            return self._response.apply( self, arguments );
         };

        
         if(this.data == null){
            this._getData(0, -1);
         }
      },
      _createSelect: function(hIndex) {
         this.selects.push($('<select>').addClass('hierarchicalselect').attr("hierarchy-index", hIndex));
         return this.selects[hIndex];
      },
      _destroySelect: function(hIndex) {
         var i = $(this.selects).length;
         while (i > hIndex){
            i--;
            this.selects[i].hide();
            this.selects[i].empty();
         }
      },
      _response: function( content, hIndex ) {
         if ( content.length ) {
            content = this._normalize( content );
            var i = hIndex+1;
            if(!this.selects[i]){
               var newSelect = $('<select>').addClass('hierarchicalselect').attr("hierarchy-index", i);
               this.selects.push(newSelect);
               newSelect.insertAfter(this.selects[hIndex]);
            }

            this._populateSelect( content, hIndex+1);
         }
      },
      _normalize: function( items ) {
         // assume all items have the right format when the first item is complete
         if ( items.length && items[0].id && items[0].text ) {
            return items;
         }
         return $.map( items, function(item) {
            if ( typeof item === "string" ) {
               return {
                  id: item,
                  text: item
               };
            }
            return $.extend({
               id: item.id || item.value,
               text: item.value || item.text
            }, item );
         });
      },
    
      _getData: function(id, hIndex){
         var self = this;
         var params = this.options.params;
         params[this.options.idname] = id;
         $.ajax({
            url: this.options.url,
            dataType: 'jsonp',
            data: params,
            success: function(data) {
               self._response($.map(data.results, function(item) {
                  return {
                     id: item.id,
                     text: item.text
                  }
               }), hIndex);
            }
         })
      },
      _populateSelect: function(data, hIndex)
      {
         if(!hIndex)
         {
            hIndex = 0;
         }
         var select = this.selects[hIndex];

         select.empty();
         select.show();
         $('<option>')
         .val(this.options.noselection.id)
         .html(this.options.noselection.text)
         .attr('selected', 'selected')
         .appendTo(select);

         for (i in data){
            $('<option>')
            .val(data[i].id)
            .html(data[i].text)
            .appendTo(select);
         }
      }
   });




}(jQuery));



