(function($) {
	$.fn.getAnchor = function() {
		var $this = $(this);
		if ($this.attr('href')) {
			return $this.attr('href').split('#')[1];
		}
		return '';
	};
	
	$.is_empty = function(mixed_var) {
		if (mixed_var === ""
			|| mixed_var === 0
			|| mixed_var === "0"
			|| mixed_var === null
			|| mixed_var === false
			|| mixed_var === undefined
			|| typeof(mixed_var) == "undefined"
		){
			return true;
		}
		if (typeof(mixed_var) == 'object') {
			for (var i in mixed_var) {
				return false;
			}
			return true;
		}
		return false;
	};
	
	/**
	 * @return $func
	 */
	$.fn.as_function = function(){
		var $this = $(this);
		if ($.fn.metadata) {
			var $func = $this.metadata({type: 'attr', name: 'rel'});
			if (!$.is_empty($func)) {
				return eval($func);
			}
		}
		return null;
	};
	
	$.getUrlVars = function(){
		var map = {};
		var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) {
			map[key] = value;
		});
		return map;
	}
})(jQuery);

$.extend($.expr[':'], {
	regex: function(elem, index, match) {
		var
			matchParams = match[3].split(','),
			regexFlags = typeof matchParams[2] != 'undefined' ? matchParams[2] : 'i',
			regex = new RegExp(matchParams[1].replace(/^\s+|\s+$/g, ''), regexFlags);

		var
			testAgainst;

		try{
			testAgainst = $(elem)[matchParams[0]]();
		} catch(e){
			testAgainst = $(elem).attr(matchParams[0]);
		}

		return regex.test(testAgainst);
	},
	defaultValue: function(elem, index, match) {
		var $this = $(elem);
		if (!$this.is('input[type=text]')) return false;
		return elem.value == elem.defaultValue;
	}
});

/**
 * Serialize a form with many levels deep
 * Input names must be arrays style
 * name="food[]" or name="name[first]"
 * Supports input, keygen, select, textarea
 */
$.fn.serializeForm = function(opt){
	opt = $.extend({}, opt);

	if (typeof opt['disabled'] === 'undefined' || opt['disabled'] === null) opt['disabled'] = false;
	if (typeof opt['all'] === 'undefined' || opt['all'] === null) opt['all'] = false;
	if (typeof opt['empty'] === 'undefined' || opt['empty'] === null) opt['empty'] = true;

	var $form = $(this);

	var
	result = {}
	formValues =
	$form
	.find('input,textarea,select,keygen')
	.filter(function(){
		var ret = true;
		if (!opt['disabled']) ret = !this.disabled;
		return ret && $.trim(this.name);
	})
	.map(function(){
		var $this = $(this),
		value = null;

		if ($this.is('input:radio') || $this.is('input:checkbox')){
			if ($this.is('input:radio')) {
				radios = $form.find('input:radio[name="' + this.name + '"]');
				if (radios.filter(':checked').size()) {
					value = radios.filter(':checked').val();
				}
				type = 'radio';
			} else if ($this.is('input:checked')) {
				value = $this.val();
				type = 'checkbox';
			}
		} else if ($this.is('select')) {
			options = $this.find('option:selected');
			if($this.attr('multiple')){
				value = options.map(function(){
					return this.value || this.innerHTML;
				}).get();
			} else {
				value = options.val() || options.text();
			}
			type = 'select';
		} else {
			value = $this.val();
			type = 'input';
		}

		return {
			'name': this.name,
			'value': value,
			'type': type
		};
	}).get();

	if (formValues){
		var i, value, name;

		for (i = 0; i < formValues.length; i++){
			name = formValues[i].name;
			value = formValues[i].value;

			if (!opt['all']){
				if (value === null) continue;
			} else {
				if (value === null) value = '';
			}
			
			if (value === '' && !opt['empty']) 
				continue;
			
			if (!name) continue;

			$matches = name.split(/\[/);

			var len = $matches.length;

			for(var j = 1; j < len; j++){
				$matches[j] = $matches[j].replace(/\]/g, '');
			}

			var fields = [], strpath = [];


			for(j = 0; j < len; j++){
				if ($matches[j]){
					fields.push($matches[j]);
				}
			}

			/*
			 * this function ensures that the object of unknown depth
			 * exists, otherwise the javascript console will trigger for eg:
			 * "result.one is undefined"
			 */
			create = function(create_array, res, path){
				var field = fields.shift();

				if (field){
					if (typeof res[field] === "undefined" || !res[field]) res[field] = (create_array?[]:{});
					path.push('[\''+field+'\']');
					create(create_array, res[field], path);
				}
			}

			if (!$matches[len-1]) { // Check if the last is [], as in food[]
				create(true, result, strpath);
				/*
				 * build a multidimensional array of unknown size
				 * result["one"]["two"]["three"]["..."]
				 */
				eval('res = result' + strpath.join('') + ';');

				if(value.constructor === Array){
					for(x = 0; x < value.length; x++){
						res.push(value[x]);
					}
				} else {
					res.push(value);
				}
			} else { // Single value like 'field[name]' or 'name'
				create(false, result, strpath);
				/*
				 * Since we don't know the depth of the object
				 * we eval() it so we can assign to
				 * result["one"]["two"]["three"]["..."] = value;
				 * 
				 * where value will be converted properly, either to
				 * a integer, string, array or object, so it must go
				 * inside eval() as well
				 */
				eval('result' + strpath.join('') + ' = value;');
			}
		}
	}

	return result;
};


