var dom    = typeof window.addEventListener == "function";
var ie     = typeof window.attachEvent == "object";
var opera  = window.opera?true:false;

var countWords		= 0;
var c_position		= 0;
var waitPressKey	= 1000; // 1000 == 1 секунда
var waitBackToSpace = 1000;

//var past_query       = '';
var double_flag        = 0;

var temp_html_all_text = '';
var temp_html_h        = '';
var temp_html_b        = '';
var temp_count_w       = 0;

// Статистика скорости
var stat_speed = {};

//var nbsp = opera?"&nbsp;":"&nbsp;";

var ws_w  = null; // Статистика слов
var ws_l  = null; //Статистика строк
var ws_fe = null; //Статистика скорости до первой ошибки.

var pauseDuration = 0; 		// Пауза между нажатием клавиш, если болье pauseDurationMax времени, то статистика не отсылается.
var pauseDurationMax = 0; // Максимально допустимое время между вводом текста. (в секундах)  

var wrds_by_speed  = null;
var lines_by_speed = null;
var statistic_mods = {'standart':true,'serfing':true,'error-free-line':true,'error-free':true,'profi':true,'words_desc':false,'letter_comb':false,'original_lines':false};

var php_file  = 'freetyping.php';


function setToErrorLones(){	
	if(confirm('Вы заметили ошибку в этом тексте и хотите сообщить о ней нашим редакторам?')){	
		var ajax  = js.ajax;	
		ajax.send(php_file, 'type=setErrorLines',function(){},null,true);
	}
}

//function getErrorLones(){	
//	var ajax  = js.ajax;	
//	ajax.send('freetyping.php', 'type=getErrorLines',function(){},null,true);	
//}


function Set_Source(radio){
	var f 	   = radio.form,
	  	source = getCheckedRadio(f.resourse);	
	f.file.disabled = source == 'self_text'?false:true;
	f.file.style.visibility = source == 'self_text'?'visible':'hidden';
	f.random.disabled = source == 'self_text'?true:false;
	f.etalon.disabled = source == 'self_text'?true:false;
	f.settoerror.disabled = source == 'self_text'?true:false;
	
	
	makeRquest('mode='+source);
}
function ShowDialogWnd(){
	var t_obj = getSelectedOptions(document.forms[0].sl_object_type); //var t_obj = getCheckedRadio(document.forms[0].object_type);
	var st = (t_obj == 'lines'?ws_l:ws_w); 
	
	list_wnd.Wnd_Show(st); 
}
function HiddenDialogWnd(str){
	if(str != '' && getSelectedOptions(document.forms[0].sl_object_type) != 'text'){
		//setAttrToRadio(document.forms[0].correct,'disabled','','chose_words');
		setAttrToOptions(document.forms[0].sl_correct,'disabled',false,'chose_words');
	}
}

function SetDefaultMode(sl){
//	var val = getSelectedOptions(sl);	
}

function GetDefaultMode(){
	var val = getSelectedOptions(document.forms[0].defaultMode);
	if(!val || val == 'no')return;
	setAttrToRadio(document.forms[0].typing, 'checked', 'checked', val);
}

function SetStatisticVisible(chBox){	
	var ch = {'show_stat_speed':'cont_speed','show_stat_errors':'cont_error','show_stat_letters':'cont_letters','show_stat_time':'cont_time','show_stat_line_speed':'line_state'};	
	
	if(!(chBox instanceof  Array)){
		chBox = [chBox];
	}
	
	for(var c in chBox){
		if(ch[chBox[c].name]){		
			document.getElementById(ch[chBox[c].name]).style.visibility = chBox[c].checked?'visible':'hidden';
		}
	}
}

function SetCustomStatisticVisible(statLns, stat){
	var sl,el;
	for(var i=0,l=statLns.length; i<l; i++){
		if((el = document.getElementById(statLns[i])))
			el.style.visibility = stat;	
	}
	
}

function SetLinesSpeed(speed){	
	var l = document.getElementById('line_state');
	if(speed == -1) return l.innerHTML = '<span>&nbsp;&nbsp;&nbsp;</span><br>';
	if(l.firstChild.innerHTML == '&nbsp;&nbsp;&nbsp;')
		l.firstChild.innerHTML = speed;
	else
		l.innerHTML += '<span>'+speed+'</span><br>';
}


function setChampions(obj){
	var type  = obj.options[obj.selectedIndex].value;
	if(type == 'none')return;
	makeRquest('type=champions&book='+type);	
	
	
}

// Обработка HTML событий, установка насроек тренировки
function setCursorColor(obj){
	
	if(!obj)obj = document.forms[0].cursor_color;	
	var classN  = obj.options[obj.selectedIndex].value;
	obj.className = classN;	
	cursor_color  = classN;
	if(curr_node.className)
	curr_node.className = classN;
	
}
// TODO: Удалить эту функцию !! или нет :) ??
function setCorrectTyping(flag){
	var c,i,f = document.forms[0];	
	c = f.correct;
	i = c.length;
	while(i--){
		if(c[i].value != 'chose_words')
		c[i].disabled = flag?'':'disabled';
	}	
	c[0].disabled = '';	
}

// Получение строки в обработке алгоритма 16, на сервере. 
function getTextAlg_16(str){
	
	if(!str){
		str   = nodeListToString(area.childNodes);
		temp_html_all_text      = area.innerHTML;
	}
	if(str.split('^').length > 3){
		alert('Не более 3-х строк !');
		return false;
	}
	str       = str.replace(/&nbsp;/ig,' ');	
	var ajax  = js.ajax;	
	var str   = ajax.send(php_file, "get_alg_16=1&text="+str,null,null,true,true).responseText;	
	str       = str.replace(/<br>/ig,'^');
	str       = str.replace(/\\/ig,'');
	
	//letterComb.Fill(str, parseInt(getCountLine()));
	letterComb.Fill(str, 1);
	str = letterComb.NextLine();	
	js.$('letter_comb_position').innerHTML = "Отработано строк: "+(letterComb.curr_pos-1)+"/"+letterComb.arr_str.length+".";				
	return str;				

}

//
//function SetObjectOfTyping(){
//	var f = document.forms[0];
//	var s = getCheckedRadio(f.object_type);
//	
//	var i = f.correct_type.length,
//		c = f.correct_type,
//		v = '',
//		t = 'all_words';
//	
//	while(i--){
//		c[i].disabled = '';
//		if(s == 'text'){
//			c[i].disabled = 'disabled';
//			c[i].checked = '';
//			v = 'disabled';
//		}else 
//		if(s == 'words'){
//			if(c[i].value == 'original_lines')			
//				c[i].disabled = 'disabled';
//			else if(c[i].value == 'words_desc')
//				c[i].checked = 'checked';
//		}else 
//		if(s == 'lines'){
//			if(c[i].value == 'original_lines')			
//				c[i].checked = 'checked';
//		}		
//	}
//	
//	
//
//	if(s == 'text'){		
//		stoped = true;
//		setAttrToRadio(f.correct,'checked','');
//		setAttrToRadio(f.correct,'disabled','disabled');	
//		SetTempText(false);
//		SetDisabledToControls('');
//		initTyping();	
//		return;
//	}
//	
//	ws_l.Stop();
//	ws_w.Stop();
//
//	
//	ws_w.getBySpeed();
//	
//	if(_err_nds.length > 0)         t+= ',error_word'; 
//	if(ws_w.stat_wrd_arr.length > 0)t+= ',very_fast_words,fast_words,slow_words,very_slow_words';
//	if(list_wnd.str.length > 0)     t+= ',chose_words';
//		
//	if(!getCheckedRadio(f.correct)){
//		setAttrToRadio(f.correct, 'checked', 'checked','all_words');
//	}	
//	
//	setAttrToRadio(f.correct,'disabled',v,t);	
//	SetDisabledToControls('disabled');
//	SetCatTyping();
//}

