// Jak cos nie ma konsoli (np IE) a debugujemy, to niech sie nie sypie
if (console === undefined)
    var console = 0;

if (!console) {// === undefined) {
	console = {
			log: function(message) {
			}
	};
}

if(typeof(String.prototype.trim) === "undefined")
{
    String.prototype.trim = function() 
    {
        return String(this).replace(/^\s+|\s+$/g, '');
    };
}

var quote = function(somestr) {
	return somestr.replace(/['"]/g, '\\$&');
}

function typeOf(value) {
    var s = typeof value;
    if (s === 'object') {
        if (!value)
            s = 'null';
        if (value instanceof Array)
            s = 'array';
    }
    return s;
}

var saveStatusList=["saveActive","saveDirty","saveFailed","saveSuccess"]

/*
 Resolvuje wlasne dodatki do selectorow:
 	^ - parent danego elementu
 Jesli nie wykryje dodatku, normalnie resolvuje selector.
*/
var resolve = function(scope, selector) {
	return devlib.resolve(scope, selector);
}

// UWAGA: do tego obiektu wkladamy wszystkie nowe funkcje (zeby byly w namespace devlib)
var devlib = {
	STATUS_OK: 0,
	STATUS_ERR: 1,
	ANIM_SPEED: 0, // default speed of animations
	FADE_SPEED: 'slow', // default speed of fade in/out (see also LOAD_FADE_SPEED for devlib.load fade speed)
	
	arrayContains: function(arr, val) {
		for (var idx = 0; idx < arr.length; idx ++)
			if (arr[idx] == val)
				return true;
		return false;	
	},
	
	/*
	 * arg[0] - klasa statusu z listy saveStatusList
	 * arg[0] - id formy podpietej pod zapis
	 *
	 * Nadaje odpowiednia klase elementowi o id = arg[1] + SaveStatus
	 *
	 * przyklady uzycia:
	 *  formSaveStatus("saveActive", "#task123132");
	 *  formSaveStatus("saveDirty", "#mail54");
	 *
	 */
	
	formSaveStatus: function(status, elem, data){
	    for (id in saveStatusList){
	        if(status==saveStatusList[id]){
	            $(elem + "SaveStatus").addClass(saveStatusList[id]);    
	        }else{
	            $(elem + "SaveStatus").removeClass(saveStatusList[id]);        
	        }
	    }
	},

	/*
	 * przyklady uzycia:
	 *  resolve(this, '^') -> this.parent()
	 *  resolve(this, '^^') -> this.parent().parent()
	 *  resolve(this, 'this > li') -> this.find('li')
	 */
	resolve: function(scope, selector) {
		if (selector.substring && selector.substring(0, 1) == '^') {
			scope = scope.parent();
			if (selector.length > 1)
				return devlib.resolve(scope, selector.substring(1));
			else
				return scope
		} else if (selector == 'next' || selector == '->') {
			return scope.next();
		} else if (selector == 'prev') {
			return scope.prev();
		} else if (selector == 'this') {
			return scope;
		} else if (selector.substring && selector.substring(0, 7) == 'this > ') {
			return $(selector.substring(7), scope);
		} else {
			return $(selector);
		}
	},

	inc: function (sel, num) {
		$(sel).each(function () {
			var val = parseInt($(this).text());
			val += (num === undefined ? 1 : num);
			$(this).text(val);
		});
	},
	
	dec: function (sel, num) {
		return devlib.inc(sel, (num === undefined ? -1 : -num));
	},
	
	randStrChars: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz",
	randstr: function (len) {
		var string_length = len;
		var randomstring = '';
		for (var i=0; i<string_length; i++) {
			var rnum = Math.floor(Math.random() * devlib.randStrChars.length);
			randomstring += devlib.randStrChars.substring(rnum,rnum+1);
		}
		return randomstring
	},
	
	tmpElem: function (id, classes) {
		var clstr = classes ? (' class="' + classes + '"') : '';
        return $('<div id="' + (id || devlib.randstr(10)) + '" style="display:none;"' + clstr + '></div>').appendTo('body');
        //return $('<div id="' + (id || devlib.randstr(10)) + '"' + clstr + '></div>').appendTo('body');
	},
	
	/*
	 * callback - callback to be called
	 * timeout - in ms
	 * 
	 * If you call singleTimeout again with the opts returned by it - it will cancel the previous
	 * timeout (if any) and start a new one.
	 */
	singleTimeout: function (opts) {
		if (!opts.fired) {
			// Cancel the previous timeout if any
			if (opts.timeoutId)
				clearTimeout(opts.timeoutId);
		} else
			// If we fired - refire
			opts.fired = false;

		// Install new timeout
		opts.timeoutId = setTimeout(function () { opts.fired = true; opts.callback() }, opts.timeout);			
		return opts;
	},

    delayedKey: '_timeoutId',

    delayedCall: function (el, func, delay) {
        var timeoutId = $(el).data(devlib.delayedKey);
        if (timeoutId)
            clearTimeout(timeoutId);

        $(el).data(devlib.delayedKey, setTimeout(func, delay || 500));
    },


	fadeOutRemove: function(elem, speed) {
		elem.fadeOut(speed || devlib.FADE_SPEED, function () {
			elem.remove();
		});
	},
	
	appendFadeIn: function(elem, data, speed) {
		if ($(data).is('tr')) {
			elem.append(data);
		} else {
			data.hide();
			elem.append(data);
			data.fadeIn();
		}
	},
	
	prependFadeIn: function(elem, data, speed) {
		if ($(data).is('tr')) {
			elem.prepend(data);
		} else {
			data.hide();
			elem.prepend(data);
			data.fadeIn();
		}
	},
	
	processCommands: function(me, _cmdstr, response) {
		return devlib.processAjaxResponse(me, response, _cmdstr);
	},

    get: function(url, post_data) {
        // Loads and processes response from URL returning data in devlib/ajax.py format.
        var callback_function = function(data) {
            if (typeof(data) == 'string')
                data = JSON.parse(data);
            devlib.processAjaxResponse($(this), data);
        }

        if (post_data)
            $.post(url, post_data, callback_function);
        else
            $.get(url, callback_function);
    },
    
	processAjaxResponse: function(me, response, _cmdstr) {
		// operations on elements
		var hide = function(elem, speed) {
			devlib.resolve(me, elem).hide(speed || devlib.ANIM_SPEED);
		}
		var show = function(elem, speed) {
			devlib.resolve(me, elem).show(speed || devlib.ANIM_SPEED);
		}
		var replaceWith = function(elem, data) {
			data.hide();
			devlib.resolve(me, elem).replaceWith(data);
			data.fadeIn(devlib.ANIM_SPEED);
		}
		var html = function(elem, data) {
			devlib.resolve(me, elem).html(data);
		}
		var toggle = function(elem, speed) {
			devlib.resolve(me, elem).toggle(speed || devlib.ANIM_SPEED);
		}
		var toggle_ffi = function(elem, speed) {
            var x = devlib.resolve(me, elem);
			x.toggle(speed || devlib.ANIM_SPEED, function(){devlib.ffi(x)});
		}
		var append = function(elem, data) {
			devlib.resolve(me, elem).append(data);
		}
		var appendFadeIn = function(elem, data, speed) {
			var tgt = devlib.resolve(me, elem);
			devlib.appendFadeIn(tgt, data, speed)
		}
		var prependFadeIn = function(elem, data, speed) {
			data.hide();
			devlib.resolve(me, elem).prepend(data);
			data.fadeIn(speed || devlib.FADE_SPEED);
		}
		var fadeOutRemove = function(elem, speed) {
			var tgt = devlib.resolve(me, elem);
			devlib.fadeOutRemove(tgt, speed);
		}
		var prepend = function(elem, data) {
			devlib.resolve(me, elem).prepend(data);
		}
		var focus = function(elem) {
			devlib.resolve(me, elem).focus();
		}
		// Focus first input
		var ffi = function(elem) {
			devlib.ffi(devlib.resolve(me, elem));
		}
		
		// Display form errors returned by the server
		var showFormErrors = function(elem) {
			var myform = devlib.resolve(me, elem);
			myform.find('.errorlist').remove();
			var errors = response.json;
            if (errors['__all__'])
                myform.before(errors['__all__']);
			for (var k in errors) {
				var label = myform.find('label[for=id_' + k + ']');
                var p = label.parents('p').eq(0);
                if (p && p.hasClass('errors-before'))
                    p.before(errors[k]);
                else
                    label.after(errors[k]);
			}
		}

		// Display form errors returned by the server
		var showFormErrorsBootstrap = function(elem) {
			var myform = devlib.resolve(me, elem);
			myform.find('.help-inline').remove();
            myform.find('.clearfix').removeClass('error');
			var errors = response.json;
            if (errors['__all__'])
                myform.before(errors['__all__']);
			for (var k in errors) {
				var label = myform.find('#id_' + k);
                label.after('<span class="help-inline">' + errors[k] + '</span>');
                label.parents('.clearfix:first').addClass('error');
			}
		}


		if (response && response.html && $.trim(response.html))
			response.html = $($.trim(response.html));
		if (response && response.json) {
			response.json = eval(response.json);
		}
		//console.log('evaluating: ' + _cmdstr);
		if (_cmdstr) {
            console.log('processing ' + _cmdstr);
			try {
				eval(_cmdstr);
			} catch (err) {
				console.log('error: ' + err);
			}
        }
			
		// We also evalute the response JS if any was provided
		if (response) {
			if (response.js) {
				//console.log('JS:' + response.js);
				eval(response.js);
			}
			if (response.html) {
				devlib.runLib(response.html);
			}
		}
	},
	
	notify: function(msg, text, time) {
		$.gritter.add({ title: msg, text: text || ' ', time: time || 6000 });
	},
	
	// Focus first input
	ffi: function (scope) {
		$(':input:visible:enabled:first', scope).focus();
	},

    clearform: function(scope) {
		$(':input[type!=hidden][type!=button][type!=submit]', scope).val('');
        $('.errorlist', scope).remove();
    },

	reload: function() {
		location.href = location.href;
	},

    // Togglebutton start!

    activeToggleData: function (val) {
        var tdata = window[val];
        for (k in tdata) {
            var o = tdata[k];
            if (o.active) {
                return o;
            }
        }
    },

    otherToggleData: function (val) {
        var tdata = window[val];
        for (k in tdata) {
            var o = tdata[k];
            if (!o.active) {
                return o;
            }
        }
    },

    iterateToggleData: function (val) {
        var a = devlib.activeToggleData(val);
        var o = devlib.otherToggleData(val);
        a.active = false;
        o.active = true;
    },

    decorateToggleButton: function (btn, toggling) {
        var tdata = devlib.activeToggleData(toggling);
        btn.text(tdata.text);
        btn.attr('href', tdata.url);
        btn.attr('data-loading-text', tdata.loading);
    },

    // Togglebutton end!

	runLib: function(scope) {
		$('.hideonload', scope).hide();

        var confirmHandler = function(event) {
			if (!confirm($(this).attr('confirm'))){
				event.stopImmediatePropagation();
				return false;
			}
		}

        $('a.async2', scope).each(function () {
            var toggling = $(this).attr('toggling');
            if (toggling) {
                devlib.decorateToggleButton($(this), toggling);
            }
        });

		// Display a confirmation question when we click on this element
		$('a[confirm]', scope).each(function () {
            if (!$(this).hasClass('async2')) {
                $(this).click(confirmHandler);
            }
        });
        $('input[confirm][type=submit]', scope).click(confirmHandler);
		
		$("a[click]", scope).click(function () {
			var click = $(this).attr('click');
			if ((typeof click == 'object') || (typeof click == 'function'))
				return true;
			devlib.processCommands($(this), click);
			return false;
		});

	    $('.growl', scope).each(function () {
	    	var header = $('.header', this).html() || $(this).html();
	    	var body = $('.body', this).html();
	    	devlib.notify(header, body || ' ');
	    });

	    // Form submission
	    $("form.async2", scope).each(function () {
	    	var myform = $(this);
			var beforecb = eval($(this).attr('beforecb'));
			var failurejs = $(this).attr('failure');
			var handleckedit = $(this).attr('handle-ckedit');

			var opts = {
		        	   dataType: 'json',
					   beforeSubmit: beforecb || function(){return true;},
		        	   success: function (resp) {
		        			if (resp.status == 0) {
		        	        	devlib.processCommands(myform, myform.attr('success'), resp);
		    					myform.find('.errorlist').remove();
		        			} else {
		        				// By default we show errors in the form
		        	        	devlib.processCommands(myform, failurejs || 'showFormErrors("this")', resp);
		        			}
		        	   }
		    };
			
			if (handleckedit)
				opts.beforeSubmit = function (data, form, options) {
					for (key in data) {
						if (data[key].name == handleckedit) 
							data[key].value = CKEDITOR.instances['id_' + handleckedit].getData();
					}
				}
			
	        $(this).ajaxForm(opts);
	    });   
	    
	    // Show some element while we hover over another
		$('div[hover-show],span[hover-show]', scope).hover(
		        function () {
		        	resolve($(this), $(this).attr('hover-show')).show();
		        },
		        function () {
		        	resolve($(this), $(this).attr('hover-show')).hide();
		        }
		);
        
	    $('div[hover-show],span[hover-show]', scope).each(function() {
	    	resolve($(this), $(this).attr('hover-show')).hide();
	    });

		// Focus the selected element
		$('.focusnow', scope).focus();

		// Externally editable by a click on some other element
	    $("span[editable-external]", scope).each(function() {
	        $(this).editable($(this).attr('editable-external'), { 
				        event  : 'dblclick',
				        type   : 'text',
				        data   : $(this).attr('editable-data'),
				        name   : 'value',
				        submitdata: {'oid': $(this).attr('editable-oid')},
				        submit : 'OK'
	        });
	    });
	    
	    $("span[editable],div[editable]", scope).each(function() {
	    	var submitdata = {
	    			'oid': $(this).attr('editable-oid'), 
	    			'varname': $(this).attr('editable-name') || 'value'
	    	};
	    	
	    	var options = { 
	    			indicator : "<img src='/static/devlib/jeditable/img/indicator.gif'>",    			
			        event  : $(this).attr('editable-event') || 'click',
			        type   : $(this).attr('editable-type') || 'text',
			        name   : $(this).attr('editable-name') || 'value',
			        rows   : 10,
			        cols   : 80,
			        tooltip: $(this).attr('editable-tooltip')||undefined,
			        submitdata: submitdata,
			        submit : devlib.jeditableSaveText || 'Save',
			        cancel : devlib.jeditableCancelText || 'Cancel',
			        or : devlib.jeditableOrText || 'or',
			        select : true,
			        onblur : $(this).attr('editable-onblur') || 'cancel',
			        csseditclass: $(this).attr('csseditclass') || undefined,
			        ckeditor: { customConfig : '/static/js/ckeditor_config.js' },
                    ajaxoptions: { dataType: 'json' },
                    callback: function(result, settings) {
                        $(this).html(result.html);
                        devlib.processCommands(this, '', result);

                        if(result.json.message) {
                            if(result.json.title)
                                devlib.notify(result.json.title, result.json.message);
                            else
                                devlib.notify(result.json.message);
                        }
                        if(result.status == 0)
                            $(this).trigger('saved', [result.html, settings]);
                    },
                    data : function(value, settings) {
						if ($(this).attr('editable-type') == 'textarea')
							return $('<div />').html(value.replace(/<br>/gi, '#BR#')).text().replace(/#BR#/gi, '\n');
						return $('<div />').html(value).text();
					}
	    	};

	    	
	    	var loadurl = $(this).attr('editable-loadurl');
	    	if (loadurl) {
	    		options.loadurl = loadurl;
	    	}
	    	
	    	if ($(this).attr('editable-placeholder') != undefined) {
	    		options.placeholder = $(this).attr('editable-placeholder');
	    	}
	    	
	    	// Data can be raw json data or it can be the ID of the element containing the data
	    	if ($(this).attr('editable-data')) {
	    		options.data = $(this).attr('editable-data');
	    	} else if ($(this).attr('editable-datavar')) {
	    		options.data = eval($(this).attr('editable-datavar'));
	    	}
	    	
            $(this).parent('span.jeditable-options[options]').each(function() {
                eval('var addme = ' + $(this).attr('options') + ';')
                options = $.extend(options, addme);
            });

	        $(this).editable($(this).attr('editable'), options);
            if (options.onsave)
                $(this).bind('saved', options.onsave);
	    });	

		/*
        try { 
            $("span[editable-widget=JTextArea], span[editable-widget=JDynTextArea]").css('white-space', 'pre-wrap');
        }
        catch(er) {
            // f*ck ie7
        }
		*/

	    $("a[edits-element]", scope).each(function () {
	        $(this).bind('click', function() {
	            $($(this).attr('edits-element')).trigger($(this).attr('edit-event') || 'dblclick');
	            return false;
	        });
	    });
	    
	    $("input[autocomplete]", scope).each(function () {
	    	// Creates an AJAX autocompleted field, if you provide 'jumpto' then data returned
	    	// as the entries needs to provide a 'text' field and a 'url' field.  And after
	    	// picking an entry the user will be redirected to the entries url.

            var url = $(this).attr('autocomplete');
            if (url == 'off')
                return;
	    	var jumpto = $(this).attr('jumpto');
	    	var opts = {};
	    	
	    	if (jumpto) {
	    		opts.formatItem = function(item) {
	    			return item.text;
	    		}
	    	}
	    	
	    	var ac = $(this).autocomplete($(this).attr('autocomplete'), opts);
	    	
	    	if (jumpto) {
	    		ac.result(function (event, item) {
	    			location.href = item.url;
	    		});
	    	}
	    });

	    // Ajax loader links - will load given HTML from given URL to given element 
	    $("a[load-from]", scope).click(function () {
	        var source = $(this).attr('load-from');
	        var destination = $(this).attr('load-to');
	        $(destination).load(source);
	        return false;
	    });
	    
	    $("div[load-from]", scope).each(function(){
	    	var source = $(this).attr('load-from');
	    	if ($(this).attr('js-url') == undefined){
	    		$(this).load(source);
	    	}else{
	        	$(this).load(source, callback=function(){
	        		$.getScript($(this).attr('js-url'), function(){})
	        	});
	    	}
	    	return false;
	    });
	    
	    // Form submission
	    $("form.async", scope).each(function () {
	        $(this).ajaxForm({
	        	   dataType: 'script'
	        });
	    });
	    
	    // Form submission
	    $("form.asyncvalidated", scope).each(function () {
	    	var myform = $(this);
	        $(this).ajaxForm({
	        	   dataType: 'json',
	        	   success: function (resp) {
	        			if (resp.status == 0) {
	        				myform.hide();
	        				myform.clearForm();
	        				resolve(myform, myform.attr('result-append')).append(resp.html);
	        			} else {
	    					myform.find('.errorlist').remove();
	        				for (var k in resp.errors)
	        					myform.find('label[for=id_' + k + ']').after(resp.errors[k]);
	        			}
	        	   }
	        });
	    });    

	    if (jQuery.datepicker) {
	    	$(".date-picker", scope).each(function() {
				$(this).datepicker({
	    			changeMonth: true,
	    			changeYear: true,
	    			yearRange: '-70:+10',
	    			dateFormat: $(this).attr('format') || 'mm/dd/yy'
				});
	    	});
	    }

	    if ($.fcbkcomplete)
		    $("select[fbcomplete]", scope).each(function () {
		    	$(this).fcbkcomplete({
			        json_url: $(this).attr('fbcomplete'),
			        cache: false,
			        filter_case: false,
			        filter_hide: true,
					firstselected: true,
			        //onremove: "testme",
					//onselect: "testme",
			        filter_selected: true,
			        newel: false        
		    	});
		    });
	    
	    //dialog do wyswietlania informacji
	    $('div.dialog-msg', scope).each(function(){
	    	$(this).dialog({ 
	    		modal: true,
	    		height: 50,
	    		minHeight: 70
	    	});
	    });
	    
		$("a[click-hide]", scope).click(function () {
			$($(this).attr('click-hide')).hide();
			return false;
		});
		
	    $('a[click-toggle]', scope).each(function() {
	    	//alert('hiding ' + $(this).attr('click-toggle'));
	        resolve($(this), $(this).attr('click-toggle')).hide();
	    });
		
		$('a[click-toggle]', scope).click(function() {
			resolve($(this), $(this).attr('click-toggle')).toggle();
			return false;
		});
		

	    $('a[click-slide]', scope).each(function() {
	        $($(this).attr('click-slide')).hide();
	    });
		$('a[click-slide]', scope).click(function() {
			$($(this).attr('click-slide')).slideToggle();
			return false;
		});
		
		$('a[click-focus]', scope).click(function() {
			resolve($(this), $(this).attr('click-focus')).focus();
		});
		
		$("form[save-drafts]:visible", scope).keypress(function() {
		    devlib.formSaveStatus("saveDirty", '#' + $(this).attr('id'));
		});

		
	    $('input[focus-show],textarea[focus-show]', scope).each(function() {
	        $($(this).attr('focus-show')).hide();
	    });
		
		$('input.select', scope).click(function() {
			$(this).focus();
			$(this).select();
		});

		$("a[click-replace-with]", scope).click(function () {
			$(this).replaceWith($(this).attr('click-replace-with'));
			return false;
		});
		
		$("a[click-remove]", scope).live('click', function () {
			resolve($(this), $(this).attr('click-remove')).remove();
			return false;
		});
	    
		if ($('.any').autoResize) {
			$('.auto-resize', scope).autoResize({
				 limit: 250, 
				 extraSpace: 30
			});
		}
		
		/*
		$("select[save-choice]", scope).change(function () {
			$("select option:selected", this).each(function () { 
	            alert($(this).text());
	        }); 
		});
		*/
		$("form.valid-form", scope).each(function(){
			$(this).validate();
		});
		
		// from jquery.form.default-value in devlib/media
		if (typeof installDefaultValue == 'function') {
			installDefaultValue(scope);
		}

		$('input[submit-not-null]').keyup(function(){
			if ($(this).val()==$(this).attr('null-value')||$(this).val()==''){
				$($(this).attr('submit-not-null')).hide();
			}
			else{
				$($(this).attr('submit-not-null')).show();
			}
		});
		
		$('input[type=checkbox][post-url]').click(function() {
		  	$.post($(this).attr('post-url'),{data: $(this).attr('checked')}, function(news) {
		    	if(news == 'OK') {
		    		$(this).css('background-color', '#b6fd90');
		    	};
		    });
		 });
		
		if (typeof DISABLE_ALL_BUTTONS_ON_SUBMIT != 'undefined') {
			$('form').submit(function() {
			    // On submit disable its submit button
			    $('input[type=submit]', this).attr('disabled', 'disabled').val('Wait..');
			});
		}
		
		$("div.overlay").each(function(){
			opts= {'api':true};
						
			if ($(this).attr('left')){
				opts.left = eval($(this).attr('left'));
			}
			
			if ($(this).attr('lib')){
				eval($(this).attr('lib'))($(this));
			}
			$(this).overlay(opts).load();
		})
				
		/*
		$("form[save-drafts]", scope).each(function () {
			var url = $(this).attr('save-drafts');
			var form = $(this);
			var intervalFunc = function () {
				devlib.saveDraft(form, url);
				$('.savelinkactive').hide();
				$('.savelinkinactive').show();
			}
			setInterval(intervalFunc, 2000);
		});
		*/

		$("input[null-value], textarea[null-value]", scope).each(function (){
			if ($(this).val()!=$(this).attr('null-value')) {
				$(this).val($(this).attr('null-value'));
			};
			
			$(this).focus(function(){
				if ($(this).val() == $(this).attr("null-value")){
					$(this).val('');
				};
			});
			$(this).blur(function(){
				if ($(this).val()==''){
					$(this).val($(this).attr('null-value'));
				};
			});
		});

		if ($.fn.ThreeDots) {
	        $(".ellipsis", scope).parent().ThreeDots({
	            max_rows: 1,
	            alt_text_t: true,
	            alt_text_e: true,
	            text_span_class: 'ellipsis'
	        });
		}
		
		if ($.fn.jqm) {
			// maybe we should use jquery ui dialog?
			$('a[show-overlay]', scope).each(function () {
				var elem = $(this).attr('show-overlay');
				var url = $(this).attr('overlay-url');
				
				opts = {};
				if (url) {
					opts.onShow = function (hash) {
						devlib.load({ url: url, selector: hash.w });
						hash.w.show();
					}
				}
				
				$(elem).jqm(opts);
				$(elem).jqmAddTrigger($(this));
			});
		}

        $('a[rel=external]', scope).click(function(){
            window.open($(this).attr('href'));
            return false; 
        });

        $('input[type=checkbox].async2').click(function () {
            var url = $(this).attr('url');
            var onurl = $(this).attr('onurl') || url;
            var offurl = $(this).attr('offurl') || url;

            devlib.get($(this).is(':checked') ? onurl : offurl);
        });

		for (hookidx in devlib.runLibHooks) {
			devlib.runLibHooks[hookidx](scope);
		}
	    
	},

    update: function (sel) {
        devlib.load({
            method: 'replace',
            selector: sel,
            url: window.location.href,
            dataSelector: sel,
        });
    },

	draftStorage: {},
	saveDraft: function(form, url) {
		previous_data = devlib.draftStorage[url];
		current_data = form.serialize();

		// Initialize if undefined
		if (!(url in devlib.draftStorage)) {
			devlib.draftStorage[url] = current_data;
			return;
		}
		

		if (previous_data != current_data) {
		    devlib.formSaveStatus("saveActive", '#' + $(form).attr('id'));
			//console.log('### DATA');
			//console.log(previous_data);
			//console.log(current_data);
			devlib.draftStorage[url] = current_data;
			$.post(url, form.serializeArray());
			devlib.formSaveStatus("saveSuccess", '#' + $(form).attr('id')); 
			//devlib.formSaved('#' + $(form).attr('id'));
		}
	},
	
	DRAFT_SAVER_INTERVAL: 2000,
	draftSaver: function() {
		$("form[save-drafts]:visible").each(function () {
			var url = $(this).attr('save-drafts');
			var form = $(this);
			
			devlib.saveDraft(form, url);
			$('.savelinkactive').hide();
			$('.savelinkinactive').show();
		});
		
		setTimeout(devlib.draftSaver, devlib.DRAFT_SAVER_INTERVAL);
	},
	
	runLibHooks: [],

	addLibHook: function(func) {
		// installs a hook to be ran alwyas when runLib is ran
		devlib.runLibHooks.push(func);
	},

    installLive: function() {
        $("a.async2").live('click', function () {
//            console.log("in click handler");
            var before = $(this).attr('before');
            var success = $(this).attr('success');
            var failure = $(this).attr('failure');
            var callback = $(this).attr('callback');
            var post_data = $(this).attr('post-data');
            var refresh = $(this).attr('refresh');
            var confirm_msg = $(this).attr('confirm');
            var toggling = $(this).attr('toggling');

            var url = $(this).attr('href');
            var aelem = $(this);

            if (confirm_msg && !confirm(typeof gettext === 'undefined' ? confirm_msg : gettext(confirm_msg))) {
				event.stopImmediatePropagation();
				return false;
			}
            
            if (before)
                eval(before);

            var callback_function = function(data) {
                if (toggling) {
                    devlib.iterateToggleData(toggling);
                    devlib.decorateToggleButton(aelem, toggling);
                }

                if (typeof data == 'string') {
                    data = JSON.parse(data);
                }
                devlib.processCommands(aelem, (data.status == devlib.STATUS_OK) ? success : failure, data);
                if(refresh == 'yes'){
                    self.location="";
                }
            }

            if (post_data)
                $.post(url, post_data, callback_function)
            else
                $.get(url, callback_function);

            return false;
        });
    },
	
	myLoad: function (selector, url, dataSelector, method) {
		// A version of the jquery $(..).load but installing all library callbacks on the returned data.
		return devlib.load({
			url: url,
			selector: selector,
			dataSelector: dataSelector,
			method: method
		});
	},

	LOAD_FADE_SPEED: 300,
    LOAD_DEFAULT_EFFECT: 'mask',
	load: function (opts) {
		/* A version of the jquery $(..).load but installing all library callbacks on the returned data.
		
		Options:
		  required:
			url - URL of the request
			selector - local selector whose content will be replaced
			
		  optional:
			method - replacement method (set -> .html (default), append -> .append, replace -> .replaceWith)
			type - GET or POST
			effect - mask, fade or none (default mask)
			dataSelector - if specified it will use this selector on data loaded from server and 
				process only the result
			data - data passed to the server (dictionary or string)
			callback - called after the content has been loaded and processed
			
			- startujemy fadeout na rzeczonym contencie
			- callback dajemy do fadeout ktory zawola callback podmiany contentu jesli bedzie w ogole dostepny
			- w callbacku z AJAX sprawdzamy czy fadeout sie skonczyl, jesli nie to on ma zrobic robote
			  a jak sie skonczyl to my
		*/
		var effects = {
			mask: {
				hideOld: function (sel, donecb) {
					if ($.fn.mask)
						$(sel).mask('Loading..');
					donecb();
				},
				showNew: function (sel) {
					if ($.fn.mask)
						$(sel).unmask();
				}
			},
			
			fade: {
				hideOld: function (sel, donecb) {
					$(sel).fadeOut(devlib.LOAD_FADE_SPEED, donecb);
				},
				showNew: function (sel) {
					$(sel).fadeIn(devlib.LOAD_FADE_SPEED);
				}
			},
			
			none: {
				hideOld: function (sel, donecb) { donecb() },
				showNew: function (sel) {}
			}
		}
		
		opts = $.extend({}, {
			effect: devlib.LOAD_DEFAULT_EFFECT
		}, opts);
		
		if (typeOf(opts.selector) != 'array')
			opts.selector = [ opts.selector ];
		if (opts.dataSelector) {
			if (typeOf(opts.dataSelector) != 'array')
				opts.dataSelector = [ opts.dataSelector ];
		} else
			opts.dataSelector = [];

		if (opts.dataSelector.length && (opts.selector.length != opts.dataSelector.length))
			console.log('number of selectors and dataSelectors should be equal!');
		
		var fx = typeof opts.effect === 'string' ? effects[opts.effect] : opts.effect;
			
		function placeData(data) {
			$.each(opts.selector, function (idx, sel) {
                var el = $('<div></div>');
                el[0].innerHTML = data;

                var script = $('script', el).remove();
                //var el = $('<div>' + data + '</div>');
                //var script = el.filter('script');

                var html = opts.dataSelector.length ? $(opts.dataSelector[idx], el) : $(el);

                if (opts.method == 'append')
                        $(sel).append(html);
                else if (!opts.method || opts.method == 'set')
                        $(sel).html(html);
                else if (opts.method == 'replace')
                        $(sel).replaceWith(html);

                if (!opts.ignoreScripts) {
                    script.each(function() {
                        // Fuck these scripts!
                        //if ($(this).attr('src'))
                        //    $.ajax({async:false,type:"POST",url:$(this).attr('src'),data:null,dataType:'script'});
                        if ($(this).attr('type') == 'text/javascript')
                            $.globalEval(this.text || this.textContent || this.innerHTML || '');
                    });
                }
                fx.showNew($(sel));
                devlib.runLib($(sel));
			});
                        
			if (opts.callback)
				opts.callback();
		}
		
		// Hide the current data and when finished - place new data in
		var state = {
				data: null,
				hideFinished: false
		}
		
		function hideFinished() {
			state.hideFinished = true;
			if (state.data)
				placeData(state.data);
		}

		$.each(opts.selector, function (_k, sel) {
			fx.hideOld($(sel), hideFinished);
		});

		$.ajax({
			url: opts.url,
			type: opts.type || (opts.data ? 'POST' : 'GET'),
			dataType: "html",
			data: opts.data,
			success: function(data) {
                try {
                    var el = data;
                    if (state.hideFinished) {
                        placeData(el);
                    } else {
                        state.data = el;
                    }
                } catch (err) {
                    console.log(err.description);
                    console.log(err);
                }
			}
		});
	},
	
	addSelectOption: function (selector, name, value) {
			$(selector).append('<option value="' + value + '" selected="1">' + name + '</option>');
	},
	
	/**
	 * url - URL for fetching tree nodes
	 * selector - location of the tree
	 * drop_finish - func that gets data.o (dragged), data.r (drop target)
	 */
	makeJSTree: function (options, direct_options) {
		var plugins = ['themes', 'json_data'];
		
		var dataFunc = function (node) {
			//console.log(node);
			return options.url + (node != -1 ? node.attr('oid') : 0) + '/';
		}
		var to = {
			"json_data": {/*
				"data": [{
					data: "chuj",
					attr: { oid: '1'},
					state: "closed",
				}],*/
				"ajax": {
					url: dataFunc
				}
			},
			/*
			"themes": {
				theme: 'apple'
			},*/
			"plugins": plugins,
			"initially_open": options.initially_open
		};
		
		if (options.on_move) {
			plugins.push('dnd');
			/*to.dnd = {
				'drop_finish': options.drop_finish 
			}*/
		}
		
		$(options.selector).jstree($.extend(to, direct_options));
		
		if (options.on_move)
		   	$(options.selector).bind('move_node.jstree', function (ev, data) {
		   		// node
		   		//console.log(data.rslt.o);
		   		var node = data.rslt.o;
		   		// reference node
		   		//console.log(data.rslt.r);
		   		var ref = data.rslt.r;
		   		// .p
		   		var move_type = data.rslt.p;
		   		options.on_move(node, ref, move_type);
				//console.log('/topic/change_position/' + node.attr('oid') + '/' + move_type + '/' + ref.attr('oid') + '/');
		   	});
	},

	wordwrap: function(str, int_width, str_break, cut) {
	    // http://kevin.vanzonneveld.net
	    // +   original by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
	    // +   improved by: Nick Callen
	    // +    revised by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
	    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
	    // +   improved by: Sakimori
	    // +   bugfixed by: Michael Grier
	    // *     example 1: wordwrap('Kevin van Zonneveld', 6, '|', true);
	    // *     returns 1: 'Kevin |van |Zonnev|eld'
	    // *     example 2: wordwrap('The quick brown fox jumped over the lazy dog.', 20, '<br />\n');
	    // *     returns 2: 'The quick brown fox <br />\njumped over the lazy<br />\n dog.'
	    // *     example 3: wordwrap('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.');
	    // *     returns 3: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod \ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim \nveniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea \ncommodo consequat.'

	    // PHP Defaults
	    var m = ((arguments.length >= 2) ? arguments[1] : 75   );
	    var b = ((arguments.length >= 3) ? arguments[2] : "\n" );
	    var c = ((arguments.length >= 4) ? arguments[3] : false);

	    var i, j, l, s, r;

	    str += '';

	    if (m < 1) {
	        return str;
	    }

	    for (i = -1, l = (r = str.split(/\r\n|\n|\r/)).length; ++i < l; r[i] += s) {
	        for (s = r[i], r[i] = ""; s.length > m; r[i] += s.slice(0, j) + ((s = s.slice(j)).length ? b : "")){
	            j = c == 2 || (j = s.slice(0, m + 1).match(/\S*(\s)?$/))[1] ? m : j.input.length - j[0].length || c == 1 && m || j.input.length + (j = s.slice(m).match(/^\S*/)).input.length;
	        }
	    }
	    
	    return r.join("\n");
	}
}

// Kompatybilnosc wstecz
var addLibHook = devlib.addLibHook;
var runLib = devlib.runLib;
var myLoad = devlib.myLoad;

$(document).ready(function() {	
	devlib.runLib(document.body);
	devlib.installLive();
});

