/*
 * Copyright (C) by Netcetera AG.
 * All rights reserved.
 *
 * The copyright to the computer program(s) herein is the property of
 * Netcetera AG, Switzerland.  The program(s) may be used and/or copied
 * only with the written permission of Netcetera AG or in accordance
 * with the terms and conditions stipulated in the agreement/contract
 * under which the program(s) have been supplied.
 *
 */

/**
 * A jQuery plugin that helps work with select boxes.
 * Usage:
 *  $('#select-box').options([[label, value], [label, value]]);
 * 
 * Supports chaining of select boxes as well as ajax reloads. 
 */
(function($) {

  $.fn.extend({
    
    options: function(obj) {
      if (obj) {
        if (typeof obj == 'number') {
          return $('option:eq(' + obj + ')', this);
          
        } else if (obj == 'selected') {
          return this.val();
          
        } else if (obj == 'selected-data') {
          return this[0].options[this[0].selectedIndex]._select_optionData;
          
        } else if (obj instanceof Array) {
          this.each(function() {
            var selBox = this;
            $.each(obj, function() {
              var op = new Option(this[0], this[1]);
              if (this.length == 3) {
                op._select_optionData = this[2];
              }
              
              selBox.options[selBox.options.length] = op;
            });
          });
          
          var me = this;
          setTimeout(function() {
            me.trigger('change');
          }, 0);
          
          return this;
        } else {
          return this.setupOptions(obj);
        }
      } else {
        return $('option', this);
      }
      return $([]); 
    },
    
    dependsOn: function(obj) {
      obj = (typeof obj == 'string') ? $(obj) : obj;

      var me = this;
      obj.change(function() {
        me.reload();
      });
      return this;
      // return this.change(function() {
      //   obj.change($.bind(me.reload, me));
      // });
    },
    
    setupOptions: function(options) {
      var allowedOptions = [
        'source',
        'url',
        'selected',
        'resultMapper',
        'prepend'
      ];
      
      var defaults = {
        key: 'id',
        value: 'label'
      };
      
      var settings = $.extend({}, defaults, options);
      
      return this.data('optionSettings', settings)
                 .reload();
    },
    
    reloadFromSource: function(settings) {
      if (!settings.source) {
        return;
      }
      
      var result;
      if ($.isFunction(settings.source)) {
        result = settings.source();
      } else {
        result = settings.source;
      }
      result = $.makeArray(result);
      
      if ($.isArray(settings.prepend)) {
        result.unshift(settings.prepend);
      }
      
      this.options(result);
      this.setDefault(settings, result);
    },
    
    reloadFromUrl: function(settings) {
      
      if (!settings.url) {
        return;
      }
      
      var url = $.isFunction(settings.url) ? settings.url() : settings.url;
      
      if (!url) {
        return;  // the function may return null if there is no data
      }
      
      var resultMapper;
      if ($.isFunction(settings.resultMapper)) {
        resultMapper = settings.resultMapper;
      } else if (settings.resultMapper &&
                 settings.resultMapper.key &&
                 settings.resultMapper.label) {
        resultMapper = function(result) {
          return $.map(result, function(val) {
            // jQuery does a flatmap instead of map so do double array
            return [[val[settings.resultMapper.label], val[settings.resultMapper.key], val]];
          });
        };
      }
      
      
      this.empty();
      
      var me = this;
      $.getJSON(url, function(result) {
        if (resultMapper) {
          result = resultMapper(result);
        }
        
        if ($.isArray(settings.prepend)) {
          result.unshift(settings.prepend);
        }
        
        me.options(result);
        
        me.setDefault(settings, result);
      });     
    },
    
    setDefault: function(settings, result) {
      var defVal = $.isFunction(settings.selected) ? 
                        settings.selected(result) :
                        settings.selected;
      var me = this;
      $.each(result, function(e) {
        if (defVal == this[1]) {
          me.val(defVal);
        }
      });
    },
    
    reload: function() {
      var settings = this.data('optionSettings');
      
      if (!settings) {
        return;
      }
      
      if (settings.source) {
        this.reloadFromSource(settings);
      } else if (settings.url) {
        this.reloadFromUrl(settings);
      }
      
      return this;
    }
    
  });

})(jQuery);