function SL_SetObjectOfTyping(){
	var f = document.forms[0];
	var s = getSelectedOptions(f.sl_object_type);
	
	var i = f.sl_correct_type.length,
		c = f.sl_correct_type,
		v = false,
		t = 'all_words';
	
	setAttrToRadio(c,'disabled',false);
	
	while(i--){
		c.disabled = '';
		if(s == 'text'){
			//c.options[i].disabled = 'disabled';
			//c.options[i].selected = 'selected';
			v = true;
		}else 
		if(s == 'words'){
			if(c.options[i].value == 'original_lines')			
				c.options[i].disabled = 'disabled';
			else if(c.options[i].value == 'words_desc')
				c.options[i].selected = 'selected';
		}else 
		if(s == 'lines'){
			if(c.options[i].value == 'original_lines')			
				c.options[i].selected = 'selected';
		}		
	}
	
	

	if(s == 'text'){		
		stoped = true;
		//setAttrToRadio(f.correct,'checked','');
		//setAttrToRadio(f.correct,'disabled','disabled');
		f.sl_correct_type.selectedIndex = -1;
		f.sl_correct.selectedIndex = -1;

		setAttrToOptions(f.sl_correct_type, 'disabled', 'disabled');
		setAttrToOptions(f.sl_correct, 'disabled', 'disabled');
		
		f.sl_correct.disabled     = 'disabled';
		f.sl_correct_type.disabled = 'disabled';
		
		js.$('letter_comb_position').innerHTML = "";			
		
		SetTempText(false);
		SetDisabledToControls('');
		initTyping();
		
		return;
	}

	
	ws_l.Stop();
	ws_w.Stop();

	
	ws_w.getBySpeed();
	
	if(_err_nds.length > 0)         t+= ',error_word'; 
	if(ws_w.stat_wrd_arr.length > 0)t+= ',very_fast_words,fast_words,slow_words,very_slow_words';
	if(list_wnd.str.length > 0)     t+= ',chose_words';
	//alert(getSelectedOptions(f.sl_correct))
	if(!getSelectedOptions(f.sl_correct) || (f.sl_correct.selectedIndex != -1 && f.sl_correct.options[f.sl_correct.selectedIndex].disabled)){ // второе условие Примочка для IE !!
		f.sl_correct.disabled = false;
		setAttrToOptions(f.sl_correct, 'selected',true,'all_words');
	}	
	
	setAttrToOptions(f.sl_correct,'disabled',v,t);	
	SetDisabledToControls('disabled');
	SL_SetCatTyping();
}

function SL_SetCorrectTyping(){	
	SL_SetCatTyping();
}
function SetTempText(flag){
	if(flag && temp_html_h == ''){
		temp_html_h      = js.$('textarea').innerHTML;
		temp_html_b      = js.$('authorName').innerHTML;
		temp_count_w     = countWords;
		countWords       = 0;
	}else if(!flag && temp_html_h != ''){
		temp_html_h = temp_html_h.replace(/<span[^>]+>/ig,'<span>');
		temp_html_h = temp_html_h.replace(/<span>/i,'<span class="cursor_01">');		
		js.$('textarea').innerHTML = temp_html_h;
		js.$('authorName').innerHTML = temp_html_b;
		countWords = temp_count_w;
		temp_count_w = 0;
		temp_html_h   = '';
		temp_html_b  = '';		
	}	
	
}
function SetDisabledToControls(v){
	var f = document.forms[0];
	var vsbl = v=='disabled'?'visible':'hidden';
	f.autor.disabled  = v;
	f.random.disabled = v;
	f.back.disabled   = v;
	f.begin.disabled  = v;
	f.next.disabled   = v;
	f._end.disabled   = v;
	
	f.search_start.disabled   = v;
	f.etalon.disabled   = v;
	f.view_modes.disabled   = v;
	
	f.openWnd.disabled   = v;
	f.settoerror.disabled   = v;	
	
	
	f.tryAgen.disabled      = v;
	f.cursor_color.disabled = v;
	f.countLine.disabled    = v;
	//f.championsLine.disabled    = v;
	//f.openWnd.disabled    = v;
	
	js.$('cont_ttl_cat').style.visibility  = vsbl;
	js.$('cont_ttl_view').style.visibility = vsbl;
	f.sl_correct.style.visibility          = vsbl;
	f.sl_correct_type.style.visibility     = vsbl;
	
	setAttrToRadio(f.typing,'disabled',v);
	setAttrToRadio(f.resourse,'disabled',v);
	
	
}

function SL_SetCatTyping(){
	 
	var form   = document.forms[0],
		t_obj  = getSelectedOptions(form.sl_object_type),
		t_view = getSelectedOptions(form.sl_correct_type),
		t_cat  = getSelectedOptions(form.sl_correct);
	//alert(form.sl_correctl.options[form.sl_correctl.selectedIndex].innerHTML)
	var by_speed = {'very_fast_words':true,'fast_words':true,'slow_words':true,'very_slow_words':true},
	str      = '';
	stoped = true;
	if(t_obj == undefined || t_view == undefined || t_cat == undefined)return;
	if(t_cat == 'chose_words' && list_wnd.str == ''){stopEvent(SL_SetCatTyping.caller.arguments[0]);return;}
	stoped = false;
	
	SetTempText(true);	
	ws_w.getBySpeed();
	ws_l.getBySpeed();
	
	if(!_err_str || _err_str.length == 0){
		_err_str       = makeErrorWords(_err_nds);
		_err_str_lines = makeErrorLines(_err_nds); // return lines winth ^ 
	}
	
	
	
	if(by_speed[t_cat]){
			if(t_obj == 'words')
			str = GetWordsBySpeed(t_cat);
		else if(t_obj == 'lines')
			str = GetLinesBySpeed(t_cat);
	}else if(t_cat == 'error_word'){		
		str = (t_obj == 'words'?_err_str:_err_str_lines);		
	}else if(t_cat == 'all_words'){
		str = getStringFromHTML(temp_html_h);
					
	}else if(t_cat == 'chose_words')
		str = list_wnd.str;		
	
		if(t_view == 'words_desc'){
			if(t_obj == 'words'){
				str = trim(str);
				str = RemoveDividerFromString(str);
				str = trim(StrSortByLength(str,'DESC').join(' '));
			}else if(t_obj == 'lines'){
				str = LinesSortByLength(str,'DESC');				
			}				
		}
		
		if(t_view == 'letter_comb')
			str = getTextAlg_16(str);
		else
			js.$('letter_comb_position').innerHTML = "";
		
		if(!str) return;
		if(t_obj == 'words' || (t_obj == 'lines'  &&  by_speed[t_cat]))
			str = AddDividerToString(str);
	
	countWords = 0;
	
	js.$('textarea').innerHTML   = parseStringToWorld(str);
	initTyping();	
	
}
//function SetCatTyping(){
//	 
//	var form   = document.forms[0],
//		t_obj  = getCheckedRadio(form.object_type),
//		t_view = getCheckedRadio(form.correct_type),
//		t_cat  = getCheckedRadio(form.correct);
//	
//	var by_speed = {'very_fast_words':true,'fast_words':true,'slow_words':true,'very_slow_words':true},
//		str      = '';
//	stoped = true;
//	if(t_obj == undefined || t_view == undefined || t_cat == undefined)return;
//	if(t_cat == 'chose_words' && list_wnd.str == ''){stopEvent(SetCatTyping.caller.arguments[0]);return;}
//	stoped = false;
//	
//	SetTempText(true);	
//	ws_w.getBySpeed();
//	ws_l.getBySpeed();
//	
//	if(!_err_str || _err_str.length == 0){
//		_err_str       = makeErrorWords(_err_nds);
//		_err_str_lines = makeErrorLines(_err_nds); // return lines winth ^ 
//	}
//	
//	
//	if(by_speed[t_cat]){
//			if(t_obj == 'words')
//			str = GetWordsBySpeed(t_cat);
//		else if(t_obj == 'lines')
//			str = GetLinesBySpeed(t_cat);
//	}else if(t_cat == 'error_word'){		
//		str = (t_obj == 'words'?_err_str:_err_str_lines);		
//	}else if(t_cat == 'all_words'){
//		str = getStringFromHTML(temp_html_h);
//					
//	}else if(t_cat == 'chose_words')
//		str = list_wnd.str;		
//	
//		if(t_view == 'words_desc'){
//			if(t_obj == 'words'){
//				str = trim(str);
//				str = RemoveDividerFromString(str);
//				str = trim(StrSortByLength(str,'DESC').join(' '));
//			}else if(t_obj == 'lines'){
//				str = LinesSortByLength(str,'DESC');				
//			}				
//		}
//		
//		if(t_view == 'letter_comb')
//			str = getTextAlg_16(str);
//		else
//			js.$('letter_comb_position').innerHTML = "";
//		
//		if(t_obj == 'words' || (t_obj == 'lines'  &&  by_speed[t_cat]))
//			str = AddDividerToString(str);
//	
//	countWords = 0;
//	js.$('textarea').innerHTML   = parseStringToWorld(str);
//	initTyping();	
//	
//}

