// Root namespace(s) for exfile - the new way

var Exfile = {
	Core: {},
	App: {},
	Vfs: {},
	User: {}
};

Exfile.Core.Ajax = {

	updateForm: function(element, url, form, options) {
		if (!options)
			options = {};
		options.postBody = Form.serialize(form);
		this.update(element, url, options);
	},

	updatePost: function(element, url, args, options) {
		if (!options)
			options = {};
		options.postBody = Exfile.Core.Util.serialize(args);
		this.update(element, url, options);
	},

	update: function(element, url, options) {
		if (!options)
			options = {};
		if (!options.onFailure)
			options.onFailure = Exfile.Core.Ajax.onUpdateError.bind(Exfile.Core.Ajax);
		new Ajax.Updater($(element), url, options);
	},

	request: function(url, options) {
		if (!options.onFailure)
			options.onFailure = Exfile.Core.Ajax.onRequestError.bind(Exfile.Core.Ajax);
		new Ajax.Request(url, options);
	},

	onUpdateError: function(res) {
		Exfile.Core.Error.handle('Core.Ajax.update', res);
	},
	onRequestError: function(res) {
		Exfile.Core.Error.handle('Core.Ajax.request', res);
	}

};

Exfile.Core.Error = {
	handle: function(caller, data) {
		if (data && data.status == 401) {
			rpc.handle_timeout();
		} else if (data && data.status == 402) {
			rpc.handle_renew();
		} else {
			debug("Unhandled error for: " + caller);
			debug("Core.Error.handle: " + caller + ", data follows: ");
			debug(data);
		}
	}
};

Exfile.Core.Util = {

	serialize: function(data) {
		var str = "";
		var started = false;
		for (var key in data) {
			if ( typeof(data[key]) == 'function' )
				continue;
			// @todo: escape
			if (started)
				str += "&";
			else
				started = true;
			str += key + "=" + data[key];
		}
		return str;
	},

	isTextNode: function(elem) {
		if (elem.nodeType == elem.TEXT_NODE)
			return true;
		return false;
	},

	hasClass: function(element, classname) {
		var classes = element.className.split(' ');
		for ( var i = 0; i < classes.length; i++ ) {
			if ( classes[i] == classname ) {
				return true;
			}
		}
		return false;
	},

	// @todo: fixme
	addClass: function(element, classname) {
		element.className = add_class(element.className, classname);
	},
	removeClass: function(element, classname) {
		element.className = remove_class(element.className, classname);
	},
        splitEmails: function(str) {
                var data = [];
                var tmp1 = str.split(',');
                for (var i=0; i < tmp1.length; i++) {
                        var tmp2 = tmp1[i].split(';');
                        for(var j=0; j < tmp2.length; j++) {
                                if (tmp2[j] != '')
                                        data[data.length] = tmp2[j];
                        }
                }
                debug('split emails: ' + str + ' into...:'); debug(data);
                return data;
        }
};

Exfile.Core.Input = {

	text: function(opt) {
		return this.render('textarea', opt);
	},
	string: function(opt) {
		return this.render('input', opt, 'text');
	},
	password: function(opt) {
		return this.render('input', opt, 'password');
	},
	hidden: function(opt) {
		return this.render('input', opt, 'hidden');
	},

	render: function(tag, opt, type) {

		if (!opt)
			opt = {};
		if (tag == 'textarea')
			opt['hasValueAttrib'] = false;
		else
			opt['hasValueAttrib'] = true;
		if (type)
			opt['type'] = type;

		var str = '<' + tag + ' ' + this.getAttrib(opt);
		if (!opt['hasValueAttrib'])
			str += '>' + opt.value + '</' + tag + '>';
		else
			str += '/>';

		return str;
	},

	getAttrib: function(opt) {
		var keys = ['id', 'class', 'href', 'onclick', 'onsubmit', 'onchange', 'onfocus', 'onblur'];
		if (opt.hasValueAttrib)
			keys[keys.length] = 'value';
		var str = '';
		opt = this.expandOpt(opt);
		for (var i=0; i < keys.length; i++) {
			if (!opt[ keys[i] ])
				continue;
			if (str != '')
				str += ' ';
			str += keys[i] + '="' + opt[ keys[i] ] + '"';
		}
		return str;
	},

	expandOpt: function(opt) {
		if (!opt['no_disable_hotkeys']) {
			opt['onfocus'] = 'hotkeys.disable()';
			opt['onblur'] = 'hotkeys.enable()';
		}
		return opt;
	}
};

