String.prototype.sReplace = function(find, replace) {
	return this.split(find).join(replace);
};

String.prototype.repeat = function(times) {
	var rep = new Array(times + 1);
	return rep.join(this);
}

var YShout = function() {
	var self = this;
	var args = arguments;
	Ext.onReady(function() {
		self.init.apply(self, args);
	});
} 

var yShout;

Ext.Element.prototype.toggle = function() {
	// Save reference to arguments for access in closure
	var args = arguments;
	
	return this.on('click', function(event) {
		// Figure out which function to execute
		this.lastToggle = 0 == this.lastToggle ? 1 : 0;
		
		// Make sure that clicks stop
		event.preventDefault();
		
		// and execute the function
		return args[this.lastToggle].apply( this, arguments ) || false;
	});
}

YShout.prototype = {
	animSpeed: 300,
	currentRefreshTime: 3750,
	refreshedThisRate: 0,
	p: [],
		
	init: function(options) {
		yShout = this;
		var self = this;
		
		if (!Ext.get('yshout')) return;
		
		this.initializing = true;
		
		var dOptions = {
			yPath: 'yshout/',
			log: 1
		};

		this.options = Ext.apply(dOptions, options);

		this.postNum = 0;
		this.floodAttempt = 0;	
		
		// Correct for missing trailing /
		if ((this.options.yPath.length > 0) && (this.options.yPath.charAt(this.options.yPath.length - 1) != '/'))
			this.options.yPath += '/';
		
		if (this.options.yLink) {
			if (this.options.yLink.charAt(0) != '#')
				this.options.yLink = '#' + this.options.yLink;
		
			Ext.get(this.options.yLink).on('click', function(event) {
				self.openYShout.apply(self);
				event.preventDefault();
				return false;
			});
		}
		
		// Load YShout from a link, in-page
		if (this.options.h_loadlink) {
			Ext.get(this.options.h_loadlink).on('click', function() {
				Ext.get('yshout').setStyle('display', 'block');
				Ext.get(this).unbind('click').on('click', function() { return false; });
				return false;
			});
			this.load(true);
		} else
			this.load();
		

	},
	
	load: function(hidden) {
		if (Ext.get('yshout').length == 0) return;

		if (hidden) Ext.get('yshout').setStyle('display', 'none');
		
		this.ajax(this.initialLoad, { 
			reqType: 'init',
			yPath: this.options.yPath,
			log: this.options.log
		});
	},
	
	initialLoad: function(updates) {
		if (updates.yError) alert('There appears to be a problem: \n' + updates.yError + '\n\nIf you haven\'t already, try chmodding everything inside the YShout directory to 777.');
		this.d('In initialLoad');
		var self = this;
		
		this.prefs = Ext.apply(updates.prefs, this.options.prefs);
		this.initForm();
		this.initRefresh();
		this.initLinks();
		if (this.prefs.flood) this.initFlood();

		if (updates.nickname)
			Ext.get('ys-input-nickname')
				.removeClass('ys-before-focus')
				.addClass( 'ys-after-focus')
				.dom.value = updates.nickname;

		if (updates)
			this.updates(updates);
	
		
		if (!this.prefs.doTruncate) {
			Ext.get('ys-posts').setStyle('height', Ext.get('ys-posts').getHeight() + 'px');
		}

		if (!this.prefs.inverse) {
			var postsDiv = Ext.get('ys-posts');
			postsDiv.scrollTop = postsDiv.scrollHeight;
		}
		
		this.totalHeight = Ext.get('ys-posts').getComputedHeight();
		
		this.resizeMessage();

		this.markEnds();
		
		this.initializing = false;
	},

	initForm: function() {
		this.d('In initForm');
			
		var postForm = '<div>'+
				(this.prefs.postFormLink == 'cp' ? '<a title="View YShout Control Panel" class="ys-post-form-link" id="ys-cp-link" href="' + this.options.yPath + 'cp/">Admin CP</a>' : '') +
				(this.prefs.postFormLink == 'history' ? '<a title="View YShout History" class="ys-post-form-link" id="ys-history-link" href="' + this.options.yPath + 'history/?log=' + this.options.log + (this.options.IsSquad?'&squad='+this.options.IsSquad:'') + '">View History</a>' : '') +
				'<br />' +'</div>' + '<div id="frmShoutbox"></div>';
		/*var postForm = 
			'<form onsubmit="return false;" id="ys-post-form"' + (this.prefs.inverse ? 'class="ys-inverse"' : '' ) + '><fieldset>' +
				(this.prefs.postFormLink == 'cp' ? '<a title="View YShout Control Panel" class="ys-post-form-link" id="ys-cp-link" href="' + this.options.yPath + 'cp/">Admin CP</a>' : '') +
				(this.prefs.postFormLink == 'history' ? '<a title="View YShout History" class="ys-post-form-link" id="ys-history-link" href="' + this.options.yPath + 'history/?log=' + this.options.log + '">View History</a>' : '') +
				'<br />' +
				'<input id="ys-input-nickname" readonly="true" value="' + this.prefs.defaultNickname + '" type="text" accesskey="N" maxlength="' + this.prefs.nicknameLength + '" class="ys-before-focus" />' +
				(this.prefs.showSubmit ? '<input id="ys-input-submit" value="' + this.prefs.defaultSubmit + '" accesskey="S" type="submit" />' : '') +
			'</fieldset></form>';*/
			
			//'<input id="ys-input-nickname" value="' + this.prefs.defaultNickname + '" type="text" accesskey="N" maxlength="' + this.prefs.nicknameLength + '" class="ys-before-focus" />' +
			//'<input id="ys-input-message" value="' + this.prefs.defaultMessage + '" type="text" accesskey="M" maxlength="' + this.prefs.messageLength + '" class="ys-before-focus" />' +

		var postsDiv = '<div id="ys-posts"></div>';

		if (this.prefs.inverse) Ext.get('yshout').dom.innerHTML = postForm + postsDiv;
		else Ext.get('yshout').dom.innerHTML = postsDiv + postForm;
		
		Ext.DomHelper.insertBefore(Ext.get('ys-posts'), '<div id="ys-before-posts"></div>');
		Ext.DomHelper.insertAfter(Ext.get('ys-posts'), '<div id="ys-after-posts"></div>');
		
		var self = this;
		
		this.txtMessageArea = new Ext.form.TextArea({
			name: "ys-input-message",
			id: "ys-input-message",
			width : 250,
			height: 19,
			fieldLabel: "Description",
			grow: true,
			grow: true,
			growMin: 19,
			growMax: 100,
			maxLength: this.prefs.messageLength,
			emptyText: this.prefs.defaultMessage,
			anchor:'90%',
			hideLabel: true,
			msgTarget: 'side'
	  });
		this.frmYshout = new Ext.FormPanel({
        renderTo: 'frmShoutbox',
        cls: (this.prefs.inverse ? 'class="ys-inverse"' : '' ),
        name: "ys-post-form",
				id: "ys-post-form",
        border: false,
        width: 500,
        waitMsgTarget:'frmShoutbox',
				bodyStyle: { backgroundColor: "transparent" },
        defaults: {
            allowBlank: false,
            msgTarget: 'side',
            hideLabel: true
        },
        items: [
        	{
        		layout:'column',
        		border: false,
						bodyStyle: { backgroundColor: "transparent" },
            items:[{
                columnWidth:.25,
                layout: 'form',
                border: false,
						bodyStyle: { backgroundColor: "transparent" },
                items: [
                {
			            xtype: 'textfield',
			            name: "ys-input-nickname",
									id: "ys-input-nickname",
									fieldLabel: "Name",
									height: 19,
									maxLength: this.prefs.nicknameLength,
									readOnly: true,
									value: this.prefs.defaultNickname,
									anchor:'95%',
									hideLabel: true
			        }]
            },{
                columnWidth:.60,
                layout: 'form',
                border: false,
								bodyStyle: { backgroundColor: "transparent" },
                items: [this.txtMessageArea]
            },{
                columnWidth:.15,
                layout: 'form',
                border: false,
								bodyStyle: { backgroundColor: "transparent" },
                items: [{
				        	xtype: 'button',
			            text: 'Submit',
			            type: 'submit',
			            name: "ys-input-submit",
									id: "ys-input-submit",
			            handler: this.send,
			            scope: self,
			            style: "display:inline"
			          }],
                anchor:'95%'
            }]
        }
	      ]
    });
    
		
		Ext.select('.x-form-grow-sizer').setStyle('padding', '0px');
			
		this.txtMessageArea.on('autosize', this.resizeMessage, this);
			
		this.resizeMessage();
			
		if (this.options.postsHeight)
		{
			Ext.get('ys-posts').setHeight(this.options.postsHeight).setStyle('overflow', 'auto');
			//Ext.get('ys-posts').hover(function() {}, function() { this.scroll('up', 50 , {duration: 1}); }, Ext.get('ys-posts'));
		}
		
		Ext.DomHelper.insertBefore(Ext.get('ys-post-form'), '<div id="ys-before-post-form"></div>');
		Ext.DomHelper.insertAfter(Ext.get('ys-post-form'), '<div id="ys-after-post-form"></div>');

		var defaults = { 
			'ys-input-nickname': self.prefs.defaultNickname, 
			'ys-input-message': self.prefs.defaultMessage
		};

		var keypress = function(e) { 
			var key = window.event ? e.keyCode : e.which; 
			if (key == 13 || key == 3) {
				self.send.apply(self);
				return false;
			}
		};

		var focus = function() { 
			if (this.dom.value == defaults[this.id])
				Ext.get(this).removeClass('ys-before-focus').addClass( 'ys-after-focus').dom.value = '';
		};

		var blur = function() { 
			if (this.dom.value == '')
				Ext.get(this).removeClass('ys-after-focus').addClass('ys-before-focus').dom.value = defaults[this.id]; 
		};
		
		var elInputMessage = Ext.get('ys-input-message');
		var elInputNickname = Ext.get('ys-input-message');
		elInputMessage.addKeyListener([13 , 3], keypress);
		elInputNickname.addKeyListener([13 , 3], keypress);
		elInputMessage.on('focus', focus)
		elInputMessage.on('blur', blur);
		elInputNickname.on('focus', focus)
		elInputNickname.on('blur', blur);

		//Ext.get('ys-input-submit').on('click', function(){ self.send.apply(self) });
		Ext.get('ys-post-form').on('submit', function(){ return false });
		
		this.resizeMessage();
	},
	
	resizeMessage: function(messageArea)
	{
		if (this.totalHeight)
		{
			Ext.get('ys-posts').setHeight(this.totalHeight - this.txtMessageArea.getSize().height);
			Ext.get('ys-post-form').setHeight( 50 - 19 + this.txtMessageArea.getSize().height);
		}
	},
	
	nextRefreshTime: function() {
		if (this.refreshedThisRate == 2)
		{
			if (this.currentRefreshTime < 60000)
			{
				this.currentRefreshTime = this.currentRefreshTime * 2;
			}
			this.refreshedThisRate = 0;
		}
		else
		{
			this.refreshedThisRate++;
		}
		
		return this.currentRefreshTime;
	},

	initRefresh: function() {
		var self = this;
		if (this.refreshTimer) clearInterval(this.refreshTimer)
		this.refreshTimer = setInterval(function() {
			self.ajax(self.updates, { reqType: 'refresh' });
		}, this.nextRefreshTime()); // ! 3000..?
	},

	initFlood: function() {
		this.d('in initFlood');
		var self = this;
		this.floodCount = 0;
		this.floodControl = false;

		this.floodTimer = setInterval(function() {
			self.floodCount = 0;
		}, this.prefs.floodTimeout);
	},

	initLinks: function() {
		//if (Ext.isIE) return;
		
		var self = this;

		if (Ext.get('ys-cp-link'))
			Ext.get('ys-cp-link').on('click', function(event) {
				self.openCP.apply(self);
				event.stopEvent(true);
				return false;
			});
		
		if (Ext.get('ys-history-link'))
			Ext.get('ys-history-link').on('click', function(event) {
				self.openHistory.apply(self);
				event.stopEvent(true);
				return false;
			});

	},
	
	openCP: function() {
		var self = this;
		if (this.cpOpen) return;
		this.cpOpen = true;
		
		var url = this.options.yPath + 'cp/';

		Ext.DomHelper.insertHtml('beforeEnd', Ext.getBody().dom, '<div id="ys-overlay"></div><div class="ys-window" id="ys-cp"><a title="Close Admin CP" href="#" id="ys-closeoverlay-link">Close</a><a title="View History" href="#" id="ys-switchoverlay-link">View History</a><object class="ys-browser" id="cp-browser" data="' + url +'" type="text/html">Something went horribly wrong.</object></div>');

		Ext.get('ys-overlay').select('#ys-closeoverlay-link').on('click', function(event) { 
			self.reload.apply(self, [true]);
			self.closeCP.apply(self);
			event.preventDefault();
			return false; 
		}); 
		
		Ext.get('ys-switchoverlay-link').on('click', function(event) { 
			self.closeCP.apply(self);
			self.openHistory.apply(self);
			event.preventDefault();
			return false;
		});

	},

	closeCP: function() {
		this.cpOpen = false;
		Ext.select('#ys-overlay, #ys-cp').remove()
	},

	openHistory: function() {
		var self = this;
		if (this.hOpen) return;
		this.hOpen = true;
		var url = this.options.yPath + 'history/?log='+ this.options.log + (this.options.IsSquad ? '&squad='+this.options.IsSquad : '');
		//Ext.DomHelper.insertHtml('beforeEnd', Ext.getBody().dom, '<div id="ys-overlay"></div><div class="ys-window" id="ys-history"><a title="Close history" href="#" id="ys-closeoverlay-link">Close</a><a title="View Admin CP" href="#" id="ys-switchoverlay-link">View Admin CP</a><object class="ys-browser" id="history-browser" data="' + url +'" type="text/html">Something went horribly wrong.</object></div>');
		Ext.DomHelper.insertHtml('beforeEnd', Ext.getBody().dom, '<div id="ys-overlay"></div><div class="ys-window" id="ys-history"><a title="Close history" href="#" id="ys-closeoverlay-link">Close</a><a title="View Admin CP" href="#" id="ys-switchoverlay-link">View Admin CP</a><iframe id="history-browser" src="' + url +'">Something went horribly wrong.</iframe></div>');

		Ext.get('ys-overlay').select('#ys-closeoverlay-link').on('click', function(event) { 
			self.reload.apply(self, [true]);
			self.closeHistory.apply(self);
			event.preventDefault();
			return false; 
		}); 

		Ext.get('ys-switchoverlay-link').on('click', function(event) { 
			self.closeHistory.apply(self);
			self.openCP.apply(self);
			event.preventDefault();
			return false;
		});

	},

	closeHistory: function() {
		this.hOpen = false;
		Ext.select('#ys-overlay, #ys-history').remove()
	},
	
	openYShout: function() {
		var self = this;
		if (this.ysOpen) return;
		this.ysOpen = true;
		url = this.options.yPath + 'example/yshout.html';

		Ext.DomHelper.insertHtml('beforeEnd', Ext.getBody().dom, '<div id="ys-overlay"></div><div class="ys-window" id="ys-yshout"><a title="Close YShout" href="#" id="ys-closeoverlay-link">Close</a><object class="ys-browser" id="yshout-browser" data="' + url +'" type="text/html">Something went horribly wrong.</object></div>');
	
		Ext.get('ys-overlay').select('#ys-closeoverlay-link').on('click', function() { 
			self.reload.apply(self, [true]);
			self.closeYShout.apply(self);
			return false; 
		}); 
	},

	closeYShout: function() {
		this.ysOpen = false;
		Ext.select('#ys-overlay, #ys-yshout').remove()
	},
	
	send: function() {
		if (!this.validate()) return;
		if (this.prefs.flood && this.floodControl) return;

		var postMessage = Ext.get('ys-input-message').dom.value;

		if (postMessage == '/cp')
			this.openCP();
		else if (postMessage == '/history')
			this.openHistory();
		else
			this.ajax(this.updates, {
				reqType: 'post',
				message: postMessage
			});

		Ext.get('ys-input-message').dom.value = '';
		this.txtMessageArea.autoSize();
		if (this.prefs.flood) this.flood();
	},

	validate: function() {
		var message = Ext.get('ys-input-message').dom.value,
				error = false;

		var showInvalid = function(input) {
			Ext.get(input).removeClass('ys-input-valid').addClass('ys-input-invalid').focus();
			error = true;
		}

		var showValid = function(input) {
			Ext.get(input).removeClass('ys-input-invalid').addClass('ys-input-valid');
		}

		if (message == '' || message == this.prefs.defaultMessage)
			showInvalid('ys-input-message');
		else
			showValid('ys-input-message');
			
		if (!this.frmYshout.getForm().isValid())
		{
			error = true;
		}

		return !error;
	},

	flood: function() {
		var self = this;
		this.d('in flood');
		if (this.floodCount < this.prefs.floodMessages) {
			this.floodCount++;
			return;
		}

		this.floodAttempt++;
		this.disable();

		if (this.floodAttempt == this.prefs.autobanFlood)
			this.banSelf('You have been banned for flooding the shoutbox!');
			
		setTimeout(function() {
			self.floodCount = 0;
			self.enable.apply(self);
		}, this.prefs.floodDisable);
	},

	disable: function () {
		Ext.get('ys-input-submit').disabled = true;
		this.floodControl = true;
	},

	enable: function () {
		Ext.get('ys-input-submit').disabled = false;
		this.floodControl = false;
	},
	
	findBySame: function(ip) {
		if (!Ext.isSafari) return;
		
		var same = [];
		for (var i = 0; i < this.p.length; i++)
			if (this.p[i].adminInfo.ip == ip) 
				same.push(this.p[i]);
		
		for (var i = 0; i < same.length; i++) {
			Ext.get('' + same[i].id).fadeTo(this.animSpeed, .8).fadeTo(this.animSpeed, 1);
		}
	},
	
	updates: function(updates) {
		if (updates)
		{
			if (updates.prefs) this.prefs = updates.prefs;
			if (updates.posts) this.posts(updates.posts);
			if (updates.banned) this.banned();
		}
		if (this.currentRefreshTime < 120000)
		{
			this.initRefresh();
		}
	},

	banned: function() {
		var self = this;
		clearInterval(this.refreshTimer);
		clearInterval(this.floodTimer);
		if (this.initializing)
			Ext.get('ys-post-form').setStyle('display', 'none');
		else
			Ext.get('ys-post-form').fadeOut(this.animSpeed);
		
		if (Ext.get('ys-banned').length == 0) {
			Ext.get('ys-input-message').blur();
			Ext.DomHelper.insertHtml('beforeEnd', Ext.get('ys-posts'), '<div id="ys-banned"><span>You\'re banned. Click <a href="#" id="ys-unban-self">here</a> to unban yourself if you\'re an admin. If you\'re not, go <a href="' + this.options.yPath + 'cp/" id="ys-banned-cp-link">log in</a>!</span></div>');

			Ext.get('ys-banned-cp-link').click(function() {
				self.openCP.apply(self);
				return false;
			});
			
			Ext.get('ys-unban-self').click(function() {
				self.ajax(function(json) {
					if (!json.error)
						self.unbanned();
					 else if (json.error == 'admin')
						alert('You can only unban yourself if you\'re an admin.');
				}, { reqType: 'unbanself' });
				return false;
			});
		}		
	},

	unbanned: function() {
		var self = this;
		Ext.get('ys-banned').fadeOut(function() { Ext.get(this).remove(); });
		this.initRefresh();
		Ext.get('ys-post-form').setStyle('display', 'block').fadeIn(this.animSpeed, function(){
			self.reload();
		});
	},
	
	posts: function(p) {
		for (var i = 0; i < p.length; i++) {
			this.post(p[i]);
		}
		
		this.truncate();
		
		if (!this.prefs.inverse) {
			var postsDiv = Ext.get('ys-posts');
			postsDiv.scrollTop = postsDiv.scrollHeight;
		}
	},

	post: function(post) {
		
		// Mechanism for fixing the double viewing of posts
		
		var self = this;
	
		var pad = function(n) { return n > 9 ? n : '0' + n; };
		var date = function(ts) { return new Date(ts * 1000); };
		var time = function(ts) { 
			var d = date(ts);
			var h = d.getHours(), m = d.getMinutes();

			if (self.prefs.timestamp == 12) {
				h = (h > 12 ? h - 12 : h);
				if (h == 0) h = 12;
			}

			return pad(h) + ':' + pad(m);
		};

		var dateStr = function(ts) {
			var t = date(ts);

		  var Y = t.getFullYear();
		  var M = t.getMonth();
		  var D = t.getDay();
		  var d = t.getDate();
		  var day = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'][D];
		  var mon = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
		             'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][M];

		  return day + ' ' + mon + '. ' + d + ', ' + Y;
		};

		var self = this;

		this.postNum++;
		var id = 'ys-post-' + this.postNum;
		post.id = id;
		
		post.message = this.links(post.message);
		post.message = this.smileys(post.message);
		post.message = this.bbcode(post.message);
		var html = 
			'<div id="' + id + '" class="ys-post' + (post.admin ? ' ys-admin-post' : '') + (post.banned ? ' ys-banned-post' : '') + (this.postNum % 2 ? ' odd' : '') + '">' +
				(this.prefs.timestamp> 0 ? '<span class="ys-post-timestamp">' + time(post.timestamp) + '</span> ' : '') +
				'<span class="ys-post-nickname">' + post.nickname + this.prefs.nicknameSeparator + '</span> ' +
				'<span class="ys-post-message">' + post.message + '</span> ' +
				'<span class="ys-post-info' + (this.prefs.info == 'overlay' ? ' ys-info-overlay' : ' ys-info-inline') + '">' + (post.adminInfo ? '<em>IP:</em> ' + post.adminInfo.ip + ', ' : '') + '<em>Posted:</em> ' + dateStr(post.timestamp) + ' at ' + time(post.timestamp)  + '.</span>' +
				'<span class="ys-post-actions"><a title="Show post information" class="ys-info-link" href="#">Info</a>'  + (post.adminInfo ? ' | <a title="Delete post" class="ys-delete-link" href="#">Delete</a> | ' + (post.banned ? '<a title="Unban user" class="ys-ban-link" href="#">Unban</a>' : '<a title="Ban user" class="ys-ban-link" href="#">Ban</a>') : '') + '</span>' +
			'</div>';
		if (this.prefs.inverse) Ext.DomHelper.insertFirst(Ext.get('ys-posts'), html);
		else Ext.DomHelper.insertHtml('beforeEnd', Ext.get('ys-posts'), html);
		
		this.p.push(post);
		
		Ext.get('' + id).select('.ys-post-nickname').on('click', function() {
					if (post.adminInfo)
						self.findBySame(post.adminInfo.ip);
					});
		Ext.get('' + id).select('.ys-info-link').toggle(function() { self.showInfo.apply(self, [id, this]); return false; },
			function(event) { self.hideInfo.apply(self, [id, this]); event.preventDefault(); return false; });
			
		Ext.get('' + id).select('.ys-ban-link').on('click', function(event) { 
			self.ban.apply(self, [post, id]); event.preventDefault(); return false;  
			});
				
		Ext.get('' + id).select('.ys-delete-link').on('click', function(event) { 
			self.del.apply(self, [post, id]); 
			event.preventDefault();
			return false; 
			});	
			
		this.currentRefreshTime = 3750;
		this.refreshedThisRate = 0;
	},
	
	showInfo: function(id, el) {
		var jEl = Ext.select('#' + id + ' .ys-post-info');
		if (this.prefs.info == 'overlay')
			jEl.setStyle('display', 'block').fadeIn({duration: this.animSpeed / 1000});
		else
			jEl.slideDown(this.animSpeed);
		
		el.dom.innerHTML ='Close Info'
		return false;
	},
	
	hideInfo: function(id, el) {
		var jEl = Ext.select('#' + id + ' .ys-post-info');
		if (this.prefs.info == 'overlay')
			jEl.fadeOut({duration: this.animSpeed / 1000});
		else
			jEl.slideOut({duration: this.animSpeed / 1000});
			
		el.dom.innerHTML = 'Info';
		return false;
	}, 
	
	ban: function(post, id) {
		var self = this;

		var link = Ext.select('' + id + ' .ys-ban-link').item(0);

		switch(link.dom.innerHTML) {
			case 'Ban':
				var pars = {
					reqType: 'ban',
					ip: post.adminInfo.ip,
					nickname: post.nickname
				};

				this.ajax(function(json) {
					if (json.error) {
						switch (json.error) {
							case 'admin':
								self.error('You\'re not an admin. Log in through the Admin CP to ban people.');
								break;
						}
						return;
					}
					//alert('p: ' + this.p + ' / ' + this.p.length);
					if (json.bannedSelf)
						self.banned(); // ?
						
					else 						
						Ext.each(self.p, function(i) {
							if (this.adminInfo && this.adminInfo.ip == post.adminInfo.ip) 
									Ext.get('' + this.id)
										.addClass('ys-banned-post')
										.find('.ys-ban-link').html('Unban');
						});
						
				}, pars);
				
				link.dom.innerHTML = 'Banning...';
				return false;
				break;
			
			case 'Banning...':
				return false;
				break;
			
			case 'Unban':
				var pars = {
					reqType: 'unban',
					ip: post.adminInfo.ip
				};
	
				this.ajax(function(json) {
					if (json.error) {
						switch(json.error) {
							case 'admin':
								self.error('You\'re not an admin. Log in through the Admin CP to unban people.');
								return;
								break;
						}
					}
					
					Ext.each(self.p, function(i) {
						if (this.adminInfo && this.adminInfo.ip == post.adminInfo.ip) 
							Ext.get('' + this.id)
								.removeClass('ys-banned-post')
								.find('.ys-ban-link').html('Ban');
					});
					
				}, pars);
	
				link.dom.innerHTML = 'Unbanning...';
				return false;
				break;
				
			case 'Unbanning...':
				return false;
				break;
		}
	},
	
	del: function(post, id) {
		var self = this;
		var link = Ext.select('#' + id + ' .ys-delete-link').item(0);

		if (link.dom.innerHTML == 'Deleting...') return;
	
		var pars = {
			reqType: 'delete',
			uid: post.uid
		};

		self.ajax(function(json) {
			if (json.error) {
				switch(json.error) {
					case 'admin':
						self.error('You\'re not an admin. Log in through the Admin CP to ban people.');
						return;
						break;
				}
			}
			self.reload();
		}, pars);

		link.dom.innerHTML = 'Deleting...';
		return false;

	},
	
	banSelf: function(reason) {
		var self = this;

		this.ajax(function(json) {
			if (json.error == false)
				self.banned();
		}, {
			reqType: 'banself',
			nickname: Ext.get('ys-input-nickname').dom.value
		});
	},

	bbcode: function(s) {
		s = s.sReplace('[i]', '<i>');
		s = s.sReplace('[/i]', '</i>');
		s = s.sReplace('[I]', '<i>');
		s = s.sReplace('[/I]', '</i>');

		s = s.sReplace('[b]', '<b>');
		s = s.sReplace('[/b]', '</b>');
		s = s.sReplace('[B]', '<b>');
		s = s.sReplace('[/B]', '</b>');

		s = s.sReplace('[u]', '<u>');
		s = s.sReplace('[/u]', '</u>');
		s = s.sReplace('[U]', '<u>');
		s = s.sReplace('[/U]', '</u>');

		return s;
	},
	
	smileys: function(s) {
		var yp = this.options.yPath;
		
		var smile = function(str, smiley, image) {
			return str.sReplace(smiley, '<img src="' + yp + 'smileys/' + image + '" />');
		};

		s = smile(s, ':twisted:',  'twisted.gif');
		s = smile(s, ':cry:',  'cry.gif');
		s = smile(s, ':\'(',  'cry.gif');
		s = smile(s, ':shock:',  'eek.gif');
		s = smile(s, ':evil:',  'evil.gif');
		s = smile(s, ':lol:',  'lol.gif');
		s = smile(s, ':mrgreen:',  'mrgreen.gif');
		s = smile(s, ':oops:',  'redface.gif');
		s = smile(s, ':roll:',  'rolleyes.gif');

		s = smile(s, ':?',  'confused.gif');
		s = smile(s, ':D',  'biggrin.gif');
		s = smile(s, '8)',  'cool.gif');
		s = smile(s, ':x',  'mad.gif');
		s = smile(s, ':|',  'neutral.gif');
		s = smile(s, ':P',  'razz.gif');
		s = smile(s, ':(',  'sad.gif');
		s = smile(s, ':)',  'smile.gif');
		s = smile(s, ':o',  'surprised.gif');
		s = smile(s, ';)',  'wink.gif');

		return s;
	},

	links: function(s) {
		return s.replace(/((https|http|ftp|ed2k):\/\/[\S]+)/gi, '<a  href="$1" target="_blank">$1</a>');
	},

	truncate: function(clearAll) {
		var truncateTo = clearAll ? 0 : this.prefs.truncate;
		var posts = Ext.DomQuery.select('#ys-posts .ys-post').length;
		if (posts <= truncateTo) return;
		//alert(this.initializing);
		if (this.prefs.doTruncate || this.initializing) {
			var diff = posts - truncateTo;
			for (var i = 0; i < diff; i++)
				this.p.shift();
			
			//	$('#ys-posts .ys-post:gt(' + truncateTo + ')').remove();

		posts = Ext.select('#ys-posts .ys-post');
			if (this.prefs.inverse) 
			{
				for(var i=0; i < posts.getCount(); i++)
				{
					if(i > truncateTo - 1)
					{
						posts.item(i).remove();
					}
				}
			}
			else
			{
					for(var i=0; i < posts.getCount(); i++)
				{
					if(i < posts - truncateTo)
					{
						posts.item(i).remove();
					}
				}
			}
		}
		
		this.markEnds();		
	},
	
	markEnds: function() {
		Ext.select('#ys-posts .ys-first').removeClass('ys-first');
		Ext.select('#ys-posts .ys-last').removeClass('ys-last');
			
		Ext.select('#ys-posts .ys-post:first-child').addClass('ys-first');
		Ext.select('#ys-posts .ys-post:last-child').addClass('ys-last');
	},
	
	reload: function(everything) {
		var self = this;
		this.initializing = true;
		
		if (everything) {
			this.ajax(function(json) { 
				Ext.get('yshout').dom.innerHTML = ''; 
				clearInterval(this.refreshTimer);
				clearInterval(this.floodTimer);
				this.initialLoad(json); 
			}, { 
				reqType: 'init',
				yPath: this.options.yPath,
				log: this.options.log
			});
		} else {
			this.ajax(function(json) { this.truncate(true); this.updates(json); this.initializing = false; }, {
				reqType: 'reload'
			});
		}
	},

	error: function(str) {
		alert(str);
	},

	json: function(parse) {
		this.d('In json: ' + parse);
		var json = {yError: false};
		if (parse.trim().length > 0)
			json = Ext.util.JSON.decode(parse);
		if (!this.checkError(json)) return json;
	},

	checkError: function(json) {
		if (!json.yError) return false;

		this.d('Error: ' + json.yError);
		return true;
	},

	ajax: function(callback, pars, html) {
		pars = Ext.apply({
			reqFor: 'shout',
			squad: this.options.IsSquad
		}, pars);

		if (this.refreshTimer) clearInterval(this.refreshTimer);
		
		var self = this;

		Ext.Ajax.request({url: this.options.yPath + 'yshout.php', params: pars, callback: function(aOptions, aSuccess, parse) {
			if (parse.responseText)
				if (html)
					callback.apply(self, [parse.responseText]);
				else
					callback.apply(self, [self.json(parse.responseText)]);
			else
				callback.apply(self);
		}});
	},

	d: function(message) {
		//Ext.get('debug').css('display', 'block').prepend('<p>' + message + '</p>');
		return message;
	}
};