function setSmile(set){
	var str = ':)';
	if(set)str = ':|';	
	js.$('smile').innerHTML = str;
}
function getCountLine(){
	var line = document.forms[0].countLine;
	return line.options[line.selectedIndex].value;
}
function setCountLines(line){
	makeRquest('move=current');	
	resetStatistics();	
}
function setTimerFld(time){
	timerFld.innerHTML = time;
}
function setSpeedFld(){	
	//js.$('speed').innerHTML = parseInt(countWords/(timer.seconds/60));
}
function setErrorsFld(time){	
	js.$('errors').innerHTML = errors==0?"-":errors;
}

/* -- Обработка и загрузка текста по различным параметрам -- */

function makeRquest(query,callBack){
	countWords = 0;
	js.$('textarea').innerHTML   = '<center>Загружаю...</center>';
	var ajax  = js.ajax;	
	ajax.send(php_file, query+"&count_line="+getCountLine(), callBack?callBack:loadedText,null,true);	
	
}
/** Обработка нажатия кнопок "Автор", "Случайный", "Эталонный" */
function startLesson(name){	
	GetDefaultMode();
	if(name == 'etalon'){
		setAttrToOptions(document.forms[0].countLine, 'selected', 'selected', '4');
	}
	makeRquest('type='+name);	
}

/** Обработка нажатия кнопок с "Вверх","Назад","Начало","Конец */
function moveTo(derection){
	makeRquest('move='+derection);
} 

// Закладки <--
/** Обработка нажатия ссылок с "Закладки" */
function byBookmark(id){		
	makeRquest('type=bybookmark&id='+id);	
}

/** Обработка нажатия кнопок с "Добавить закладку...." */
function addBookmark(){
	makeRquest('type=addbookmark',addedBookmark);
}

function cleanBookmark(id){	
	makeRquest('type=cleanbookmark'+(id?'&id='+id:''),addedBookmark);
}
/*
function addedBookmark(text){
	startLesson('showbookmarks');
}
*/
// -->
// Загрузка ajax данных 
function loadedText(res){
	var form  = js.$$('form')[0];
	var arr,text;
	arr = res.responseText.split("#");	
	
	/*if(arr[2] == 'bookmarks'){
		js.$('bookmarks').style.display = 'block';
		js.$('bookmarks').innerHTML   = arr[0];		
		return;
	}
	*/
	
	if(arr[2] == 'book_fin'){
		form.next.disabled = 'disabled';
	}else if(arr[2] == 'book_start'){
		form.back.disabled = 'disabled';
	}else {
		form.next.disabled  = '';
		form.back.disabled = '';
	}
	
	js.$('textarea').innerHTML   = parseStringToWorld(arr[0]);
	js.$('authorName').innerHTML = '<a href='+encodeURI("http://www.google.com/search?hl=ru&q="+arr[1].replace(/\s+/ig,'+')+"")+' target="_blank">'+arr[1]+'</a>';
	
	if((arr[1]==''&&arr[2]=='')|| arr[2] == 'search_null'|| arr[2] == 'error')return;
	
	initTyping(true);
	initWordStatistic();
	
	setTimeout(updateLineStatPos,50);
	
}



/** Преоброзование строки в побуквенные элементы SPAN
	@param str String Строка где переносы отмечены как ^    
 	@return String HTML разметка.
*/
function parseStringToWorld(str){
	
	var str_arr = str.split("^");
	var html    = '';	
		
	if(str_arr[0].length)
		str_arr[0] = ' '+str_arr[0];
	
	for(var i=0,l=str_arr.length; i<l; i++){
		var arr = str_arr[i].split("");
		for(var j=0,jl=arr.length; j<jl; j++){
			if(arr[j] == " ")arr[j] = '&nbsp;';
			html += '<span>'+arr[j]+'</span>';
			countWords++;
		}
		html += '<br/>';
	}
	return html;

}


//---------------------| Обработка событий и статистики. |----------------------- //
// Логика программы.->


var timer = new js.Timer();
var err_timer = new js.Timer();
var errors = 0;
var err_nodes = [];
var _err_ltrs_  = [];
var _err_nds  = [];
var _err_str  = '';
var _err_str_lines = '';
var startTyping    = false;
	
var cursor_color = 'cursor_01';
var typeTyping   = 'standart';
var curr_node;
var curr_letter = '';
var area;
var cword_fld;

var timerFld  = null;
var idTimSerf = 0;

var stoped    = false;

/** 
 * Установка курсора в конец строки(начало следующей) или слова.
 */ 
function ToEndLine(){
	if(typeTyping != 'error-free-line' && typeTyping != 'serfing')return;
	var _temp   = null;
	var tmp     = curr_node;
	var stopEl  = typeTyping == 'serfing'?'&nbsp;':'BR';
	var atopAtr = typeTyping == 'serfing'?'innerHTML':'tagName';
	
	do{
		tmp = tmp.nextSibling;				
	}while(tmp && tmp[atopAtr] != stopEl);
	
	if(typeTyping == 'error-free-line')
	tmp = tmp.nextSibling;
	
	if(tmp == null)return;
	
	curr_node.className = '';
	curr_node = tmp;
	curr_letter = '&nbsp;';
	
	if(typeTyping == 'error-free-line' || tmp.previousSibling.tagName == 'BR'){
		ws_l.Stop();
		ws_l.statistic.pop();
		SetLinesSpeed('&nbsp;');
	}
	
	ws_w.Stop();
	ws_fe.Stop();
	
	
	curr_node.className = cursor_color;
}
/**
 * Позиция скорости строк
 * */