Exfile.Edit = {

        open: function(url, id) {
                ctl.rsh_set('ed', id, url);
        },

        _open: function(url, id) {
                url += id + '&out=flake';
                var opt = { evalScripts: false, keepScripts: true };
                Exfile.Core.Ajax.update($('fileItem'), url, opt);
        }

};

Exfile.Edit.Text = {
        onSubmit: function(id, form) {
                var data = '';
                for (var i = 0; i < form.elements.length; i++) {
                        var elem = form.elements[i];
                        if (elem.name == 'data') {
                                data = elem.value;
                        }
                }
                var cb = function(res){ Exfile.Edit.Text.cbSubmit(res, id); };
                rpc.call(cb, "Text.update", id, data);
        },
        cbSubmit: function(res, id) {
                if (!res.success) {
                        ctl.gui.display_vfs_error('update_text', res);
                        return;
                }
                history.back();
        },
        onCancel: function(id) {
                history.back();
        }
};

Exfile.Core.Poll = {

	handle: null,
	frequency: 8000,
	enabled: true,         // option to temporary disable without actually unregistering
	gotArgs: false,        // another enable/disable switch, true if we have args
	polling: false,        // polling right now?
	autobind: true,        // register after first poll?
	service: 'Poll.poll',  // backend service
	args: {},              // args to backend, what to poll

	// enable (mixed) / disable (null) polling of something
	setArg: function(key, val) {
		if (val == null)
			delete this.args[key];
		else
			this.args[key] = val;
		this.onUpdateArgs();
	},
	setArgs: function(args) {
		this.args = args;
		this.onUpdateArgs();
	},

	onUpdateArgs: function() {
		var n = 0;
		for(var i in this.args) {
			if (typeof(this.args[i]) == 'function')
				continue;
			n++;
		}
		if (n > 0)
			this.gotArgs = true;
		else
			this.gotArgs = false;
		trace('Poll.onUpdateArgs: ' + this.gotArgs, this.args);
	},

	// register poller unless already registered
	touch: function() {
		trace('Poll.touch');
		if (this.handle)
			return;
		if (this.polling)
			this.register();
		else {
			this.autobind = true;
			this.poll();
		}
	},

	// start polling periodically
	register: function() {
		trace('Poll.register');
		this.handle = setInterval(this.poll.bind(this), this.frequency);
	},

	// stop polling
	unregister: function() {
		trace('Poll.unregister');
		if (this.handle != null)
			clearInterval(this.handle);
	},

	enable: function() { this.enabled = true; }, // default
	disable: function() { this.endabled = false; },

	// poll unless already polling
	poll: function() {
		if (!this.enabled || !this.gotArgs || this.polling)
			return;
		trace_poll('Poll.poll: poll started');
		try {
			this.polling = true;
			rpc.call(this.pollCb.bind(this), this.service, this.args);
		} catch (e) {
			this.polling = false;
			debug('Poll.poll: poll stopped on exception:', e);
		}
	},

	// handle polled data and optionally register if autobind
	pollCb: function(result) {
		trace_poll('Poll.pollCb: ', result);
		try {
			var change = false;
			if ( result['invitations'] > 0 ) {
				this.onInvitations(result['invitations']);
				change = true;
			}
			if ( result['preview'] ) {
				this.onPreview(result['preview']);
				change = true;
			}
			if ( result['stats'] ) {
				this.onStats(result['stats']);
			}
			if (change)
				this.onChange(result)
	
			if (this.autobind && !this.handle)
				this.register();
		} finally {
			this.polling = false;
			trace_poll('Poll.pollCb: poll finished');
		}
	},

	// handlers for polled data

	onInvitations: function(data) {
		trace('Poll.onInvitations: ', data);
		if ( ctl && ctl.set_status('invited', true) )
			debug('invitation count changed to: ' + data);
	},

	onPreview: function(data) {
		trace('Poll.onPreview: ', data);
		Exfile.Vfs.Item.updatePreview(data.nodeId, data.type);
	},

	onStats: function(data) {
		trace('Poll.onStats: ', data);
		if (!Exfile.App)
			return;
		Exfile.App.loadStats();
	},

	onChange: function(data) {
		trace('Poll.onChange: ', data);
		if ( ctl && $(ctl.cfg.e_status) )
			$(ctl.cfg.e_status).innerHTML = ctl.gui.render_status_content();
	}

};