$(function(){
  $('select:not(.no)').each(function(){
    var
      $this = $(this),
      $options = $this.find('option'),
      $text = $('<span/>'),
      $select = $('<div/>', {'class': 'select'}),
      $trigger = $('<a/>');

    $this.bind({
      'toggle':function(e){
        var $this = $(this);
        
        if ($this.attr('multiple')) {
          
        } else {
          $text.text($options.filter(':selected').text());
        }
        
        $this.trigger('change');
      }
    });

    $select.insertAfter($this);

    $list = $('<ul/>').html(
        $.map($this.find('option'), function(e){
          return '<li><a rel="' + $(e).val() + '">' + $(e).text() + '</a></li>';
        }
      ).join('')
    );

    $list.find('a').each(function(){
      $(this).bind({
        'click':function(e){
          $this.val(e.target.rel);
          $trigger.triggerHandler('click');
          $this.trigger('toggle');
          
          e.preventDefault();
          return false;
        }
      })
    });

    $select
    .append($list)
    .append(
      $trigger
      .bind({
        'click': function(e){
          var $this = $(this);
          $this.toggleClass('expanded');
          
          if ($this.hasClass('expanded')) {
            $list.addClass('expanded');
          } else {
            $list.removeClass('expanded');
          }
        }
      })
    )
    .append(
      $text.text($this.find(':selected').text())
    );
    
    $this.css({'display': 'none'})
  });

	$('input[type=checkbox],input[type=radio]').each(function(){
		var $this = $(this);
		var className = '';
		
		switch ($this.attr('type')) {
			case 'radio':
				className = 'radio';
				break;
			case 'checkbox':
				className = 'checkbox';
				break;
		}

		var $link = $('<a/>');

		$link.addClass(className);

		if ($this.is(':checked')) {
			$link.addClass('checked');
		}

    $this.data('collective', $('input[type="' + className + '"][name="' + $this.attr('name') + '"]'));
    
    $this.bind({
      'toggle':function(e){
        var $vthis = $(this);
        $vthis.trigger('click');

        if (this.checked) {
          $vthis.data('owner').addClass('checked');
        } else {
          $vthis.data('owner').removeClass('checked');
        }

        if ($this.is(':radio')) {
          $vthis.trigger('uncheckall');
        }
      },
      'uncheckall':function(e){
        var $vthis = $(this);
        $vthis.data('collective').not($vthis).each(function(){
          $(this).data('owner').removeClass('checked');
        })
      }
    });

		$link.html($this.attr('title'));
		$link.attr('style', $this.attr('style'));
    $link.data('parent', $this);
    
		$link
		.insertAfter($this);
    
    $this.data('owner', $link);

		$link.click(function(e){
			var $a = $(this);
      
			$a.data('parent').trigger('toggle');
			
			e.preventDefault();
			return false;
		});

		$this.css({'display':'none'});
	});
});