function updateLineStatPos(){
	var ls = document.getElementById('line_state');
	var p  = findPos(document.getElementById('textarea'));
	ls.style.top  = (p[0] + 6)+'px';
	ls.style.left = (p[1] - (ls.firstChild?ls.firstChild.offsetWidth:30))+'px';	
}
/**
 * Обнуление "View" статистики
 * */
function resetStatistics(){
	js.$('errors').innerHTML = '-';
	js.$('line_state').innerHTML = ''; // Список скорости строк.
	js.$('ws_1').innerHTML = 0; // Скорость строки
	js.$('ws_2').innerHTML = 0; // Скорость слова
	js.$('ws_3').innerHTML =''; // Безошибочно
	SetLinesSpeed(-1);
}
/**
 * Инициализация печати
 * */
function initTyping(all_rest){

	errors     = 0;
	timerFld   = js.$('timer');
	area       = js.$('textarea');
	cword_fld  = js.$('words');
	
	//var prof = [true,false];
	var f = document.forms[0];
	
	var oldTypeTyping = typeTyping;	
// Выбор режима печати
	if(document.forms[0].typing[0].disabled)					  
		typeTyping = getSelectedOptions(document.forms[0].sl_correct_type); 		//typeTyping = getCheckedRadio(document.forms[0].correct_type);
	else
		typeTyping = getCheckedRadio(document.forms[0].typing);  

// Если текст не подгруженн.
	if(!area.firstChild)return; 

// Обнуление статистики при изминении режима.
	if(oldTypeTyping != typeTyping || all_rest == true){ 
		resetStatistics();
	}
	
	clearErrors();
	 
	if(typeTyping == 'view'){
		stoped       = true;		
		cursor_color = '';
	}else if(typeTyping == 'profi'){		
		//prof = [false, true];
		//f.show_stat_errors.checked    = prof[0];
		//f.show_stat_free_err.checked  = prof[0];	
		
		//js.$('cont_error').style.visibility = 'hidden';
		//js.$('cont_free_err').style.visibility = 'hidden';
		
	}else{		
		document.forms[0].toEndLine.disabled = (typeTyping == 'error-free-line' || typeTyping == 'serfing')?false:true;		
		var obj = document.forms[0].cursor_color;	
		cursor_color  = obj.options[obj.selectedIndex].value;
		stoped = false;
	}
	if(oldTypeTyping == 'profi' && typeTyping != 'profi'){
		var f = document.forms[0];
		setAttrToFormElements(['show_stat_speed','show_stat_errors','show_stat_letters','show_stat_time','show_stat_line_speed','show_stat_free_err'],'disabled',false);		
		SetStatisticVisible([f['show_stat_speed'],f['show_stat_errors'],f['show_stat_letters'],f['show_stat_time'],f['show_stat_line_speed'],f['show_stat_free_err']]);		
	}
	
		
	//f.show_stat_errors.disabled   = prof[1];
	//f.show_stat_free_err.disabled = prof[1];
	
	curr_node   = area.firstChild;
	curr_letter  = curr_node.innerHTML;
	
	
	curr_node.className = cursor_color;
	
// Если изменили тип печати Стандартный,Виндсерфинг итд.	
	if(timer.status){		
		timer.stop();
		timerFld.innerHTML = '00:00';
	}
	
	setSmile(false);
	startTyping  = false;
	//textIsOver   = false;
	if(typeTyping == 'profi'){
		cursor_color = '';
		curr_node.className = cursor_color;
	}else{
		setCursorColor();
	}
	setErrorsFld();
	js.$('words').innerHTML = (c_position=0)+'/'+countWords;	
	ws_fe.start_from = 0;
	
	document.getElementById('prof_err_words').innerHTML = '';
	
}

/* Функция подсчета статистики "Безошибочно" */
function setFirstError(endtTyping){
	
	if(ws_fe.status == 0)return;
	if(ws_l.status == 0 && !endtTyping){		// вернувшись на отработаную строку и совершив там ошшитбку ничего не происходит. 
		ws_fe.Stop();
		ws_fe.status = 0;
		return;
	}
	var str   = '', 
		lastSpace = 0,
		str_t = '',
		l = ws_l.statistic.length,
		i = 0;//typeTyping == 'error-free-line'?l-1:0;
	
	// Возврощает весь напечатаный тексты
	for(; i<l; i++){
		if(ws_l.statistic[i].word)str += ws_l.statistic[i].word;
	}
	str += ws_l.str;
	str = str.replace(/&nbsp;/g,' ');
	
	
	// Если тип печати "Безошибочный текст" lastSpace = 0(с самого начала текста)
	if(typeTyping != 'error-free'){
		if(typeTyping == 'standart'){
			// Позиция первого ошибочного символа.
			lastSpace = str.length;		
		}else if(typeTyping == 'error-free-line'){ 
			// Позиция первого пробела в строке.
			lastSpace = ws_l.statistic.length > 1?str.length - ws_l.str.replace(/&nbsp;/g,' ').length:0;
		}else{
			// Позиция последнего пробела в строке. режимы которые по принципу Виндсерфинг. 
			lastSpace = str.lastIndexOf(' ');
		}
	}
	
	// Безошибочная подстрока, ws_fe.start_from == последнему символу предудущей подстроки.
	str = str.substr(ws_fe.start_from,str.length);
	
	
	ws_fe.start_from = lastSpace != -1?lastSpace:str.length;
	
	ws_fe.str = ' '+str;
	
	ws_fe.Stop();
	
	//js.$('temp_seconds').innerHTML  = str+' : '+ws_fe.speed;
	js.$('ws_3').innerHTML 			= ' '+str.length+' - '+ws_fe.speed;
	
}
/** Окончание печати всего текста.
 * Выводит курсор в начало текста, но не обнулаяет статистику. 
 * */