// wiki(name) defined in vfs/item.wm & app/index.wm
function _wiki(name, type) {
	var efi = $('fileItem');
	var efo = $('folderList');
	var pid;
	if (efo && efi && efi.style.display == 'none')
		pid = Exfile.Vfs.List.folderId;
	else
		pid = $('fileParentId').value;
	if (type == 'pub')
		document.location='/pub/' + pid + '?wiki=' + name;
	else
		document.location='#wi.' + pid + '.' + name;
}


// Cleanup below ------------------------

// argh.. fixme. 
var enableTrace = false;
var enableTracePoll = false;
var enableTraceRpc = false;
function trace_rpc(a, b, c, d, e) { if (!enableTraceRpc) return; trace(a, b, c, d, e); }
function trace_poll(a, b, c, d, e) { if (!enableTracePoll) return; trace(a, b, c, d, e); }
function trace(a, b, c, d, e) { if (!enableTrace) return; debug(a, b, c, d, e); }
// and me
function debug() { 
	if (!window.console)
		return;
	if (!arguments)
		return;
	var s = ''+arguments[0];
	var a = arguments;
	if (a[1] == null)
		console.log(s);
	else if (a[2] == null)
		console.log(s, a[1]);
	else if (a[3] == null)
		console.log(s, a[1], a[2]);
	else if (a[4] == null)
		console.log(s, a[1], a[2], a[3]);
	else if (a[5] == null)
		console.log(s, a[1], a[2], a[3], a[4]);	
	
}

var ctl;
var _track_unload_url = null; // @todo: de-quick-and-dirty-fy. @see: track_unload

function track_unload() {
	if ( !_track_unload_url )
		return;
	var im = document.createElement('img');
	im.src = _track_unload_url;
	document.body.appendChild(im);
}
function track_unload_url(u) {
	_track_unload_url = u;
}
function setPreference(k,v) { return set_property(k,v); }
function set_property(prop, e) {
	var val;
	if ( e && typeof(e) == 'object' && e.tagName ) {
		switch (e.tagName.toLowerCase()) {
			case 'input':
				switch (e.type) {
					case 'text':
						val = e.value;
						break;
					case 'checkbox':
						if ( e.checked )
							val = true;
						else
							val = false;
						break;
					case 'radio':
						debug('radio property not implemented');
						break;
				}
				break;
			case 'textarea':
				val = e.innerHTML;
				break;
			case 'select':
				debug('select property not implemented');
				break;
		}
	} else {
		val = e;
	}
	if (val == undefined)
		return;
	_set_property(prop, val);
	return val;
}

function _set_property(prop, val) {
	new Ajax.Request( '/ws/soap/User/setPreference?key=' + prop + '&value=' + val );
}

