function get_attr_string(ctid, objid, attr, tag, special){
	separator = default_separator;
	value_arr = [attr, tag, ctid];
//	var ret_text = attr + '_' + tag + '_' + ctid + '_' + objid;
	
	if(tag == 'input'){
		console.assert(
			special, 
			"get_attr_string: field specifiaction expected, " +
				"when using tag " + tag);
	}
	
//	if (special) ret_text += '_' + special;
//	if (special) value_arr.append(special);
	if (objid) value_arr.push(objid);
	if (special) value_arr.push(special);
	
//	console.info(ret_text);
	return value_arr.join(separator);
}

function get_jqelem(ctid, objid, tag, special){
	//default tag
	if(!tag) tag = 'li';
	
//	 console.log('get_jqelem parameters:', ctid, objid, tag, special)
	selector = '#' + get_attr_string(ctid, objid, 'id', tag, special);
//	 console.info('get_jqelem selector:', selector);
	return $(selector);
}

function parse_attr_string(attr_string){
	console.assert(attr_string);
	var separator = default_separator
	var arr = attr_string.split(separator);
	var spec_arr = [];
//	console.log(arr)
	
	var retval = {
			'attr' : arr[0],
			'tag' : arr[1],
			'ctid' : arr[2]
	}
	// id_input_85_5_phone
	// ["id", "input", "85", "5", "phone"]
	
	if (arr.length > 3)
		if(isNaN(parseInt(arr[3]))){
			retval.oid = null;
			spec_arr.push(arr[3]);
		}else{
			retval.oid = arr[3];
		}
//		console.log(val);
	
	//TODO: make better separator
//	console.log(arr.length)
	if (arr.length > 4){
		spec_arr.push(arr[4]);
//		console.log(spec_arr)
		if (arr.length > 5) 
			spec_arr.push(arr[5])
//		console.log(spec_arr)
		if (arr.length > 6) 
			spec_arr.push(arr[6])
//		console.log(spec_arr)
		if (arr.length > 7) 
			spec_arr.push(arr[7])
//		console.log(spec_arr)
	}
	retval.spec = spec_arr.join('_');
	
	return retval;
}

/**
 * Swaps two DOM elements.
 * @param a
 * @param b
 */
function swapNodes(a, b) {
    var aparent= a.parentNode;
    var asibling= a.nextSibling===b? a : a.nextSibling;
    
    b.parentNode.insertBefore(a, b);
    aparent.insertBefore(b, asibling);
}

jQuery.fn.swapWith = function(to) {
	/**
	 * Swaps two DOM elements.
	 */
    return this.each(function() {
        var copy_to = $(to).clone(true);
        var copy_from = $(this).clone(true);
        $(to).replaceWith(copy_from);
        $(this).replaceWith(copy_to);
    });
};

function oc(a){
	/**
	 * For simulating python "in iterable"
	 * Can be used in if condition like:
	 * if(element in oc('elem1', 'elem2', 'elem3', ...))
	 */
	var o = {};
	
	for(var i=0; i<a.length; i++){
		o[a[i]]='';
	}
	
	return o;
}

function AddAnchor(anchor){
	/**
	 * Changes hash in url. 
	 * Used by jQuery tabs. 
	 */
	window.location.hash = anchor;
	return true
}

function chosen_render($elem, propag_onblur){
	/**
	 * This function  renders `$elem` as a chosen  select and  does some
	 * additional things like propagating classes, attributes and
	 * placing `$elem` behind rendered chosen element
	 * 
	 * `$elem` must have class chzn-select.
	 */
	var separator = default_separator
	var no_propagation_classes = Array("chzn-select", "chzn-done")
	
	if (propag_onblur == null)
		propag_onblur = true;
	
	// select id of element to be rendered
	var old_id = $elem.attr('id');
	
	// render chosen
	$elem.chosen();
	
	// select rendered chosen element
	$chzn_elem = $('#' + old_id + separator + 'chzn');
	
	// propagate onblur
	if(propag_onblur){
		onblur = $elem.attr('onblur');
		$chzn_elem.attr('onblur', onblur);
	}
	
	// propagate classes
	class_string = $elem.attr('class');
	classes = class_string.split(' ')
	
	// don't propagate element-specific classes
	$(no_propagation_classes).each(function(index, cls){
		i = $.inArray(cls, classes);
		if (i != -1){
			classes.splice(i, 1);
		}
	})
	// console.log('classes:', classes);
	
	// assign classes to chosen element
	for (cls in classes){
		$chzn_elem.addClass(classes[cls]);
	}
	
	// change hidden input position for correct error strings placement
	$elem.insertAfter($chzn_elem);
	//console.log('old_id', old_id, '$this', $this, '$chzn', $chzn);
}

function defval(arg, def) {
   return (typeof arg == 'undefined' ? def : arg);
}


function not_implemented(){
	alert('Not yet implemented');
}

//===========================
// prototype changes
//===========================
//var ParamArray = function (){asdf = 'asdf'};
//ParamArray.prototype = new Array();
//ParamArray
Array.prototype.push_jqparam = function (key, value){
	Array.prototype.push.apply(this, [{'name' : key, 'value' : value}]);
};

String.prototype.format = function(){
  var args = arguments;
  return this.replace(/{(\d+)}/g, function(match, number) { 
    return typeof args[number] != 'undefined'
      ? args[number]
      : match
    ;
  });
};

