//
// 2006-04-20
// Copyright (c) Art. Lebedev Studio | http://www.artlebedev.ru/
// Author - Leechy | leechy@design.ru
//

var sFAYTHLElemName = 'b';
var sFAYTHLElemClass = null;
var iFAYTMinTextLength = 2;
var bFAYTWordStartOnly = true;
var bFAYTTranslit = false;
var bFAYTAddClass = false;
var sFAYTFoundClassName = 'found';
var sFAYTFilteredClassName = 'filtered';

var rSpaces = new RegExp( '(\\s|' +  String.fromCharCode( 160 ) + '|&nbsp;)+', 'g' );


function defaultOption(oOptions, vOptionValue, vDefault) {
	if (oOptions && oOptions[vOptionValue] != null) return oOptions[vOptionValue];
	else return vDefault;
}

function FAYT(oElem, oOptions) {
	this.oElem = oElem;
	this.sHLElemName = defaultOption(oOptions, 'sHLElemName', sFAYTHLElemName);
	this.sHLElemClass = defaultOption(oOptions, 'sHLElemClass', sFAYTHLElemClass);
	this.iMinTextLength = defaultOption(oOptions, 'iMinTextLength', iFAYTMinTextLength);
	this.bWordStartOnly = defaultOption(oOptions, 'bWordStartOnly', bFAYTWordStartOnly);
	this.bTranslit = defaultOption(oOptions, 'bTranslit', bFAYTTranslit);

	this.bAddClass = defaultOption(oOptions, 'bAddClass', bFAYTAddClass);
	this.sFoundClassName = defaultOption(oOptions, 'sFoundClassName', sFAYTFoundClassName);
	this.sFilteredClassName = defaultOption(oOptions, 'sFilteredClassName', sFAYTFilteredClassName);
	this.sParentClasses = defaultOption(oOptions, 'sParentClasses', null);

	this.aOccurrences = new Array();
	this.iLastSearchTime = 0;
	this.sLastText = '';

	this.clearing = false;
	this.TO = 0;

	return this;
}

FAYT.prototype.find = function(sText) {
	if (this.TO) clearTimeout(this.TO);
	var oThis = this;
	this.TO = setTimeout(function() { oThis.findIt(sText) }, 300);
}

FAYT.prototype.findIt = function(sInputText) {
	if (this.clearing) {
		this.find(sInputText);
	} else if (sInputText != this.sLastText) {
//		var dStart = new Date();
		this.clearSelection();
		if (sInputText.length >= this.iMinTextLength) {
			var sText = sInputText.toLowerCase();
			// array with all the strings we are searching for
			var aText = this.createAdditionalTextsArray(sText, this.iMinTextLength);
			// regexp for speeding the search
			var reText = '';
			for (var i = 0; i < aText.length; i++) { if (i > 0) reText += '|'; reText += aText[i][0] }
			this.reText = new RegExp('(' + reText + ')', 'g');
			// searching
			this.selectText(sText, aText, this.oElem, 0);
			this.aOccurrences.sort(function(a, b){ return a[1] - b[1] });
		}
		this.sLastText = sInputText;
		
		/* если нужно классом помечать родительские элементы,
		   то это делается уже после окончательного поиска */
		if (this.bAddClass) {
			addClassToParents(this.aOccurrences, this.sFoundClassName, this.sParentClasses, this.oElem);
			if (this.aOccurrences.length) addClass(this.oElem, this.sFilteredClassName);
			else removeClass(this.oElem, this.sFilteredClassName);
		}
//		var dEnd = new Date();
//		this.iLastSearchTime = dEnd.getTime() - dStart.getTime();	
//		dalert('чистка с поиском заняли ' + this.iLastSearchTime + 'ms');
		if (window.FAYTResults) FAYTResults(this);
	}
}