function endTyping(keyCode){
	var speed = '-';
	var sec = timer.getSeconds();
	var t   = timer.getDuration();
	var _cWords = countWords;
	var tmp_err_nds = _err_nds;
	var tmp_err_ltrs = _err_ltrs_;
	var tmp_err = errors;
	
	//var tt  = timer.getTimestampDuration();
	

	
	if(typeTyping == 'profi'){
		
		if(keyCode != 13 || errors == 0){
			
// Опредиление количества символов в тексте, так как окончание может сработать по нажати. Enter. countWords, не корректен.			
			_cWords = getEndLettersForNow().length;	
			speed = parseInt(_cWords/(sec/60));
			
			statisticSetMax(typeTyping,speed);	
			statisticPlus(typeTyping,'end');
		}
		
		var f = document.forms[0];
		SetCustomStatisticVisible(['cont_speed','cont_error','cont_letters','cont_time','line_state'], 'visible');
		setAttrToFormElements(['show_stat_speed','show_stat_errors','show_stat_letters','show_stat_time','show_stat_line_speed'],'disabled',false);		
		SetStatisticVisible([f['show_stat_speed'],f['show_stat_errors'],f['show_stat_letters'],f['show_stat_time'],f['show_stat_line_speed']]);
	}else{
		
		if(errors == 0 || typeTyping == 'standart' || typeTyping == 'error-free'){
			speed = parseInt(_cWords/(sec/60));		
			statisticSetMax(typeTyping,speed);			
		}		
		statisticPlus(typeTyping,'end');
	}
	
		
	stoped = true;
	var r 	= errors;
	// Ожидание в 1 секунду перед началом следующей печати
	setTimeout(function(){
		stoped = false;		
	},1000);
	
	initTyping(false);
	setFirstError(true);
	
	if(statistic_mods[typeTyping] && pauseDurationMax < 120000)
	setStatLinesWrote(typeTyping, sec, getCountLine());
		
	pauseDuration = 0;
	pauseDurationMax = 0;
	
	js.$('errors').innerHTML = r;
	js.$('timer').innerHTML = t;		
	
	cword_fld.innerHTML = (c_position=0)+'/'+countWords;
	
	
	if(typeTyping == 'profi'){
		document.getElementById('prof_err_words').innerHTML = tmp_err == 0?'Ошибок не было :).':makeErrorWordsWithoutSort(tmp_err_nds,true,tmp_err_ltrs);//.split(' ').reverse().join(' ');
		
	}

}


// Проверка вводимого символа
function check_word(e){
	if(stoped) return;
	var e    = e || event;
	var code = e.charCode || e.keyCode;
	var serfFunc;
	var nextS;

	var code   = (e.charCode) ? e.charCode : ( (e.keyCode) ? e.keyCode : ( (e.which) ? e.which : 0 ) );
	var letter = String.fromCharCode(code);
	//alert(String.fromCharCode(160));
	//alert(curr_letter.charCodeAt(0))
	//alert(typeof curr_letter)
	//32

	if(code == 32){		
		letter = '&nbsp;';
		stopEvent(e);
	}
	
	if(opera){		
		if(code == 32)letter = ' ';
		if(curr_letter.charCodeAt(0) == 160) curr_letter = ' ';	
	}		
	// Когда Backspace	
	if(code == 8 || (!startTyping && code == 13)){		
		return false;
	}else  if(!(code == 13 && typeTyping == 'profi') && (code < 1040 || code > 1104) && (code < 32 || code > 64)){
		// Если символ не из русской расскалдки.
		return; 
	}
	
	if(curr_node && curr_node.nextSibling)
		nextS = curr_node.nextSibling;
	else 
		return;
	
	
	// Начало печати, Обнуления всй статистики.
	if(!startTyping){ 
		

		if(typeTyping != 'error-free')
			resetStatistics();

		SetLinesSpeed(-1);
		startTyping  = true;
		
		if(statistic_mods[typeTyping]){ // Не отладочные режимы, все данные для отладочных режимов обнуляются.		
			_err_nds  = [];
			_err_ltrs_= [];
			_err_str  = '';
			if(typeTyping != 'letter_all')
			js.$('letter_comb_position').innerHTML = '&nbsp;';
		}
		
		statisticPlus(typeTyping,'all'); // Плюсует попытки		
		setSmile(true);
		
		timer.start(setTimerFld);
		
		
		if(statistic_mods[typeTyping]){
			wrds_by_speed = null;		
			ws_w.Reset();
			ws_l.Reset();
			
		}
		
		if(typeTyping == 'profi'){			
			SetCustomStatisticVisible(['cont_speed','cont_error','cont_letters','cont_time'], 'hidden');
			setAttrToFormElements(['show_stat_speed','show_stat_errors','show_stat_letters','show_stat_time','show_stat_line_speed'],'disabled',true);
		}
		document.getElementById('prof_err_words').innerHTML = '';
	}
	
	/// Опридиление максимального времени паухы между вводом.	
		
	if(pauseDuration == 0){
		pauseDuration = (new Date).getTime();
	}else{
		var tm = (new Date).getTime();
		var now_pd = tm - pauseDuration;
		pauseDurationMax = now_pd > pauseDurationMax?now_pd:pauseDurationMax;
	}
	///
	
// В режиме "Професиональный" при нажатии на Enter остановка печати.	
	if(code == 13 && typeTyping == 'profi'){
		
//		SetCustomStatisticVisible(['cont_speed','cont_error','cont_letters','cont_time','line_state','cont_free_err'], 'visible');
//		setAttrToFormElements(['show_stat_speed','show_stat_errors','show_stat_letters','show_stat_time','show_stat_line_speed','show_stat_free_err'],'disabled',false);
//		
//		var f = document.forms[0];		
//		SetStatisticVisible([f['show_stat_speed'],f['show_stat_errors'],f['show_stat_letters'],f['show_stat_time'],f['show_stat_line_speed'],f['show_stat_free_err']]);
		
		endTyping(code);
		if(err_nodes.length == 0)
//		statisticPlus(typeTyping,'end');
		return; 
	}
	

	// Окончание строки и переход на следующую. 
	while(nextS && nextS.tagName != 'SPAN'){		
		if(typeTyping == 'double'){			// Обработка для двойного режима	
				if(double_flag == 0 && nextS.nextSibling){
					if(!nextS.nextSibling.nextSibling)double_flag = -1;														
					curr_node = backToBegin();					
					double_flag = 1;			
					return;
				}else{
					double_flag = 0;								
					nextS = nextS.nextSibling;
				}				
		}else{						
			nextS = nextS.nextSibling;
		}
		if(statistic_mods[typeTyping])
		if(err_nodes.length == 0 && curr_letter == letter){
			if(ws_l.status == 1){
				ws_l.str += curr_node.innerHTML;
// В режиме "Стандартный" если вернутся на уже пройденную строку, статистика остается страой !				
				if(typeof ws_l.statistic[ws_l.statistic.length-1].speed == 'undefined') 
					ws_l.Stop();
				else{
					ws_l.status = 0;
					ws_l.str = '';
				}
				
				SetLinesSpeed(ws_l.speed);
				ws_l.fld_line.innerHTML = ws_l.speed;
			}
			if(ws_w.status == 1){
				ws_w.str += curr_node.innerHTML;
				ws_w.Stop();
				ws_w.fld_word.innerHTML = ws_w.speed;
			}
		}
	}	
	if(statistic_mods[typeTyping])
	if(ws_l.status == 0 && nextS && (!curr_node.previousSibling || curr_node.previousSibling.tagName == 'BR')){
		ws_l.Start();
	}			
	
	// Введен правельный символ	
	if(curr_letter == letter){
		
		// Курсор красного цвета, если ошибки уже допущены, исключение режим "Професиональный" 		
		if(typeTyping != 'profi')
		curr_node.className = err_nodes.length > 0?'red':'';
		
		 // Окончание печати всего текста
		if(!nextS && err_nodes.length == 0){ 
			// Отладочный режим "Букво сочетание".			
			if(typeTyping == 'letter_comb'){ 
				nextLetterCombLine();				
				js.$('letter_comb_position').innerHTML =  "Отработано строк: "+(letterComb.curr_pos-1)+"/"+letterComb.arr_str.length+".";
			}else if(typeTyping != 'profi'){ 					
				// Все остальные режимы.
				endTyping(e);				
//				statisticPlus(typeTyping,'end');				
			}
			return;
		}
			// В режиме "Профиль" заканчиваем, даже если ест ошибки!			
		/*}else if(!nextS && typeTyping == 'profi'){ 
			endTyping(e);			
//			statisticPlus(typeTyping,'end');
		}*/
	
		// Напечатан последний символ но, остались ошибки
		if(!nextS){
			nextS = curr_node;
			cword_fld.innerHTML = (c_position+1)+'/'+countWords;
		}else{
			cword_fld.innerHTML = (++c_position)+'/'+countWords;
		}
		
		// Подсчет скорости каждого слова
		if(statistic_mods[typeTyping]){
			if(err_nodes.length == 0 && typeTyping != 'profi')			
			if(ws_w.status == 0 && nextS.innerHTML != '&nbsp;' && letter == '&nbsp;'){
				ws_w.Start();
			}else if(ws_w.status == 1 && nextS.innerHTML == '&nbsp;' && err_nodes.length == 0){
				ws_w.str += curr_node.innerHTML;			
				//document.getElementById('temp_seconds').innerHTML = ws_w.str;
				ws_w.Stop();			
				ws_w.fld_word.innerHTML = ws_w.speed;
			
			}
			if(ws_w.status == 1){
				ws_w.str += curr_node.innerHTML;			
			}
			if(nextS && ws_l.status == 1){
				//if(ws_l.statistic.length && !ws_l.statistic[ws_l.statistic.length-1].speed)
				ws_l.str += curr_node.innerHTML;
			}
		}
		//document.getElementById('temp_seconds').innerHTML = ws_w.str;
		nextS.className = cursor_color;		
		if((typeTyping != 'standart' && typeTyping != 'view' && typeTyping != 'profi') && err_nodes.length > 0){ // Запуск таймера между вводом символов, если ошибки уже были допущенны . 
			pressPauseDuration(nextS);
		}else{
			if(ws_fe.status == 0){ // Статистика скорости до первой ошибки, запускается если нету ошибок и слово введенно правельно.
				ws_fe.Start();				
				err_timer.start();
			}
		}
		setSpeedFld();
	}else{	 // Введен ошибочный символ
		
		if(err_nodes.length == 0){ // Выполняет если текст уже с ошибочными символами.
			setFirstError();
			//_err_ltrs_[_err_ltrs_.length] = curr_node; //  Массив ошибочных символов, для формирования списка ошибрчных слов.
			errors ++;
		}
		
		if(statistic_mods[typeTyping] && nextS){
			//if(ws_l.statistic.length && !ws_l.statistic[ws_l.statistic.length-1].speed)
				ws_l.str += letter;		
			
			if(ws_w.status == 1)
				ws_w.str += letter;
		}
		
//		if(!nextS && typeTyping == 'profi'){
//			endTyping(e);
//			//statisticPlus(typeTyping,'end');
//		}
		
		if(statistic_mods[typeTyping] && err_nodes.length == 0){
			_err_nds[_err_nds.length] 	  = curr_node; //  Массив ошибочных символов, для формирования списка ошибрчных слов.
			_err_ltrs_[_err_ltrs_.length] = letter;
		}
		
		setErrorsFld();			
		err_nodes[err_nodes.length]   = [curr_node,curr_node.innerHTML];
		
		if(typeTyping != 'profi'){
			curr_node.className = 'red';	    		
			curr_node.innerHTML = letter==" "?"&nbsp;":letter;
		}
		
		if(nextS){
			cword_fld.innerHTML = (++c_position)+'/'+countWords;
			nextS.className = cursor_color;			
		}else{ 
			nextS = curr_node;
			cword_fld.innerHTML = (c_position+1)+'/'+countWords;
		}
		if(typeTyping != 'standart' && typeTyping != 'view' && typeTyping != 'profi'){ // Все по принципу виндсерфинга кроме  "Свободный" и "Стандартный"
			pressPauseDuration(nextS);
			//js.$('speed').innerHTML = '-';
			//ws_w.fld_text.innerHTML = '-';
		}else{		
			ws_fe.start_from += 1;	
		}
		
	}

	curr_node  = nextS;
	if(curr_node.className != 'red')
		curr_letter = curr_node.innerHTML; 

}

