var allowSpy = 0;
var spy2_debug = 0;
var spy2_remember = 1;
var spy2_periodical = 0;
var spyData = '';		// spy data container
var interval;			// timer
var updateRate = 10;	// timer interval, sec
	updateRate *= 1000;	// sec -> msec
var ajax = false;		// ajax object
var dataSize = 100;	// min size of ajax sending data, bytes
var firstTime = 1;

window.onload = init;

// init engine
function init()
{	
	if (!allowSpy) return ;

	ajax = createAjax();
	if (ajax) {
		setSpyId();		// spy identifier
		spy2_lock();
		var body = document.documentElement ? 
			document.documentElement : document.body;
		// create array of elements
		__parseDoc(body);
		spy2_showElements();
		addEvent(body,'mousemove',spy2_evt_dispatcher);
		addEvent(body,'click',spy2_evt_dispatcher);
		addEvent(window,'resize',spy2_evt_dispatcher);
		addEvent(window,'scroll',spy2_evt_dispatcher);
		addEvent(window,'unload',spy2_evt_dispatcher);
		addEvent(body, 'keypress', spy2_evt_dispatcher);
		spyData  = spy2_timestamp() + spy2_recDelim;
		spyData += spy2_elements2 + spy2_recDelim;
		spyData += '0' + spy2_fldDelim + SPY2_W_LOAD + spy2_fldDelim;
		spy2_snap();
		spy2_unlock();

		// set periodical execution
		if (spy2_periodical)
			interval = setInterval(periodical, updateRate);
	}
}

//-----------------------------------------------------------
// spy service
//-----------------------------------------------------------

//events type
var SPY2_W_LOAD		= 'l';	// window.load
var SPY2_W_RESIZE	= 'r';	// window.resize
var SPY2_W_SCROLL	= 's';	// window.scroll
var SPY2_M_MOVE		= 'm';	// mousemove
var SPY2_M_CLICK	= 'c';	// mouseclick
var SPY2_D_CLICK	= 'd';	// doubleclick
var SPY2_K_PRESS	= 'k';	// keypress

var spy2_elements = new Array();	// elements for fast access
var spy2_elements2 = '';			// elements for export

// delimiters
var spy2_delim = ',';		// in field
var spy2_fldDelim = ';';	// field
var spy2_recDelim = '|';	// records

var spy2_mov_delta=3; // mouse move accuracy

var spy2_oldX=spy2_oldY=0;

var spy2_timestamp;
var spy2_firstTime;

var sc_timer = rsz_timer = 0;

var spy2_lock_content=0;
function spy2_lock(){spy2_lock_content=1}
function spy2_unlock(){spy2_lock_content=0}


function spy2_evt_dispatcher(e)
{
	if (!e) var e = window.event;
	var target = e.target ? e.target : e.srcElement;
	var time = Number(new Date()) - Number(spy2_firstTime) + spy2_fldDelim;
	switch (e.type)
	{
	case 'load':
/*		spy2_lock();
		var body = document.documentElement ? 
			document.documentElement : document.body;
		// create array of elements
		__parseDoc(body);
		spy2_showElements();
		addEvent(body,'mousemove',spy2_evt_dispatcher);
		addEvent(body,'click',spy2_evt_dispatcher);
		addEvent(window,'resize',spy2_evt_dispatcher);
		addEvent(window,'scroll',spy2_evt_dispatcher);
		addEvent(window,'unload',spy2_evt_dispatcher);
		addEvent(body, 'keypress', spy2_evt_dispatcher);
		spy2_content  = spy2_timestamp() + spy2_recDelim;
		spy2_content += spy2_elements2 + spy2_recDelim;
		spy2_content += '0' + spy2_fldDelim + SPY2_W_LOAD + spy2_fldDelim;
		spy2_snap();
		spy2_unlock();
*/
		break;
	case 'resize':
/*		if (!spy2_lock_content) {
			spy2_lock();
			lastResize(function()
				{
				spyData += time + SPY2_W_RESIZE + spy2_fldDelim;
				spy2_snap();
				spy2_unlock();
				}
				, 250);
		}
*/
		if (rsz_timer)  
			clearTimeout(rsz_timer);
		spy2_lock();			
		rsz_timer = setTimeout("var time = Number(new Date()) - Number(spy2_firstTime) + spy2_fldDelim; spyData += time + SPY2_W_RESIZE + spy2_fldDelim;	spy2_snap(); spy2_unlock(); rsz_timer = 0; ", 100);
		break;
	case 'scroll':
/*		if (!spy2_lock_content) {
			spy2_lock();
			lastScroll(function()
				{
				spyData += time + SPY2_W_SCROLL + spy2_fldDelim;
				//spy2_snap();
				spyData += __frameSLT() + spy2_recDelim;
				spy2_unlock();
				}
				, 250);
		}
*/
			if (sc_timer)  
				clearTimeout(sc_timer);
			spy2_lock();			
			sc_timer = setTimeout("var time = Number(new Date()) - Number(spy2_firstTime) + spy2_fldDelim; spyData += time + SPY2_W_SCROLL + spy2_fldDelim;	spyData += __frameSLT() + spy2_recDelim; spy2_unlock(); sc_timer = 0; ", 100);
		
		break;
	case 'mousemove':
		if (!spy2_lock_content) {
			spy2_lock();
			if (Math.abs(spy2_oldX-e.clientX)>spy2_mov_delta || 
			Math.abs(spy2_oldY-e.clientY)>spy2_mov_delta) {
				spyData += time + SPY2_M_MOVE + spy2_fldDelim;
				spyData += e.clientX + spy2_delim + e.clientY;
				spyData += spy2_recDelim;
				spy2_oldX=e.clientX;
				spy2_oldY=e.clientY;
			}
			spy2_unlock();
		}
		break;
	case 'click':
		if (!spy2_lock_content) {
			spy2_lock();
			spyData += time + SPY2_M_CLICK + spy2_fldDelim;
			spyData += e.clientX + spy2_delim + e.clientY;
			spyData += spy2_recDelim;
			spy2_unlock();
		}
		break;
	case 'keypress':
		if (!spy2_lock_content) {
			spy2_lock();
			spyData += time + SPY2_K_PRESS + spy2_fldDelim;
			spyData += String.fromCharCode(e.keyCode);
			spyData += spy2_recDelim;
			spy2_unlock();
		}
		break;
	case 'unload':
		spy2_lock();
		spy2_elements = 0;
		echo(spyData);
		aj_send();
		break;
	}
}