FAYT.prototype.selectText = function(sText, aText, oParent, iParentNo) {
	var oNode = (oParent)? oParent.firstChild : this.oElem.firstChild;
	var iNextParentNo = iParentNo + 1;
	while (oNode) {
		switch (oNode.nodeType) {
			case 1:
				// проверяем а есть ли вообще такой текст внутри этой нодой и если есть - ищем дальше
				// ускоряет при сложных HTML-конструкциях и поиске уникального текста
				if ( oNode.innerHTML.replace( /<\/?\w[^>]*>/g, ' ' ).toLowerCase().match(this.reText) )
					iNextParentNo = this.selectText(sText, aText, oNode, iNextParentNo);
				break;
			case 3:
				if (oNode.nodeValue.length > 0) {
					var aNodeOccurrences = getNodeOccurrences(oNode.nodeValue, sText, aText);
					for (var i = 0; i < aNodeOccurrences.length; i++) {
						var oSelectionText = oNode.splitText(aNodeOccurrences[i][0]);
						var oLeftText = oSelectionText.splitText(aNodeOccurrences[i][1]);
						var oSelectionElem = document.createElement(this.sHLElemName);
						if (this.sHLElemClass) oSelectionElem.className = this.sHLElemClass;
						oNode.parentNode.insertBefore(oSelectionElem, oNode.nextSibling);
						oSelectionElem.appendChild(oSelectionText);
						this.aOccurrences[this.aOccurrences.length] = [oSelectionElem, iParentNo];
						oNode = oLeftText;
					}
				}
				break;
		}
		oNode = oNode.nextSibling;
	}
	return iNextParentNo;
}

function getNodeOccurrences(sNodeValue, sText, aText) {
	var aNodeOccurrences = new Array();
	var sNodeValue = sNodeValue.toLowerCase();

	for (var i = 0; i < aText.length; i++) {
		var iIteration = 0;
		while (sNodeValue.indexOf(aText[i][0]) >= 0) {
			var iTextOffset = sNodeValue.indexOf(aText[i][0]);
			aNodeOccurrences[aNodeOccurrences.length] = [iTextOffset + aText[i][1], aText[i][0].length];
			sNodeValue = sNodeValue.substr(iTextOffset + aText[i][0].length);
			iIteration++;
		}
	}

	return aNodeOccurrences;
}

FAYT.prototype.clearSelection = function() {
	this.clearing = true;
	if (this.bAddClass) {
		removeClassFromParents(this.aOccurrences, this.sFoundClassName, this.sParentClasses, this.oElem);
	}
	for (var i = this.aOccurrences.length - 1; i >= 0 ; i--) {
		if (this.aOccurrences[i][0]) {
			var oOccurrence = this.aOccurrences[i][0];
			if (oOccurrence && oOccurrence.firstChild) {
				var oParent = oOccurrence.parentNode;
				oParent.insertBefore(oOccurrence.firstChild, oOccurrence);
				oParent.removeChild(oOccurrence);
				if (i == 0 || this.aOccurrences[i][1] != this.aOccurrences[i-1][1]) {
					if (document.all && !window.opera) oParent.innerHTML = oParent.innerHTML;
					else oParent.normalize();
				}
			}
		}
	}
	this.aOccurrences.length = 0;
	this.clearing = false;
}

FAYT.prototype.createAdditionalTextsArray = function(sText, iMinTextLength) {
	var aText = new Array();
	var aSplit = sText.replace(/(\s|,(\s)?)/g, '±').split('±');
	var iWordStart = (this.bWordStartOnly)? 1 : 0;
	for (var i = 0; i < aSplit.length; i++) if (aSplit[i].length >= iMinTextLength) aText[aText.length] = [aSplit[i], 0, iWordStart];
	if (this.bTranslit && window.translitToLat) {
		var sLat = translitToLat(sText);
		var sCyr = translitToCyr(sText);
		if (sText != sLat) aText[aText.length] = [sLat, 0, iWordStart];
		if (sText != sCyr) aText[aText.length] = [sCyr, 0, iWordStart];
	}
	if (this.bWordStartOnly) {
		aText[aText.length] = ['"' + sText, 1, 1];
		aText[aText.length] = [' ' + sText, 1, 1];
		aText[aText.length] = ['\t' + sText, 1, 1];
	}
	return aText;
}



// common functions


function switchClass( objNode, strCurrClass, strNewClass ) {
	if ( matchClass( objNode, strNewClass ) ) replaceClass( objNode, strCurrClass, strNewClass );
		else replaceClass( objNode, strNewClass, strCurrClass );
}