// Удаляет все ошибки    
function clearErrors(){
	if(!curr_node)return;
	if(!err_nodes.length){
		curr_node.className = '';
		return;
	}
	
	var i =0, s = curr_node,firstError = err_nodes[0][0],flag=false;	
	s.className = '';
	if(err_nodes.length){
		i = err_nodes.length-1; 
		do{			
			if(i >= 0 && err_nodes[i][0] == s){				
				s.innerHTML = err_nodes[i][1];				
				i--;
				if(firstError == s)flag = true;
				
			}if(flag && s.innerHTML == '&nbsp;'){
				s.className = '';
				break;
			}
			c_position--;
		s.className = '';	
		}while(s = s.previousSibling);
	}
	cword_fld.innerHTML = (c_position)+'/'+countWords;
	err_nodes = [];
	return s;
}
//Возврат курсора на 1ую позицию строки и удаление ошибочных символов
function backToBegin(){
	var firsNode,err_l = 0;
	
	firsNode = clearErrors();
	
	while(firsNode.previousSibling){
		if(firsNode.previousSibling.tagName == 'BR')break;
		firsNode = firsNode.previousSibling;
		c_position--;
	}
	cword_fld.innerHTML = (c_position+=err_l)+'/'+countWords;
	curr_node.className = '';
	
	curr_node  = firsNode;	
	
	curr_letter = "&nbsp;";
	curr_node.innerHTML = "&nbsp;";
	curr_node.className = cursor_color;
	stoped = false;
	return curr_node;
}

