//class is in
var Typewriter = new Class({
	
	//implements
	Implements: [Options],

	//options
	options: {
		container: '',
		message: '',
		delay: 70,
		cursor: 0,
		variance: 10,
		tag: 'div',
		attribs: {},
		backChar: '|',
		backDelay: 90,
		delayChar: '^',
		delayCharTime: 1200,
		totalLength: false,
		bkgContainer: 'bkg',
		debug: false,
		onComplete: $empty,
		action: ''
	},
	
	//initialization
	initialize: function(options) {
		//set options
		this.setOptions(options); 
		
		if(!this.options.message) {
		new Element(this.options.tag).setProperties(this.options.attribs).inject($(this.options.container));
		this.stopped = true;
		return;	
		}
		
		this.SZ = document.getSize();
		this.cursor = this.options.cursor;
		this.letters = 0;
		this.foundletters = 0;
		this.completed=false;
	
		if(this.options.attribs.rel=='over-alter') this.options.action = 'over-alter';
		
		this.mainContainer = new Element(this.options.tag).setProperties(this.options.attribs).inject($(this.options.container));
		this.options.message = this.options.message.replace(/\s+/g,'&#160;');
		if(this.options.debug) {
			this.debug = new Element('div',{'id':'debug'}).inject( $(this.options.container).getParent() ,'top');
		}
		//this.matrixWorm(100);	
	},
	
	//start the Typewriter
	start: function() {
		
		if(this.stopped) {
			this.options.onComplete();	
			return;
		}
	
		if (this.options.message.charAt(0)=='<') return;
		//for every letter
		this.evalLetter(0,this.options.message.length);
	},
	
	evalLetter: function(x, num) {
		
		if(x>=num) return;
		
			var pace = this.options.delay;
			/*var pace = (this.options.delay * x) + $random(0,this.options.variance);*/
			var current = this.options.message.charAt(x);
			
			
			if(current=='&') {
				Cr = '';
				skip=true;
				sec=0;
				while(current!=';'&&sec<10) {
					current = this.options.message.charAt(x);
					Cr += current; 
					x++;
					sec++;
				}
				x--;
			} else {
				Cr = current;
			}
			
			if(Cr == this.options.backChar) {
				this.processing = true;
				this.deleteLetter.delay(pace + this.options.backDelay,this,[x+1,num]);
			} else if(Cr == this.options.delayChar) {
				this.processing = true;
				this.waitLetter.delay(this.options.delayCharTime,this,[x+1,num]);
			} else {
				this.letters++;
				this.setLetter(Cr);
				this.evalLetter.delay(this.options.delay,this,[x+1,num]);
			}
				// $('debug').set('html',Cr+":"+x);
			//
	},
	
	//place the newest letter in the container
	setLetter: function(C) {
		if(!C) return;
		//this.mainContainer.set('html',this.mainContainer.get('html') + '' + this.options.message.charAt(this.cursor));
		var rd = $random(0,this.options.variance); var frd = this.options.variance*0.9;
		var vrd = (rd>frd)? rd*2 : rd;
		/*var offset = (this.options.message.length-this.cursor*C.length) + vrd;*/
		var offset = this.options.variance + vrd;
		if(C==' ') C = '&#160;';
		var SP = new Element('span',{'html': C, '_v':C, '_s':offset }).inject(this.mainContainer,'bottom');
		
		if(C!='&#160;') {
			/*$(SP).addEvents({
				'mouseover':this.alterLetter.bind(this,SP),
				//'click':this.dropLetter.bind(this,[$(this.options.bkgContainer).getChildren()[50],true])
				'click':this.alterLetter.bind(this,[SP,3,true])		
			});*/
			if(this.options.action=='over-alter') {
				$(SP).addEvent( 'mouseover',this.alterLetter.bind(this,SP) );
			}
			if(this.options.action=='click-alter') {
				$(SP).addEvent( 'click',this.alterLetter.bind(this,[SP,3,true]) );
			}
		}
		this.alterLetter(SP,offset) ;
		//increment cursor
		this.cursor++;
	},
	
	alterLetter: function(letter, offset, expand, speed) {
		if(!letter) return;
		if(!speed) speed = this.options.backDelay ;
		var S;
		var V = letter.getProperty('_v');
		if(V!='&#160;' && V!=' ') {
			if(!offset) { 
				offset = 20;
				letter.setProperty('_s',offset ) ;
			}
			
			if(expand) { letter.setProperty('_s',offset ) ; S = offset; }
			else S = letter.getProperty('_s') ;
			
			var L = this.alterChar();
			
			if (L!=' ') letter.innerHTML = L ;
			if(S > 0) {
				letter.setProperty('_s',S-1 ) ;
				this.alterLetter.delay(speed*0.2, this, [letter,S]);
			} else { 
				letter.innerHTML = letter.getProperty('_v') ;
				this.foundletters++;
			}			
		} else {
			this.foundletters++;
		}
		if(this.options.debug) this.debug.set('html','LETTERS: '+this.letters+' FOUND: '+this.foundletters); 
		if(this.letters==this.foundletters&&!this.processing) {
			if(this.options.action=='') {
				var VH = this.removeHTMLTags( this.mainContainer.get('html') );
				this.mainContainer.empty();
				this.mainContainer.set('html',VH);
			}
			if(!this.completed) {
				this.options.onComplete();
				this.completed=true;
			}
		}		

		if(expand) {
			if(expand!='next') { try { this.alterLetter.delay(speed*0.4, this, [letter.getPrevious(),2,'prev']); } catch(er){} }
			if(expand!='prev') { try { this.alterLetter.delay(speed*0.4, this, [letter.getNext(),2,'next']); } catch(er){} }
		}
		return false;
	},
	
	alterChar: function() {
			var L = $random(33,255);
			while((L>126 && L<161) || L < 33 || L > 255) L = $random(33,255);
			return  String.fromCharCode(L) ;	
	}, 
	
	dropLetter: function(letter,viral) {
		
		if(!letter) return;
		if(!viral) viral = false;
		
		var P = letter.getPosition();
		
		if(!letter.getProperty('_p')) {		
			letter.setProperty('_p',1 );
			letter.style.position = 'fixed';
			letter.style.left = P.x;
			letter.style.top = P.y;
		}
		
		var Pd = letter.getProperty('_p');
		letter.setProperty('_p',Pd*10);
		var Py = P.y+(Pd*2);
		letter.style.top = Py+'px';
		
		if(Pd==1&&viral) {
			if(viral!='next') this.dropLetter.delay(this.options.backDelay*0.01, this, [letter.getPrevious(),'prev']); 
			if(viral!='prev') this.dropLetter.delay(this.options.backDelay*0.01, this, [letter.getNext(),'next']);
		}
		
		if(document.getSize().y*2>Py) this.dropLetter.delay(this.options.backDelay*0.1, this, letter);
		else {
			letter.destroy();
		}
	},
	
	waitLetter: function(x, num) {
		this.processing = false;
		if(x>=num) {
			this.options.onComplete();
			return;
		}
		this.evalLetter(x, num);
	},
	//deletes a letters -- goes backward
	deleteLetter: function(x, num) {
		this.mainContainer.getLast().destroy();
		this.letters--;
		this.foundletters--;
		this.cursor++;
		this.processing = false;
		if(x>=num) {
			this.options.onComplete();
			return;
		}
		this.evalLetter(x, num);
	},
	
	shineLetter: function(letter, up) {
		if(!letter) return; 
		if(!letter.getProperty('_i')) letter.setProperty('_i',128);
		var OC = (letter.getProperty('_ii'))? letter.getProperty('_ii') : letter.getProperty('_i') ;
		var CC = (OC).toInt() + (up? 10: -10);
		if(CC>255) CC = 255;
		if(CC<1) CC = 1;
		letter.setProperty('_ii',CC);
		
		letter.style.color = 'rgb('+CC+','+CC+','+CC+')';
		
		if(up && CC<255) { this.shineLetter.delay(20, this, [letter,true]); }
		if(!up&& CC>(letter.getProperty('_i')).toInt() ) { this.shineLetter.delay(20, this, letter); }
	},
	
	autochangeLetter: function(letter,delay) {
		if(!letter) return;
		letter.innerHTML = this.alterChar();
		this.autochangeLetter.delay(delay,this,[letter,delay]);
	},
	
	randomWorm: function(left) {
		var dS = document.getSize();
		var coords = {'x':$random(0,this.SZ.x-20), 'y':$random(0,this.SZ.y-20),'z':$random(5,15)};
		var depth = $random(0,999); var C = (depth*0.255).toInt();
		var WRM = new Element('span',{'html': this.alterChar(),'_i':C }).setStyles({'color': 'rgb('+C+','+C+','+C+')','z-index': depth, 'position':'fixed', 'top':coords.y,'left':coords.x }).inject($(this.options.bkgContainer));
		this.letterMove(WRM,coords,{'x':$random(-5,5),'y':$random(-5,5),'z':$random(-3,1)},true);
		/*WRM.addEvents({	'click' : this.dropLetter.bind(this,[WRM,true])
					//'mouseover' : this.shineLetter.bind(this,[WRM,true]),
					// 'mouseout' : this.shineLetter.bind(this,WRM)				
		});*/
		//this.dropLetter.delay(1000,this,[WRM,true]);
		//this.autochangeLetter.delay(this.options.backDelay,this,[WRM,this.options.backDelay]);
		
		if(left&&left>0) {
			this.randomWorm.delay((this.options.backDelay*0.05).toInt(), this, left-1);
		}
		
		//while(this.SZ.y*2>Py) {  }
		return false;
	
	},
	
	letterMove: function(letter,pos,speed,Z) {
		if(!letter) return;
		pos.y = pos.y + speed.y;
		pos.x = pos.x + speed.x;
		pos.z = pos.z + speed.z;
		var color = (pos.z*255/120).toInt();
		letter.setStyles({'top':pos.y, 'left':pos.x, 'color':'rgb('+color+','+color+','+color+')'});
		if(Z) letter.setStyle('font-size',pos.z );
		if(pos.y>this.SZ.y || pos.x>this.SZ.x || pos.z < 1 || pos.z > 120) { letter.destroy(); this.randomWord(); return; }
		this.letterMove.delay(this.options.backDelay, this, [letter,pos,speed,Z]);
		
	},
	
	matrixWorm: function(left) {
		
		var P = $random(2,60); var z = $random(80,160) ;
		var params = {'x':$random(0,this.SZ.x-20), 'y':$random(0,this.SZ.y-20), 'z': z, 'p':P, 'i':(z/P).toInt(), 'r':$random(0,3), 'n':0 };
		var C = this.alterChar();
		var WRM = new Element('span').setStyles({'color': 'rgb('+params.z+','+params.z+','+params.z+')','font-size': (5+z/20).toInt(), 'z-index': params.z, 'position':'fixed', 'top':params.y,'left':params.x }).inject($(this.options.bkgContainer));
		this.letterMatrixFall(WRM,params,C,true);
		if(left&&left>0) {
			this.matrixWorm.delay((this.options.backDelay*0.02).toInt(), this, left-1);
		}
		return false;
	},
	
	letterMatrixFall: function(letter,params, i, W) {
		if(!letter) return;
		if(params.p < 1) return;
			params.z -= params.i;
			if (params.z < 1) return;
			var MF = new Element('span',{'html': this.alterChar()}).setStyles({'color': 'rgb('+params.z+','+params.z+','+params.z+')','z-index': params.z, 'position':(W)?'fixed':'absolute', 'top':(W)? params.y:params.n*(-15),'left':W? params.x :((params.r==0)?$random(-params.n,params.n):0) });
			if(W) MF.inject($(letter));
			else  MF.inject($(letter).getParent());
		if(W) letter.interval = this.letterMFall.periodical(100, this, [letter,15+$random(0,15),params.p]);
		params.p --;
		params.n ++;
		this.letterMatrixFall(MF,params,i);

	},
	
	letterMFall: function(letter,dist,size) {
		
			var T = letter.style.top.toInt()+dist ;
			letter.setStyle('top', T);
			letter.firstChild.innerHTML = this.alterChar();
		
		if(T>this.SZ.y+(size*15)) { 
			this.matrixWorm.delay(100,this,0);
			$clear(letter.interval); 
			letter.destroy(); 
			return; 
		
		}
	},

	removeHTMLTags: function (ObjString){
	 		return ObjString.replace(/<\/?[^>]+(>|$)/g, "");
 	}	

	
});