// png transparency hack for IE
function pngfix() {
	var arVersion = navigator.appVersion.split("MSIE")
	var version = parseFloat(arVersion[1])
	if ( ! ((version >= 5.5) && (document.body.filters)) )
		return;
	for(var i=0; i<document.images.length; i++) {
		var img = document.images[i]
		var imgName = img.src.toUpperCase()
		if (imgName.substring(imgName.length-3, imgName.length) != "PNG")
			continue;
		if ( !img.className.match(/(^| )pngfix( |$)/) )
			continue;
		var imgID = (img.id) ? "id='" + img.id + "' " : ""
		var imgClass = (img.className) ? "class='" + img.className + " img' " : "class='img'"
		var imgTitle = (img.title) ? "title='" + img.title + "' " : "title='" + img.alt + "' "
		var imgStyle = "display:inline-block;" + img.style.cssText 
		var onClick = (img.onClick) ? "onclick='" + img.onClick + "' " : " ";
		if (img.align == "left") imgStyle = "float:left;" + imgStyle
		if (img.align == "right") imgStyle = "float:right;" + imgStyle
		if (img.parentElement.href) imgStyle = "cursor:hand;" + imgStyle
		var strNewHTML = "<span " + imgID + imgClass + imgTitle + onClick
		+ " style=\"" + "width:" + img.width + "px; height:" + img.height + "px;" + imgStyle + ";"
		+ "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader"
		+ "(src=\'" + img.src + "\', sizingMethod='image');\"></span>" 
		img.outerHTML = strNewHTML
		i = i-1
	}
}

function invoice_open(id) {
	window.open('/subscribe/invoice?out=minimal&id='+id,'invoice'+id,'scrollbars=0,width=650,height=600,resizable=1');
}

function remove_class(haystack, q) {
	return replace_class(haystack, q, null);
}
function add_class(haystack, q) {
	return replace_class(haystack, null, q);
}
function replace_class(haystack, needle, replacement) {
	var is_add = false;
	if ( needle == null ) {
		is_add = true;
		needle = replacement;
	}
	var classes = haystack.split(' ');
	var started = false;
	var replaced = false;
	var str = '';
	for ( var i = 0; i < classes.length; i++ ) {
		if ( started )
			str += ' ';
		else
			started = true;
		if ( classes[i] == needle ) {
			if ( replacement == null )
				continue; // for removing class
			str += replacement;
			replaced = true;
		} else
			str += classes[i];
	}
	if ( is_add && !replaced )
		str += ' ' + replacement;
	return str;
}
function has_class(element, classname) {
	return Exfile.Core.Util.hasClass(element, classname);
}

function get_doc_dim() {

        var obj = new Object();
        obj.width = 0;
        obj.height = 0;

        // Non-IE
        if( typeof( window.innerWidth ) == 'number' ) {
                obj.width = window.innerWidth;
                obj.height = window.innerHeight;
        // IE 6 standards compliant mode
        } else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
                obj.width = document.documentElement.clientWidth;
                obj.height = document.documentElement.clientHeight;
        //IE 4
        } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
                obj.width = document.body.clientWidth;
                obj.height = document.body.clientHeight;
        }

        return obj;

}
function get_x_pos(obj)
{
        var curleft = 0;
        if (obj.offsetParent)
        {
                while (obj.offsetParent)
                {
                        curleft += obj.offsetLeft
                        obj = obj.offsetParent;
                }
        }
        else if (obj.x)
                curleft += obj.x;
        return curleft;
}