//Воозврат курсора назад на ближайший пробел  и удаление ошибочных символов.
function backToSpace(){
	// TODO: замеченна ошибка исчезнавения слова , нужно проверять ! 
	var _lIndes = ws_w.str.length>0?ws_l.str.lastIndexOf(ws_w.str):ws_l.str.lastIndexOf('&nbsp;');
	if(_lIndes < 1 || typeTyping == 'error-free-line'){
		ws_l.str = '';
		ws_l.Break();		
	}else{
		ws_l.str = ws_l.str.substr(0,_lIndes);
	}
	
	ws_w.Break();	
	//ws_l.Reset();
	
	var firsErrNode     = err_nodes[0]?err_nodes[0][0]:null;
	if(!firsErrNode)return;

	//document.onkeypress = stopEvent;
	stoped = true;

	setTimeout(function(){
		
		firsErrNode     = err_nodes[0][0]; // Первый ошибочный символ
		
		if(typeTyping == 'error-free'){
			var _rn  = _err_nds;
			var _rs = _err_str;
			
			initTyping();
			//clearErrors();			
			_err_nds = _rn;
			_err_str = _rs ;
		
			return;
		}else if(typeTyping == 'error-free-line'){
			firsErrNode = backToBegin();	
			return;
		}
		clearErrors();
		
		
		while(firsErrNode && firsErrNode.innerHTML != '&nbsp;'){ // Начиная с первого ошибочный символ назат к ближайшему пробелу.			
			firsErrNode = firsErrNode.previousSibling;				
		}	  
		// Режим serfing-hard deleted
		/*if(typeTyping == 'serfing-hard' && firsErrNode.previousSibling && firsErrNode.previousSibling.tagName != 'BR'){
			firsErrNode =  firsErrNode.previousSibling;			
			while(firsErrNode && firsErrNode.innerHTML != '&nbsp;'){
				firsErrNode = firsErrNode.previousSibling;				
			}			
		}*/						
					
		
		if(firsErrNode.innerHTML == ' ')firsErrNode.innerHTML = '&nbsp;';
		
		curr_letter            = firsErrNode.innerHTML;
		curr_node             = firsErrNode;
		firsErrNode.className = cursor_color;
		
		stoped = false;
		//document.onkeypress   = check_word;
		
	},waitBackToSpace);
	
	return firsErrNode;
}
/* Отработка клавиши Backspace возврат курсора и удаление ошибочных символов*/
function backSpace(e){
	// Во всех режимах кроме ничеперечисленых, бэкспэйс отключен.
	if(typeTyping != 'standart' && typeTyping != 'text' && typeTyping != 'word')return;
	
	var prevS, 
		currN     = null,
		temp_node = curr_node,
		cw = 1,
		prev_line_flag = false;
	
	if(temp_node.nextSibling.tagName == 'BR'){
		temp_node = temp_node.nextSibling;		
		while(temp_node && temp_node.tagName != 'SPAN'){
			temp_node = temp_node.nextSibling;
			if(!temp_node){
				currN = curr_node;				
			}
		}
	}
	
	if(!(prevS = curr_node.previousSibling)){
		if(ws_l.statistic.length)ws_l.statistic.pop();
		return;
	}
	
	if(prevS.innerHTML == '&nbsp;' && err_nodes.length == 0)
		ws_w.Break();
	
	while(prevS && prevS.tagName != 'SPAN'){
		prevS = prevS.previousSibling;
		prev_line_flag = true;		
	}
	
	prevS.className     = cursor_color;
	curr_node.className = '';	
	curr_node 			= prevS;
	curr_letter  		= prevS.innerHTML;
	

	
	cword_fld.innerHTML = (--c_position)+'/'+countWords;
	
	var i = err_nodes.length;
	
	
	
	if(statistic_mods[typeTyping]){
		if(curr_letter == '&nbsp;'){
			ws_l.str = ws_l.str.substr(0,ws_l.str.length - 6);
			if(ws_w.status && ws_w.str.length)
				ws_w.str = ws_w.str.substr(0,ws_w.str.length - 6);		
		}else{		
			ws_l.str = ws_l.str.substr(0,ws_l.str.length - cw);
			if(ws_w.status && ws_w.str.length)
				ws_w.str = ws_w.str.substr(0,ws_w.str.length - 1);		
		}
		if(prev_line_flag)
			ws_l.statistic.pop();
	}
	
	//if(ws_fe.status)ws_fe.Start();		
	if(typeTyping == 'standart')
		ws_fe.start_from -= cw;	
	
		
	while(i--){
		if(curr_node == err_nodes[i][0]){
			curr_node.innerHTML = err_nodes[i][1];
			curr_letter  = err_nodes[i][1];
			err_nodes.splice(i,1);
		}else if(currN == err_nodes[i][0]){ // Если символ в блоке последний.
			currN.innerHTML = err_nodes[i][1];
			err_nodes.splice(i,1);
		}
	}
	//document.getElementById('temp_seconds').innerHTML = ws_w.str;
	
}

function pressPauseDuration(nextS){
	var timerSerfer = 0;	
	var t = function(){
		timerSerfer += 200;	
		if(timerSerfer < waitPressKey) {
			idTimSerf = setTimeout(t,200);
		}else{
			backToSpace(nextS);
		}
		
	};
	if(idTimSerf)clearTimeout(idTimSerf);	
	t();
}

function stopEvent(e){
	e = e || event;	
	if (dom) {
		e.preventDefault();
		e.cancelBubble = true;
	} else if (ie) {
		e.returnValue = false;
		//e.stopPropagation();
	}
	return false;    
}
function stopEventAndBack(e){
	if(stoped)return;
	e = e || event;	
	if(e.keyCode == 8){
		stopEvent(e);
		if(!stoped)
		backSpace(e);
		return false;
	}
}

function nextLetterCombLine(){
	var s = letterComb.NextLine();
	if(!s){
		s = letterComb.FirstLine();
		letterComb.curr_pos = 1;
		startTyping = false;
		
		initTyping();
	}
	var str     = parseStringToWorld(s);
	area.innerHTML = str;
	curr_node   = area.firstChild;
	curr_letter  = curr_node.innerHTML;
	curr_node.className = cursor_color;	
	return true;
}

//---------------------| Вспомогательные функции |----------------------- //

function getStringFromHTML(str){	
	str = str.replace(/<br[^>]*>/ig,'^');	
	str = str.replace(/<span[^>]*>([^<]*)<\/span[^>]*>/ig,'$1');	
	str = str.replace(/&nbsp;/ig,' ');
	return str.substr(0,str.length-1);
	
}

function getCheckedRadio(rb){	
	var i 	= rb.length;
	while(i--){
		if(rb[i].checked) 
			return rb[i].value;
	}
	return false;
}

function setAttrToFormElements(elmsID, attr, value){
	
	var i 	= elmsID.length;
	var el  = null;
	while(i--){
		if((el = document.forms[0][elmsID[i]])){ 
			el[attr] = value;
		}
	}
}

function setAttrToRadio(rb, attr, value, targets){	
	var i = rb.length;
	var t = {},flag = false;
	if(targets){
		flag = true;
		var j = targets.split(','),ii = j.length;
		while(ii--){t[j[ii]] = true;}		
	}
	while(i--){
		if(flag){
			if(t[rb[i].value])rb[i][attr] = value;
		}else{
			rb[i][attr] = value;
		}
		
	}
	
}
function getSelectedOptions(sl){	
	return sl.selectedIndex == -1?false:sl.options[sl.selectedIndex].value;
}

function setAttrToOptions(sl, attr, val, target){	
	var i = sl.length,
		flag = false;
	if(target){
		flag = true;
		target = ','+target+',';
	}
	
	while(i--){
		if(flag){				
			if(target.indexOf(','+sl.options[i].value+',')!= -1){
				sl.options[i][attr] = val;
			}else if(attr === 'selected'){
				sl.options[i].selected = false;
			}
		}else{
			sl.options[i][attr] = val;
		}		
	}
	
	
	
}
function RemoveDividerFromString(str){	
	return str.replace(/\^/g, '');
}
function AddDividerToString(str){	
	var s = '',len=0,arr = [], _str = '';
	str = trim(str);
	
	arr = str.split(' ');
		
	for(var i=0,l = arr.length; i<l; i++){
		s = ' '+arr[i];
		len += s.length;
		if(len > 46){
			len = s.length;					
			_str += '^';
		}
		_str += s;
	}
	return _str;
}

function trim(str){
	var	str = str.replace(/^\s\s*/, ''),
	ws  = /\s/,
	i   = str.length;
	while (ws.test(str.charAt(--i)));
	return str.slice(0, i + 1);
}

function RemoveDuplicates(arr){	
	if(typeof(arr) ==  'string')arr = arr.split(' ');	
	var arr_tmp = [];	
	for(var i=0,l=arr.length ; i<l; i++){
		if(arr_tmp.indexOf(arr[i]) == -1)
			arr_tmp[arr_tmp.length] = arr[i];
	}
	return arr_tmp;
}

function StrSortByLength(arr,ASC_DESC){
	if(typeof(arr) ==  'string')arr = arr.split(' ');
	var cmp = function(a,b) { 
		if (a.length<b.length)  return -1;
		if (a.length>b.length)  return 1;
		if (a.length==b.length) return 0;	
	};
	return ASC_DESC=='DESC'?arr.sort(cmp).reverse():arr.sort(cmp);	
}

