// language utilities - marcus phillips
//
// a namespace for general language extensions and helpers

var lu = Object();


lu.defaulted = function( current_value, default_value ){ return (current_value === undefined) ? default_value : current_value; };
lu.default_to = lu.defaulted; // backwards compatibility

/**
 * Sets and ensures default attribute values in the specified object.
 * Initializes the object if it is undefined.
 * Does not alter attributes that are already set in the object
 * @param target Object in which we want to ensure default values
 * @param source Object containing desired default values
 * @return Object with default values set
 */
lu.defaults = function( target, source ){
  if( arguments.length !== 2 ){ throw 'lu.defaults requires exactly two arguments: the target, and a hash of defaults'; }
  target = lu.defaulted(target, {});
  $.each(source, function(which,property){
    target[which] = lu.defaulted(target[which], property);
  });
  return target;
};

lu.set_defaults = function( focus, defaults ){ return jQuery.extend(defaults, focus); };

lu.absorb = function( destination, source, keys ){
  lu.each(keys, function(which_key, each_key){
    destination[each_key] = source[each_key];
  });
};

lu.type_of = function( value ){
  var type = typeof value;
  if( type === 'object' ){
    if( ! value ){
      return 'null';
    }else if( typeof value.length === 'number' && !(value.propertyIsEnumerable('length')) && typeof value.splice === 'function' ){
      return 'array';
    }
  }
  return type;
};

lu.in_array = function( needle, haystack, strictly ){
  for( var which in haystack ){ if( haystack.hasOwnProperty(which) ){
    if(  strictly && haystack[which] === needle ){ return true; }
    if( !strictly && haystack[which] ==  needle ){ return true; }
  }}
  return false;
};

lu.is_empty = function( container ){
  var which_element, element;
  if( lu.type_of(container) === 'string' ){ return container.length === 0; }
  if( lu.type_of(container) === 'array'  ){ return container.length === 0; }
  if( lu.type_of(container) === 'object' ){
    for(which_element in container){ if(container.hasOwnProperty(which_element)){
      element = container[which_element];
      if( element !== undefined && lu.type_of(element) !== 'function' ){
        return false;
      }
    }}
  }
  return true;
};


// Array Remove - By John Resig (MIT Licensed)
lu.array_remove = function(array, from, to) {
    var rest = array.slice((to || from) + 1 || array.length);
    array.length = from < 0 ? array.length + from : from;
    return array.push.apply(array, rest);
};

// duplicated from jquery to avoid dependency
lu.each = function( object, callback, args ){
    var name, i = 0, length = object.length;

    if ( args ) {
        if ( length === undefined ) {
            for ( name in object ){
                if ( callback.apply( object[ name ], args ) === false ){
                    break;
                }
            }
        }else{
            for ( ; i < length; ){
                if ( callback.apply( object[ i++ ], args ) === false ){
                    break;
                }
            }
        }

    // A special, fast, case for the most common use of each
    } else {
        if ( length === undefined ) {
            for ( name in object ){
                if ( callback.call( object[ name ], name, object[ name ] ) === false ){
                    break;
                }
            }
        }else{
          for( var value = object[0]; i < length && callback.call( value, i, value ) !== false; value = object[++i] ){ }
        }
    }

    return object;
};

lu.index_of = function( item, list ){
  var matching_index;
  lu.each(list, function(which_item, each_item){
    if( each_item === item ){ matching_index = which_item; return false; }
  });
  return matching_index;
};

lu.deep_transform = function( item_or_list, transformation_function, test_function ){
  if( test_function === undefined ){ test_function = function(){return true;}; }
  if( lu.index_of( lu.type_of(item_or_list), ['array', 'object'] ) !== undefined){
    jQuery.each( item_or_list, function( which_sub_item_or_list, each_sub_item_or_list ){
      item_or_list[which_sub_item_or_list] = lu.deep_transform(each_sub_item_or_list, transformation_function, test_function);
    });
    return item_or_list;
  }else{
    if( test_function(item_or_list) ){
      return transformation_function( item_or_list );
    }else{
      return item_or_list;
    }
  }
};

lu.indexed_by = function(set, lookup){
  var key_generator = ( lu.type_of(lookup) === 'string' ? function(each_item){return each_item[lookup];} : lookup );
  var indexed_set = {};
  jQuery.each(set, function(which_element, each_element){
    indexed_set[key_generator(each_element)] = each_element;
  });
  return indexed_set;
};

lu.alphabetized = function(set, lookup){
  var string_maker = (
    lu.type_of(lookup) === 'undefined' ? function(each_item){return lu.alphabetizable(each_item        );} :
    lu.type_of(lookup) === 'string'    ? function(each_item){return lu.alphabetizable(each_item[lookup]);} :
    lu.type_of(lookup) === 'function'  ? lookup :
    lu.error('bad lookup type for lu.alphabetized: '+lu.type_of(lookup))
  );
  var result = [];
  lu.each(set, function(which_item, each_item){
    result.push(each_item);
  });
  return result.sort(function(apple,orange){
    var apple_string = string_maker(apple), orange_string = string_maker(orange);
    return apple_string < orange_string ? -1 : orange_string < apple_string ? 1 : 0;
  });
};

lu.trim                = function(string){ return (string).replace(/^\s*|\s*$/g,'' ); };
lu.remove_whitespace   = function(string){ return (string).replace(/\s+/g      ,'' ); };
lu.collapse_whitespace = function(string){ return (string).replace(/\s+/g      ,' '); };
lu.alphabetizable      = function(string){ return lu.collapse_whitespace(lu.trim(string.toLowerCase())); };
lu.abbreviate          = function(string, options){
  options = lu.defaults(options, {
          /*
    'ellipsis' : "…",
    'limit' : 15,
    'unescape_HTML' : false
          */
  });
  /*
  if( options.unescape_HTML ){
    string = lu.unescape_HTML(string);
  }
  if( string.length > options.limit ){
    string = string.substring(0, Math.max(options.limit - ellipsis.length, 1));
    string += options.ellipsis;
  }
  */
  return string;
};

lu.is_plural = function( input ){
  return lu.type_of(input) === 'array';
};
lu.pluralized = function( input ){
  return lu.is_plural(input) ? input : [input];
};

lu.unescape_HTML = function( escaped ){
	var node = document.createElement("div");
	node.innerHTML = escaped;
	if( node.innerText !== undefined ){ return node.innerText;   } // Internet explorer
	else                              { return node.textContent; } // Firefox
};