function get_y_pos(obj)
{
        var curtop = 0;
        if (obj.offsetParent)
        {
                while (obj.offsetParent)
                {
                        curtop += obj.offsetTop
                        obj = obj.offsetParent;
                }
        }
        else if (obj.y)
                curtop += obj.y;
        return curtop;
}
function update_prefs(obj) {
    var receive = function() { }
    XMLRPC.call(receive, '/xmlrpc/', 'cust.update_prefs', obj);
}
var BrowserDetect =  {

	init: function () {
		this._browser = this.searchString(this.dataBrowser) || "An unknown browser";
		this._version = this.searchVersion(navigator.userAgent) || this.searchVersion(navigator.appVersion) || "an unknown version";
		this._OS = this.searchString(this.dataOS) || "an unknown OS";
	},
    
    browser: function() { return this._browser.toLowerCase(); },
    version: function() { return this._version; },
    os: function() { return this._OS.toLowerCase(); },
    
	searchString: function (data) {
		for (var i=0;i<data.length;i++)	{
			var dataString = data[i].string;
			var dataProp = data[i].prop;
			this.versionSearchString = data[i].versionSearch || data[i].identity;
			if (dataString) {
				if (dataString.indexOf(data[i].subString) != -1)
					return data[i].identity;
			}
			else if (dataProp)
				return data[i].identity;
		}
	},
	searchVersion: function (dataString) {
		var index = dataString.indexOf(this.versionSearchString);
		if (index == -1) return;
		return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
	},
	dataBrowser: [
		{ 	string: navigator.userAgent,
			subString: "OmniWeb",
			versionSearch: "OmniWeb/",
			identity: "OmniWeb"
		},
		{
			string: navigator.vendor,
			subString: "Apple",
			identity: "Safari"
		},
		{
			prop: window.opera,
			identity: "Opera"
		},
		{
			string: navigator.vendor,
			subString: "iCab",
			identity: "iCab"
		},
		{
			string: navigator.vendor,
			subString: "KDE",
			identity: "Konqueror"
		},
		{
			string: navigator.userAgent,
			subString: "Firefox",
			identity: "Firefox"
		},
		{
			string: navigator.vendor,
			subString: "Camino",
			identity: "Camino"
		},
		{		// for newer Netscapes (6+)
			string: navigator.userAgent,
			subString: "Netscape",
			identity: "Netscape"
		},
		{
			string: navigator.userAgent,
			subString: "MSIE",
			identity: "Explorer",
			versionSearch: "MSIE"
		},
		{
			string: navigator.userAgent,
			subString: "Gecko",
			identity: "Mozilla",
			versionSearch: "rv"
		},
		{ 		// for older Netscapes (4-)
			string: navigator.userAgent,
			subString: "Mozilla",
			identity: "Netscape",
			versionSearch: "Mozilla"
		}
	],
	dataOS : [
		{
			string: navigator.platform,
			subString: "Win",
			identity: "Windows"
		},
		{
			string: navigator.platform,
			subString: "Mac",
			identity: "Mac"
		},
		{
			string: navigator.platform,
			subString: "Linux",
			identity: "Linux"
		}
	]

};
BrowserDetect.init();


function round(num) {
    var decimals = 2;
    if (arguments[1] || arguments[1] == 0)
        decimals = arguments[1];
    var rounded = Math.round( num * Math.pow(10,decimals) ) / Math.pow(10,decimals);
    var n = (""+rounded).split('.');
    var ret = '.';
    var start = 0;
    if (n[1]) {
        ret += n[1];
        start = n[1].length;
    }
    for (var i = start; i < decimals; i++) {
        ret += '0';
    }
    if (ret != '.') return n[0] + ret;
    return rounded;
}
    
function remove_childnodes(element) {
    var css_class = null;
    if ( arguments[1] ) css_class = arguments[1];
    var kids = [];
    for(var i = 0; i < element.childNodes.length; i++) {
        if ( css_class && element.childNodes[i].className != css_class )
            continue;
        kids[i] = element.childNodes[i];
    }
    for(var i = 0; i < kids.length; i++) {
        var dummy = element.removeChild( kids[i] );
    }
}
    
function OLD_popup2(url) {
        window.open(url, 'title', 'scrollbars=0,resizable=1,height=350,width=450,top=200,left=300');
}
function popup(url, id) {
	var opt = 'scrollbars=0,resizable=1,height=108,width=460';
	if ( id ) {
		switch (id) {
			case 'terms':
				opt = 'scrollbars=1,resizable=1,height=550,width=550,top=200,left=300'
				break;
			case 'help':
				opt = 'scrollbars=1,resizable=1,height=350,width=300,top=200,left=300';
				break;
		}
		
	} else {
		id = '_new';
	}
	window.open(url, id, opt);
}
function help(item) {
	var u = '/page/popup/Help' + item;
	popup(u, 'help');
}

function emailChg(src) {
	target = document.getElementById('email');
	target.value = src.value;
}