function LinesSortByLength(lines,ASC_DESC){
	var arr = lines.split('^');
	var len = arr.length;
	var str = ' ';
	for(var i=0;i<len;i++){
		str += trim(StrSortByLength(arr[i],'DESC').join(' '));
		str += '^ ';	
	}
	return str.substr(0,str.length-1);	
	
}

function forceClick(obj){
	
	if(document.createEventObject){
        var evt = document.createEventObject();
        obj.fireEvent("onclick", evt);
    }else if(document.createEvent) {    	
        var evt = document.createEvent("MouseEvents");
        evt.initMouseEvent('click', true, true, window,
        	    0, 0, 0, 0, 0, false, false, false, false, 0, null);
        obj.dispatchEvent(evt);
    } else {
        return false;
    }
}

function getEndLettersForNow(){
	var str ='';
	for(var i=0,l = ws_l.statistic.length; i<l; i++){
		if(ws_l.statistic[i].word)str += ws_l.statistic[i].word;
	}
	str += ws_l.str;
	return str.replace(/&nbsp;/g,' ');
		
}
// ---------------------| Статистика режимов |----------------------- //

function initWordStatistic(){
	
// Если установлен " " значит данная статистика не отоброжается.	
	var modes = {'standart'       :[0,0,0,0],
				 'serfing'        :[' ',0,0,' '],
				 'error-free-line':[' ',0,0,' '],
				 'error-free'     :[0,0,0,0],
				 'profi'          :[0,0,0,0]};
	var i = '';
	var el = null;
	for(i in modes){		
		stat_speed[i] = {
			el:{max:document.getElementById(i+'_maxspeed'),
				end:document.getElementById(i+'_end_try'),
				all:document.getElementById(i+'_all_try'),
				lastspeed:document.getElementById(i+'_lastspeed')
				},
			max:modes[i][0],
			end:modes[i][1],
			all:modes[i][2],
			lastspeed:modes[i][3]
			
		};
		el = stat_speed[i].el;
		el.max.innerHTML = stat_speed[i].max;
		el.end.innerHTML = stat_speed[i].end;
		el.all.innerHTML = stat_speed[i].all;
		el.lastspeed.innerHTML = stat_speed[i].lastspeed;
		
		el.max.style.visibility = 'hidden';
		el.end.style.visibility = 'hidden';
		el.all.style.visibility = 'hidden';
		el.lastspeed.style.visibility = 'hidden';
	}	
}

function statisticSetVisible(el){	
	if(el.all.style.visibility == 'hidden'){
		el.all.style.visibility = 'visible';
		el.max.style.visibility = 'visible';
		el.end.style.visibility = 'visible';
		el.lastspeed.style.visibility = 'visible';
	}
}

function statisticPlus(mode,type){	
	
	if(!stat_speed[mode]) return;
	statisticSetVisible(stat_speed[mode].el);	
	if(typeof stat_speed[mode][type] != 'number')stat_speed[mode][type] = 0;
	stat_speed[mode][type] += 1;
	stat_speed[mode].el[type].innerHTML = stat_speed[mode][type];
	
}	

function statisticSet(mode,type,val){	
	stat_speed[mode][type] = val;
	stat_speed[mode].el[type].innerHTML = stat_speed[mode][type];
}	
function statisticSetMax(mode, val){
	
	if(!stat_speed[mode])return;	
	
	val = parseInt(val);
	if(stat_speed[mode].max !== ' '){
		if(stat_speed[mode].max < val)
		stat_speed[mode].max = val;	
		stat_speed[mode].el.max.innerHTML = stat_speed[mode].max;
	}
	if(stat_speed[mode].lastspeed !== ' '){
		stat_speed[mode].lastspeed = val;	
		stat_speed[mode].el.lastspeed.innerHTML = val;
	}
	
}
//---------------------> //



//---------------------| Загрузка собственного текста |----------------------- //

function UploadSelfText(file){
	var fName = file.value;
	if(!/^.+\.txt$/.test(fName)){
		alert('Недопустимое расширение  файла: '+fName);
		return;
	}	
	js.ajax.uploadFile(file.form, 'uploadselftext.php?count_line='+getCountLine(),'fileUploaded');
}
function fileUploaded(data){

	if(data.response != 'error'){
		loadedText(data);
	}else{
		alert(data.responseText);
	}
}

//---------------------| Поиск текста |----------------------- //

function searchInDb(text){
	makeRquest('type=search&text='+text);
}

//---------------------| Отправка данных на сервер.  Статистика режимов (время и количество напечатаных строк) |----------------------- //
function setStatLinesWrote(mode, sec, lines){
	var ajax  = js.ajax;	
	ajax.send('statistic.php', 'type=linesWrote&sec='+parseInt(sec)+'&lines='+lines+'&mode='+mode,function(){},null,true);	
}

//---------------------| Завершение работы |----------------------- //
function unloadPage(){
	
}

function loadPage(pt){
	if(!pt)pt = 1;
	var ajax  = js.ajax;	
	ajax.send('statistic.php', 'type=loadPage&pt='+pt,function(){},null,true);		
}



//---------------------| Инициализация |----------------------- //

function initScripts(){
	clearAllEvents();
	if (dom) {
		window.addEventListener("keypress", check_word, false);
		window.addEventListener("keydown", stopEventAndBack, false);		
	} else if (ie) {	
		document.attachEvent("onkeydown", stopEventAndBack);		
		document.attachEvent("onkeypress", check_word);
	}
	
	///
	var scripts = document.getElementsByTagName("script");
	var rg;
	for(var i=0,l = scripts.length; i<l; i++){
		
		if((rg = scripts[i].src.match('/freetyping_script\.js+\\?(.*)'))){
			if(rg[1] == 'mode=safe')
				php_file  = 'freetyping_2.php';
		}
	}	
	
	startLesson('random');	
	
	ws_w  = new Statistic_wl('word'); // Статистика слов
	ws_l  = new Statistic_wl('line'); // Статистика строк
	ws_fe = new Statistic_wl('err'); // Статистика скорости до первой ошибки.
	ws_fe.start_from = 0;
	
	
	//ws_l.fld_text = ws_w.fld_text = document.getElementById('ws_0');
	ws_l.fld_line = ws_w.fld_line = document.getElementById('ws_1');
	ws_l.fld_word = ws_w.fld_word = document.getElementById('ws_2');
	
	
	///

	//loadPage();
};

function initViewer(name,clbk){
	var ajax  = js.ajax;	
	var div = document.createElement('DIV');
	div.className = 'content';

	var body = document.getElementsByTagName('BODY')[0];
	body.innerHTML = '<br><br><center><b>Загрузка данных...<b><center>';
	
	ajax.send('view/'+name+'.html','',function(data){		
		div.innerHTML = data.responseText; 
		body.innerHTML = '';
		body.appendChild(div);
		
		if(clbk)clbk();
	},null,true);
}
function clearAllEvents(){
	if (dom) {
		window.removeEventListener("keypress", check_word, false);
		window.removeEventListener("keydown", stopEventAndBack, false);		
	} else if (ie) {	
		document.detachEvent("onkeydown", stopEventAndBack);		
		document.detachEvent("onkeypress", check_word);
	}	
}