function addRemoveClass(oNode, sClass, bAction) {
	if (bAction && !matchClass(oNode, sClass)) replaceClass(oNode, sClass, '');
	else if (!bAction && matchClass(oNode, sClass)) replaceClass(oNode, '', sClass);
}


function addClassToParents(aNodes, sClassName, sParentClasses, eParent) {
	for (var i = 0; i < aNodes.length; i++) {
		var eThisParent = aNodes[i][0].parentNode;
		while (eThisParent && eThisParent != eParent) {
			if (matchClass(eThisParent, 'job-offer') ) {
				addClass(eThisParent, 'found');
			}
			eThisParent = eThisParent.parentNode;
		}
	}
}


function removeClassFromParents(aNodes, sClassName, sParentClasses, eParent) {
	for (var i = 0; i < aNodes.length; i++) {
		var eThisParent = aNodes[i][0].parentNode;
		while (eThisParent && eThisParent != eParent) {
			if (matchClass(eThisParent, 'job-offer') ) {
				removeClass(eThisParent, 'found');
			}
			eThisParent = eThisParent.parentNode;
		}
	}
}

function getTextValue( objNode ) {
	var strValue = new String();
	if ( objNode.childNodes.length ) {
		for ( var i = 0; i < objNode.childNodes.length; i++ ) {
			if ( objNode.childNodes[i].nodeType == 1 ) strValue += getTextValue( objNode.childNodes[i] );
			if ( objNode.childNodes[i].nodeType == 3 ) strValue += objNode.childNodes[i].nodeValue;
		}
	}
	return strValue;
}

function getAncestorByClassName( oCurrentElement, sClassName, sTagName ) {
	var eCurrent = oCurrentElement.parentNode;
	while ( eCurrent.parentNode ) {
		if ( matchClass( eCurrent, sClassName ) && ( !sTagName || eCurrent.tagName.toLowerCase() == sTagName.toLowerCase() ) ) return eCurrent;
		eCurrent = eCurrent.parentNode;
	}
}

function getAncestorByTagName( oCurrentElement, sTagName ) {
	var eCurrent = oCurrentElement.parentNode;
	while ( eCurrent.parentNode ) {
		if ( eCurrent.tagName.toLowerCase() == sTagName.toLowerCase() ) return eCurrent;
		eCurrent = eCurrent.parentNode;
	}
}

function getNextSiblingByTagName( eCurrentElement, sTagName ) {
	var eCurrent = eCurrentElement.nextSibling;
	while ( eCurrent ) {
		if ( eCurrent.nodeType == 1 && eCurrent.tagName.toLowerCase() == sTagName.toLowerCase() ) return eCurrent;
		eCurrent = eCurrent.nextSibling;
	}
	return null;
}

function getPrevSiblingByTagName( eCurrentElement, sTagName ) {
	var eCurrent = eCurrentElement.previousSibling;
	while ( eCurrent ) {
		if ( eCurrent.nodeType == 1 && eCurrent.tagName.toLowerCase() == sTagName.toLowerCase() ) return eCurrent;
		eCurrent = eCurrent.previousSibling;
	}
	return null;
}

function getNextSiblingByClassName( eCurrentElement, sClassName, sTagName ) {
	var eCurrent = eCurrentElement.nextSibling;
	while ( eCurrent ) {
		if (
			eCurrent.nodeType == 1
			&& matchClass( eCurrent, sClassName )
			&& (
				!sTagName
				|| eCurrent.tagName.toLowerCase() == sTagName.toLowerCase()
			)
		) return eCurrent;
		eCurrent = eCurrent.nextSibling;
	}
	return null;
}

function getPrevSiblingByClassName( eCurrentElement, sClassName, sTagName ) {
	var eCurrent = eCurrentElement.previousSibling;
	while ( eCurrent ) {
		if (
			eCurrent.nodeType == 1
			&& matchClass( eCurrent, sClassName )
			&& (
				!sTagName
				|| eCurrent.tagName.toLowerCase() == sTagName.toLowerCase()
			)
		) return eCurrent;
		eCurrent = eCurrent.previousSibling;
	}
	return null;
}