// show spy elements
function spy2_showElements()
{
	if (spy2_debug) {
		for (var i=0; i < spy2_elements.length; i++) {
 			spy2_elements[i].style.border = "1px dotted red";
		}
	}
}


//snap window, "spy2_content" - global var
function spy2_snap()
{
	var res = spy2_getFrame() + spy2_fldDelim;
	for(var i = 0; i < spy2_elements.length; i++)
	{
		res += spy2_boxElement(spy2_elements[i]) + spy2_fldDelim;
	}
	spyData += res + spy2_recDelim;
}

//window width and height
function spy2_getFrame()
{
	return __frameSLT() + spy2_delim + __frameWH();
}

//box dimensions
function spy2_boxElement(n)
{	
	var res = __getElX(n) + spy2_delim;
	res += __getElY(n) + spy2_delim;
	res += n.offsetWidth + spy2_delim;
	res += n.offsetHeight;
	return res;
}

//time stamp HHMMSSMSS
function spy2_timestamp()
{
var dt = new Date();
spy2_firstTime = Number(dt);
var base = dt.getFullYear();
base += _addLeadingZero(String(dt.getMonth() + 1));
base += _addLeadingZero(String(dt.getDate()));
base += _addLeadingZero(String(dt.getHours()));
base += _addLeadingZero(String(dt.getMinutes()));
base += _addLeadingZero(String(dt.getSeconds()));
var ms = String(dt.getMilliseconds());
if (ms.length<2) {ms = '0' + ms;}
if (ms.length<3) {ms = '0' + ms;}
return base+ms;
}

function _addLeadingZero(input) {
	if (input.length < 2) {input = '0' + input;}
	return input;
}
//SERVICES

//window width and height
function __frameWH()
{
	var x,y;
	// Explorer 6 Strict Mode
	if (document.documentElement && document.documentElement.clientHeight) {
		x = document.documentElement.clientWidth;
		y = document.documentElement.clientHeight;
	}
	else 
	if (document.body) { // other Explorers
		x = document.body.clientWidth;
		y = document.body.clientHeight;
	}
	return x + spy2_delim + y;
}

//element left & top
function __getElX(el)
{
var xx=el.offsetLeft;
while (el.offsetParent)
{
	el = el.offsetParent;
	xx += el.offsetLeft
}
return xx;
}

function __getElY(el)
{
var yy=el.offsetTop;
while (el.offsetParent)
{
	el = el.offsetParent;
	yy += el.offsetTop
}
return yy;
}

//window scroll top
function __frameSLT()
{
	var x,y;
	// Explorer 6 Strict
	if (document.documentElement && document.documentElement.scrollTop) {
		x = document.documentElement.scrollLeft;
		y = document.documentElement.scrollTop;
	}
	else 
	if (document.body) { // all other Explorers
		x = document.body.scrollLeft;
		y = document.body.scrollTop;
	}
	return x + spy2_delim + y;
}

// elInfo
function elInfoTxt(n)
{
	var el = n.tagName;
	if (n.spy2.length > 1) {
		el += spy2_delim + n.spy2;
		return el;
	}
	switch (n.tagName) {
		case 'A':
			el += spy2_delim + (n.firstChild ? n.firstChild.nodeValue : '[blank]');
			break;
		case 'INPUT':
			if (n.type == 'button') {
				el += spy2_delim + n.value;
			}
			break;
	}
	return el;
}
//find elements
function __parseDoc(n)
{
	var i;
	if (n.nodeType != 1) return ;
	if (n.getAttribute('spy2')) {
		i = spy2_elements.length;
		spy2_elements[i] = n;
		spy2_elements2 += elInfoTxt(n) + spy2_fldDelim;
	}
	for (var c = n.firstChild; c != null; c = c.nextSibling)
		__parseDoc(c);
}

