
	var prototypereact = Class.create({
		initialize:function(apiKey, container, ref, styleSheet, lang, debug){
			this.instID = 'prototypereact_' + parseInt(Math.random()*1000000);
			this.uri = "http://"+window.location.hostname+"/include/preact/index.php";
			this.messages = [];
			if (!lang) {
				this.lang = 'UK';
			}else{
				this.lang = lang.toString().toUpperCase();
			}
			this.currentForm = '';
			if (!container){
				this.error(this.getText('errNoContainer'))
				return;
			}
			this.container = $(container);
			this.container.className ='prototypereact';
			if (!apiKey){
				this.error(this.getText('errNoAPIKey'))
				return;
			}
			this.apiKey = apiKey;

			if (!ref){
				this.error(this.getText('errNoRef'))
				return;
			}
			this.ref = ref;
			
//			if (!styleSheet) styleSheet = 'http://miniforum.syntacticsugar.nl/css/prototypereact.css';
//			var link = new Element('link', {rel:'stylesheet', type:'text/css', href:styleSheet});
//			if ($$('head')[0]) {
//				$$('head')[0].insert(link);
//			}else{
//				$(this.container.parentNode).insert(link)
//			}

			if (!debug) {
				this.debug = false;
			}else{
				this.debug = true;
			}

			// some text-thingies:
			this.texts = $H({});
			this.texts.set('formInputName', this.getText('formName'));
			this.texts.set('formInputEmail', this.getText('formEmail'));
			this.texts.set('formInputURL', this.getText('formURL'));
			this.texts.set('formInputMsg', this.getText('formReponse'));
			this.texts.set('formInputSubmit', this.getText('formSubmit'));
			this.buildThread();
		},
		
		buildThread : function(){
			// get messages from rpc-interface;
			var rpc = new rpcClient(this.uri, this.apiKey);
			this.waiter(this.container);
			if (this.debug) rpc.debug = true;
  			rpc.createCall('react', 'getMessages', {'ref':this.ref});
  			rpc.execute(this._buildThread.bind(this));
		},
		
		_buildThread : function(req, rpc){
			this.unWaiter();
			try{
				if (!( rpc.toObject().responses.response.message instanceof Array) ){
					this.messages = [rpc.toObject().responses.response.message];
				}else{
					this.messages = $A(rpc.toObject().responses.response.message);
				}

				var formContainer = new Element('div', {className:'msgReactForm'});
				//msgContainer.insert(formContainer);
				formContainer.hide();
				this.container.insertBefore(formContainer,this.container.firstChild);

				var reactTo = new Element('div', {className:'msgReactTo'}).update(this.getText('newThread') + "<br/><br/>");
				this.container.insertBefore(reactTo,this.container.firstChild);

				
				var msgContainer = new Element('div', {className:'messages'});
				this.container.insert(msgContainer);
				this.messages = this.sortByDate(this.messages);
				this.messages = this.messages.reverse();
				this.messages.each(
					(function(msg){
						if (msg && msg.parentID == 0) this.buildMessage(msg, msgContainer);
					}).bind(this)
				)
	
				
				reactTo.formContainer = formContainer;
				reactTo.parentMessage = null;
				reactTo.observe('click', this.drawForm.bindAsEventListener(this));
				
				formContainer.threadsContainer = msgContainer;
				formContainer.moreLink = reactTo;
			}catch(e){
				if (this.debug) console.log(e)
			}

		},
		
		sortByDate : function(messages){
			var sorted = messages.sort(this._sortByDate);
			return sorted;
		},
		
		_sortByDate : function(msg1, msg2){
			var date1 = new Date(msg1.dtPosted)
			var date2 = new Date(msg2.dtPosted)
		
			if (date1 < date2) return -1;
			if (date1 > date2) return 1;
			return 0;
		},
		
		buildMessage : function(msg, container){
			var msgContainer = new Element('div', {className:"message"});
			container.insert(msgContainer);
			
			if (msg.url){
				var name = '<a href="' + msg.url + '" target="_blank">' + msg.name + '</a>';
			}else{
				var name = msg.name;
			}
			var title = new Element('div', {className:"msgTitle"}).update(name + this.getText('saidOn')  + msg.dtPosted);
			msgContainer.insert(title);
			var msgTxt = this.nl2br(msg.message.toString().stripScripts(), true)
			var body  = new Element('div', {className:"msgBody"}).insert(msgTxt);
			msgContainer.insert(body);
			
			var reactTo = new Element('div', {className:'msgReactTo'}).update(this.getText('replyTo'));
			msgContainer.insert(reactTo);
			var formContainer = new Element('div', {className:'msgReactForm'});
			msgContainer.insert(formContainer);
			formContainer.hide();
			
			reactTo.formContainer = formContainer;
			reactTo.parentMessage = msg;
			reactTo.observe('click', this.drawForm.bindAsEventListener(this));
			
			
			var children = this.getChildren(msg);

			var more = new Element('div', {className:'msgMore'}).update('[+]');
			msgContainer.insert(more);
			
			more.childMsgs = children;
			
			more.expanded = false;
			more.observe('click', this.toggle.bindAsEventListener(this));
			
			var inlineContainer = new Element('div', {className:'msgMoreContainer'});
			msgContainer.insert(inlineContainer);
			inlineContainer.hide();
			formContainer.threadsContainer = inlineContainer;
			formContainer.moreLink = more;

			more.inlineContainer = inlineContainer;
			if (children.length == 0){
				more.hide() 
			}
			
		},

		
		drawForm : function(e){
			var elem = e.element();
			var container = elem.formContainer;
			
			if (this.currentForm){
				// remove any open forms, just one form at a time..
				this.currentForm.hide();
				this.currentForm.update('');
			}
			this.currentForm = container;
			this.currentForm.parentMessage = elem.parentMessage;
			container.show();
			
			// NAME:
			if (this.readCookie('prName')){
				var defaultName  = this.readCookie('prName');
			}else{
				var defaultName  = this.texts.get('formInputName')
			}
			this.inputName = new Element('input', {type:'text', value:defaultName});
			var inputContainer = new Element('div', {className:'formRow'}).insert(this.inputName);
			container.insert(inputContainer);
			this.inputName.observe('focus', (function(){
				if ( this.inputName.getValue() == this.texts.get('formInputName') ) this.inputName.value ='';
			}).bind(this))
			this.inputName.observe('blur', (function(){
				if (this.inputName.getValue() == '') this.inputName.value = this.texts.get('formInputName');
			}).bind(this))

			// EMAIL
			if (this.readCookie('prEmail')){
				var defaultEmail  = this.readCookie('prEmail');
			}else{
				var defaultEmail = this.texts.get('formInputEmail')
			}
			this.inputEmail = new Element('input', {type:'text', value:defaultEmail});
			var inputContainer = new Element('div', {className:'formRow'}).insert(this.inputEmail);
			container.insert(inputContainer);
			this.inputEmail.observe('focus', (function(){
				if ( this.inputEmail.getValue() == this.texts.get('formInputEmail') ) this.inputEmail.value ='';
			}).bind(this))
			this.inputEmail.observe('blur', (function(){
				if (this.inputEmail.getValue() == '') this.inputEmail.value = this.texts.get('formInputEmail');
			}).bind(this))
			this.inputEmail.observe('change', this.checkEmail.bindAsEventListener(this));

			// URL
			if (this.readCookie('prURL')){
				var defaultURL  = this.readCookie('prURL');
			}else{
				var defaultURL = this.texts.get('formInputURL')
			}
			
			this.inputURL = new Element('input', {type:'text', value:defaultURL});
			var inputContainer = new Element('div', {className:'formRow'}).insert(this.inputURL);
			container.insert(inputContainer);
			this.inputURL.observe('focus', (function(){
				if ( this.inputURL.getValue() == this.texts.get('formInputURL') ) this.inputURL.value ='http://';
			}).bind(this))
			this.inputURL.observe('blur', (function(){
				if (this.inputURL.getValue() == '' || this.inputURL.getValue() == 'http://' ) this.inputURL.value = this.texts.get('formInputURL');
			}).bind(this))

			// message
			this.inputMsg = new Element('textarea', {}).insert(this.texts.get('formInputMsg'));
			var inputContainer = new Element('div', {className:'formRow'}).insert(this.inputMsg);
			container.insert(inputContainer);
			this.inputMsg.observe('focus', (function(){
				if ( this.inputMsg.getValue() == this.texts.get('formInputMsg') ) this.inputMsg.value ='';
			}).bind(this))
			this.inputMsg.observe('blur', (function(){
				if (this.inputMsg.getValue() == '') this.inputMsg.value = this.texts.get('formInputMsg');
			}).bind(this));
			this.inputMsg.observe('change', this.parseMsg.bindAsEventListener(this));// HTML input prevention
			this.inputMsg.observe('keyup', this.countChars.bindAsEventListener(this));// char counter
			this.inputMsgCounter = new Element('div', {className:'formMsgCounter'});
			container.insert(this.inputMsgCounter);
			
			
			this.inputCheck = new Element('input', {type:'checkbox', className:'inputCheckbox', id:'saveName'});
			var inputContainer = new Element('div', {className:'formRow'}).insert(this.inputCheck);
			container.insert(inputContainer);
			var label = new Element('label', {'for':'saveName'}).update(this.getText('setCookie'));
			inputContainer.insert(label);
			if (this.readCookie('prName') && this.readCookie('prEmail') && this.readCookie('prURL')){
				this.inputCheck.checked = true;
			} 
			
			// submitter;
			this.submitter = new Element('button').update(this.texts.get('formInputSubmit'));
			var inputContainer = new Element('div', {className:'formRow'}).insert(this.submitter);
			container.insert(inputContainer);

			this.submitter.observe('click', this.validate.bindAsEventListener(this));
			
			this.errorContainer = new Element('div', {className:'msgReactFormError'});
			container.insert(this.errorContainer);
		},
		
		toggle : function(e){
			var elem = e.element();
			var container = elem.inlineContainer;
			if (!elem.expanded){
				container.show();
				var children = elem.childMsgs;
				//children.reverse();
				children.each(
						(function(msg){
							this.buildMessage(msg, container);
						}).bind(this)
					)
				// update elem:
				elem.update('[-]');
				elem.expanded = true;
			}else{
				// collapse
				container.hide();
				container.update('');
				elem.update('[+]');
				elem.expanded = false;
			}
		},
		
		getChildren : function(msg){
			var children = this.messages.findAll(
				function(m){
					if (m && m.parentID == msg.id) return m;
				}
			);
			if (children.length == 0) return [];
			return children;
		},

		validate : function(){
			this.submitter.disabled = true;
			this.submitter.update(this.getText('validating'));
			// check name, email & message values:
			var ok = true;
			var errMsg = '';
			
			var name = this.inputName.getValue();
			if (name.strip() == '' || name == this.texts.get('formInputName')){
				ok = false;
				errMsg += this.getText('errNoName');
				this.inputName.setStyle('border-color:red;')
			}else if (name.length > 128){
				ok = false;
				errMsg += this.getText('errNameTooLong');
				this.inputName.setStyle('border-color:red;')
			}else{
				this.inputName.setStyle('border-color:green;')
			}

			var email = this.inputEmail.getValue();
			if (email.strip() == '' || email == this.texts.get('formInputEmail') || !this.isEmail(email)){
				ok = false;
				errMsg += this.getText('errEmail');
				this.inputEmail.setStyle('border-color:red;')
			}else if (email.length > 256){
				ok = false;
				errMsg += this.getText('errEmailTooLong');
				this.inputName.setStyle('border-color:red;')
			}else{
				this.inputEmail.setStyle('border-color:green;')
			}
		
			this.inputMsg.value = this.inputMsg.getValue().stripTags();
			var msg = this.inputMsg.getValue();
			if (msg.strip() == '' || msg == this.texts.get('formInputMsg')){
				ok = false;
				errMsg += this.getText('errNoMsg');
				this.inputMsg.setStyle('border-color:red;')
			}else if (msg.length > parseInt(this.maxChars()) ){
				ok = false;
				errMsg += this.getText('errMsgTooLong');
				this.inputName.setStyle('border-color:red;')
			}else{
				this.inputMsg.setStyle('border-color:green;')
			}
			
			if (!ok){
				this.submitter.disabled = false;
				this.submitter.update(this.texts.get('formInputSubmit'));
				this.errorContainer.update(errMsg);
				return;
			}
			if (this.inputCheck.getValue() == 'on'){
				this.createCookie('prName', this.inputName.getValue());
				this.createCookie('prEmail', this.inputEmail.getValue());
				this.createCookie('prURL', this.inputURL.getValue());
			}else{
//				this.eraseCookie('prName');
//				this.eraseCookie('prEmail');
//				this.eraseCookie('prURL');
			}			
			// request post-serial
			this.requestPost();
		},
		
		requestPost : function(){
			this.submitter.update(this.getText('requestPost'));
			// request a serial from server:
			var rpc = new rpcClient(this.uri, this.apiKey);
			this.waiter(this.container);
			if (this.debug) rpc.debug = true;
  			rpc.createCall('react', 'requestPost', {'ref':this.ref});
  			rpc.execute(this.postMessage.bind(this));
		},
		
		postMessage :function(req, rpc){
			var serial = rpc.toObject().responses.response.serial;
			if (this.currentForm.parentMessage) {
				var parent = this.currentForm.parentMessage.id;
			}else{
				var parent = 0;
			}
			if ( this.inputURL.getValue() != this.texts.get('formInputURL') ){
				var url = this.safeStr(this.inputURL.getValue());
			}else{
				var url = '';
			}
			var rpc = new rpcClient(this.uri, this.apiKey);
			if (this.debug) rpc.debug = true;
  			rpc.createCall('react', 'post', {
  				'ref' : this.ref, 
  				'serial' : serial,
  				'name' : this.safeStr(this.inputName.getValue()),
  				'email' : this.safeStr(this.inputEmail.getValue()),
  				'url' : url,
  				'message' : this.safeStr(this.inputMsg.getValue()),
  				'parent' : parent
  			});
  			rpc.execute(this.reloadThread.bind(this));
		},
		
		reloadThread : function(req, rpc){
			try{
				if (rpc.toObject().responses.response.exception){
					alert(this.getText('errPosting'));
					this.submitter.update(this.getText('retryPost'));
					this.submitter.disabled = false;
					return;
				}
				if (!( rpc.toObject().responses.response.message instanceof Array) ){
					var messages = [rpc.toObject().responses.response.message];
				}else{
					var messages = $A(rpc.toObject().responses.response.message);
				}
				
				messages = this.sortByDate(messages);
//				messages = this.messages.reverse();
				
				var container = this.currentForm.threadsContainer;
				this.currentForm.moreLink.update("[-]");
				this.currentForm.moreLink.expanded = true;
				this.currentForm.moreLink.show();
				container.update('');
				container.show();
				messages.each(
						(function(msg){
							this.buildMessage(msg, container);
						}).bind(this)
					)
				this.currentForm.hide();
				this.currentForm.update('');
				this.currentForm = null;
				this.unWaiter();
			}catch(e){
				if (this.debug) console.log(e)
			}
		},
		
		/**
		 * HELPERS
		 */
		
		countChars : function(){
			// set counter:
			var elem = this.inputMsg;
			var chars = parseInt(this.maxChars()) - parseInt(elem.getValue().length);
			this.inputMsgCounter.update(chars + this.getText('charsLeft'));
			if (parseInt( chars)  < 0){
				this.inputMsgCounter.setStyle('color:red');
			}else{
				this.inputMsgCounter.setStyle('color:black');
			}
		},
		
		maxChars : function(){
			return 280;
			if (PrototypeMod.Browser.IE){
				return 1500;
			}else{
				return 3500
				
			}
		},
		
		safeStr : function(value){
			return encodeURIComponent(value.stripTags());
		},
		
		parseMsg : function(e){
			// strip HTML from element:
			var elem = e.element();
			elem.value = elem.getValue().toString().stripTags();
		},
		
		checkEmail: function(e){
			var elem = e.element();
			if (!this.isEmail(elem.getValue())){
				elem.setStyle('border-color:red');
			}else{
				elem.setStyle('border-color:black');				
			}
		},
		
		isEmail: function(emailStr){
			var checkTLD=1;
			var knownDomsPat=/^(com|net|org|edu|int|mil|gov|arpa|biz|aero|name|coop|info|pro|museum)$/;
			var emailPat=/^(.+)@(.+)$/;
			var specialChars="\\(\\)><@,;:\\\\\\\"\\.\\[\\]";
			var validChars="\[^\\s" + specialChars + "\]";
			var quotedUser="(\"[^\"]*\")";
			var ipDomainPat=/^\[(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\]$/;
			var atom=validChars + '+';
			var word="(" + atom + "|" + quotedUser + ")";
			var userPat=new RegExp("^" + word + "(\\." + word + ")*$");
			var domainPat=new RegExp("^" + atom + "(\\." + atom +")*$");
			var matchArray=emailStr.match(emailPat);

			if (matchArray==null) {
				return false;
			}

			var user=matchArray[1];
			var domain=matchArray[2];

			for (i=0; i<user.length; i++) {
				if (user.charCodeAt(i)>127) {
					return false;
				}
			}

			for (i=0; i<domain.length; i++) {
				if (domain.charCodeAt(i)>127) {
					return false;
				}
			}
			
			if (user.match(userPat)==null) {
				return false;
			}

			var IPArray=domain.match(ipDomainPat);
			
			if (IPArray!=null) {
				for (var i=1;i<=4;i++) {
					if (IPArray[i]>255) {
						return false;
			   		}
				}
				return true;
			}
			
			 
			var atomPat=new RegExp("^" + atom + "$");
			var domArr=domain.split(".");
			var len=domArr.length;

			for (i=0;i<len;i++) {
				if (domArr[i].search(atomPat)==-1) {
					return false;
			   }
			}

			if (checkTLD && domArr[domArr.length-1].length!=2 && domArr[domArr.length-1].search(knownDomsPat)==-1) {
				return false;
			}

			if (len<2) {
				return false;
			}
			
			return true;
		},
		
		waiter : function(){
			
		},

		unWaiter : function(){
			
		},

		getText : function(key){
			
			var textObj = prLang[this.lang];
			return textObj[key];
		},
		nl2br : function (str, is_xhtml) {
		    var breakTag = '';

		    breakTag = '<br />';
		    if (typeof is_xhtml != 'undefined' && !is_xhtml) {
		        breakTag = '<br>';
		    }

		    return (str + '').replace(/([^>]?)\n/g, '$1'+ breakTag +'\n');
		},
		
		error : function(msg){
			if (window.console) {
				console.log(msg)
			}else{
				if (this.container) {
					this.container.update('<span style="color:red;">' + msg + '</span>');
				}else{
					alert(msg);
				}
			}
		},
		
		createCookie : function(name,value) {
			var date = new Date();
			date.setTime(date.getTime()+(720*24*60*60*1000));
			var expires = "; expires="+date.toGMTString();
			document.cookie = name+"="+value+expires+"; path=/";
		},

		readCookie : function (name) {
			var nameEQ = name + "=";
			var ca = document.cookie.split(';');
			for(var i=0;i < ca.length;i++) {
				var c = ca[i];
				while (c.charAt(0)==' ') c = c.substring(1,c.length);
				if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
			}
			return null;
		},

		eraseCookie : function(name) {
			createCookie(name,"",-1);
		}
		
		
	})
	