function submitTo(action) {
	f = document.getElementById('param_form');
	f.action = action;
	f.submit();
}
function validEmail(str) { return valid_email(str); } // deprecated
function valid_email(str) {
        return (str.indexOf(".") > 0) && (str.indexOf("@") > 0);
}
function mkObj(typ,klasse) {
	var obj = document.createElement(typ);
	if (klasse) obj.className = klasse;
	return obj;
}
function randomString() {
	var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
	var string_length = 8;
	var randomstring = '';
	for (var i=0; i<string_length; i++) {
		var rnum = Math.floor(Math.random() * chars.length);
		randomstring += chars.substring(rnum,rnum+1);
	}
	document.randform.randomfield.value = randomstring;
}

function debug_obj(val) {
	var str = '';
	for (var i in val) {
		if ( typeof(val[i]) == 'function' )
			continue;
		str += i + ': ' + val[i] + '\n';
	}
	alert(str);
}

/*
You will note that all backslashed metacharacters in Perl are alphanumeric, such as \b, \w, \n. 
Unlike some other regular expression languages, there are no backslashed symbols that aren't alphanumeric. 
So anything that looks like \\, \(, \), \<, \>, \{, or \} is always interpreted as a literal character, 
not a metacharacter. This makes it simple to quote a string that you want to use for a pattern 
but that you are afraid might contain metacharacters. Simply quote all the non-alphanumeric characters.
*/

function regexp_quote(str) {
    return str.replace(/(\W)/g, '\\$1');
}

function urlencode(str) {
    str = str.replace(/\+/, 'PLUSS');
//    str = str.replace(/ /, '+');
//    str = escape(str);
alert(str);
    return str;
    return escape( str.replace(/\+/, 'PLUSS').replace(/ /, '+') ).
              replace(/PLUSS/, '%2B').
                replace(/\"/g,'%22').
                   replace(/\'/g, '%27').
                     replace(/\//g,'%2F');
}
 
function escape_arg(arg) {
    return arg.replace(/\\/g,'\\\\');
}

function escape_dquote(str) {
	return str.replace(/\"/g, '\\"');	
}

function closebox_toggle(content_id,toggle_id) {
	ctl.box_toggle(content_id, toggle_id);
}

function cb_over(type, element, is_mouseout) {
	if ( ctl && ctl.onboxover )
		ctl.onboxover(type, element, is_mouseout);
}

function noop() {}

function url(opt) {
	var u = "/";
	if (opt.handler) {
		u += opt.handler;
		if (opt.view) {
			u += "/" + opt.view;
			if (opt.key) {
				u += "/" + opt.key;
			}
		}
	}
	return u;
}



function dialog(opt) {

	if (typeof(opt) == 'string')
		opt = {text: opt};
	if (!opt)
		opt = {}

	var close = $('dialogClose');
	var text = $('dialogText');
	var dia = $('dialog');

	if (opt.noClose)
		close.style.display = 'none';
	else
		close.style.display = 'block';	

        if (opt.text)
                text.innerHTML = opt.text;
	else if (opt.url)
		text.innerHTML = '<img src="/img/common/loading.gif"/>';

	if (opt.url) {
debug("Ajax dialog: " + opt.url);
		Exfile.Core.Ajax.update(text, opt.url, {
			onComplete: function() {
				dialogSetVisibility(true);
			}
		});
	} else {
debug("normal dialog, showing");
		dialogSetVisibility(true);
	}
debug("dialog COMPLETE");

}

function dialogSetVisibility(val) {
	$('dialog').style.visibility = (val) ? "visible" : "hidden";
}
function dialogGetVisibility() {
	return ($('dialog').style.visibility == 'visible');
}

function himga(elem, src, src_hover, isHover) {
	var img = false;
	for(var i=0; i < elem.childNodes.length; i++) {
		var c = elem.childNodes[i];
		if (c.tagName && c.tagName.toLowerCase() == 'img') {
			img = c;
			break;
		}
	}
	if (!img)
		return;
	if (isHover)
		img.src = src_hover;
	else
		img.src = src;
}