//add event
function addEvent(obj, type, fn)
 {
 if (obj.addEventListener)
 obj.addEventListener( type, fn, false );
 else if (obj.attachEvent)
 {
 obj["e"+type+fn] = fn;
 obj[type+fn] = function() { obj["e"+type+fn]( window.event ); }
 obj.attachEvent( "on"+type, obj[type+fn] );
 }
 else 
{
	obj['on'+type]=fn;
}
 }
 
function removeEvent(obj, type, fn)
 {
 if (obj.removeEventListener)
 obj.removeEventListener( type, fn, false );
 else if (obj.detachEvent)
 {
 obj.detachEvent( "on"+type, obj[type+fn] );
 obj[type+fn] = null;
 obj["e"+type+fn] = null;
 obj['on'+type]=null;
 }
 }
//scroll handle - catch last scroll only! (but many occurs)
var ls_scroll_counter=0;
var ls_timer=0;
function lastScroll(fun, delta)
{
if(!delta)delta=150;
ls_scroll_counter++;
ls_timer=setTimeout(function(t)
	{
	return function()
		{if (ls_scroll_counter == t)
			{
			//scroll event handler
			fun();
//			window.status='scroll > '+scrollW();
			ls_scroll_counter=0;
			ls_timer=0;
			}
		}
	}(ls_scroll_counter),
	// sleep time in ms before firing scroll handler
	delta)
}
//-----------------------------------------------------------

//-----------------------------------------------------------
//resize handle - catch last resize only! (minimum 2 occurs)
var lr_resize_counter=0;
var lr_timer=0;
function lastResize(fun, delta)
{
if(!delta)delta=150;
lr_resize_counter++;
lr_timer=setTimeout(function(t)
	{
	return function()
		{if (lr_resize_counter == t)
			{
			//scroll event handler
			fun();
			lr_resize_counter=null;
			lr_timer=null;
			}
		}
	}(lr_resize_counter),
	// sleep time in ms before firing resize handler
	delta)
}



// generate identifier
function makeRnd(n)
{
	if (!arguments.length) var n = 10;
	var rnd;
	var rndstr = '';
	do {
		rnd = Math.round(Math.random() * 74) + 43;
		if ((rnd >= 48 && rnd <= 57) |
			(rnd >= 65 && rnd <= 90) |
			(rnd >= 97 && rnd <= 122)) {
				rndstr += String.fromCharCode(rnd)
			}
	} while (rndstr.length < n);
	return rndstr;
}

// store identifier in cookie
function setSpyId()
{
	var coo = document.cookie;
	if (coo.indexOf('idSpy=') != -1)
		return 1;

	var st = 'idSpy=' + makeRnd();

	if (spy2_remember) {
		var nextyear = new Date();
		nextyear.setFullYear(nextyear.getFullYear() + 1);
		st += '; expires=' + nextyear.toGMTString();
	}
	st += '; path=/';
	document.cookie = st;
	echo(document.cookie);
	return 0;
}

//-----------------------------------------------------------
// AJAX
//-----------------------------------------------------------

var XMLHttpFactories = [
    function () {return new XMLHttpRequest()}, // Opera, Mozilla
    function () {return new ActiveXObject("Msxml2.XMLHTTP")},   // IE
    function () {return new ActiveXObject("Msxml3.XMLHTTP")},   // IE
    function () {return new ActiveXObject("Microsoft.XMLHTTP")} // IE
];

// создание объекта AJAX с учетом браузера
function createAjax() {
   var xmlhttp = false;
   for (var i = 0; i < XMLHttpFactories.length; i++) {
           try {
                  xmlhttp = XMLHttpFactories[i]();
          }
          catch (e) {
                  continue;
          }
          break;
    }
    return xmlhttp;
}

// отправка spyData
function aj_send()
{
	var data = '';
	if (firstTime) {
		firstTime = 0;
		data += 'first=1&';
	}

	data += 'spyData=' + spyData;
    ajax.onreadystatechange = aj_ready;
    ajax.open('POST', '_spy/spy_server.php', true);
    ajax.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;');
    ajax.send(data);    
}

// сброс ajax
function aj_ready()
{
    if (ajax.readyState != 4) return ;
    ajax.abort();
    return ;
}

// periodical executer
function periodical()
{	
/*	if (spy2_debug) {
		alert('Ajax send\n' + spyData.length + ': ' + spyData);
		spyData = '';
		return ;
	}
*/
	if (spyData.length >= dataSize) {
		aj_send();		
		spyData = '';
	}
}

//-----------------------------------------------------------
// service
//-----------------------------------------------------------
function echo(text)
{
	if (!spy2_debug) return ;
	alert(text);
}