/**
 * @author fmap team
 */
var EGetData = "php/GetData.php?type=";
var EEditData = "php/EditData.php?type=";
//var EGetData = "_php/GetData.php?type=";
//var EEditData = "_php/EditData.php?type=";
var ESaveTrack = "php/SaveTrack.php";
var EPHP_TrackPoints = EGetData + "track_points";
var ELogin = "php/login.php?username=";
var ESignUp = "php/signup.php?";
var EProfile = "php/profile.php?";
var EForgetPass = "php/forgetpass.php?";
//var EUser_Track = EGetData + "user_tracks";
/** globals */

/* cookies */
/** create cooky name=value with expiration days or now expiration */
function _createCookie(name,value,days) {
	if (days) {
		var date = new Date();
		date.setTime(date.getTime()+(days*24*60*60*1000));
		var expires = "; expires="+date.toGMTString();
	}
	else var expires = "";
	document.cookie = name+"="+value+expires+"; path=/";
}
/** privacy Dictionary access function to avoid error for bad key value 
 * 
 * @param {Object} id - main table index 
 * @param {Object} id2 - secondary key index
 */
function _PrivacyDict(id,id2) {
	if(gPrivacyDict){
		if(gPrivacyDict[id]) return gPrivacyDict[id][id2];
		else{
			_console("gPrivacyDict is not defined for:"+id);
		}
	} else {
		_console("gPrivacydict is not defined");
	}
	return "";
}
/** readCooky name */
function _readCookie(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;
}

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

/** copy all fields src object to dest object */
function _copyFields(src,dest){
	for(var i in src){
		dest[i]=src[i];
	}
}
/**
 * joint two NodeList and return sum as array (no push on NodeList object)
 * @param {Object} list1
 * @param {Object} list2
 */
function _joinNodeList(list1,list2) {
	var ret=Array();
	for(var i=0;i<list1.length;i++) ret[ret.length]=list1[i];
	for(var i=0;i<list2.length;i++) ret[ret.length]=list2[i];
//	ret.concat(list1);
//	ret.concat(list2);
	return ret;
/*	var len1 = list1.length;
	if (list2.length > 0) {
		for(var i=0;i<list2.length;i++){
			list1[len1+i]=list2[i];
		}
	}
	return list1;*/
}	
/**
 * return key value
 * @param {Object} key - key name
 * ex. status=nok key is status value - nok
 */
String.prototype.key_value = function(key){
	var b=this.indexOf(key+'=');
	this.indexOf('w');
	if(b<0)b=0;
	else b+=key.length+1;
	var e=this.indexOf(';',b);
	if(e<0)e=this.indexOf('&',b);
	if(e<0)e=this.indexOf(' ',b);
	if(e<0)e=this.length-1;
	var ret=this.substring(b,e);
	return ret;
};
/**
 * return object with setup split parameters; 'e' parameters are decoded
 * @param {Object} obj optionaly object to be setup
 */
String.prototype.toObject = function(obj){
	if(!obj)var obj={};
	var array=this.split(';');
	for(var i=0;i<array.length;i++){
		var key_value=array[i].split('=');
		if(key_value[0]=='e') _hexBackDecode(key_value[1]).toObject(obj);
		else if(key_value[0]&&(typeof key_value[1] != "undefined"))obj[key_value[0]]=key_value[1];
	}
	return obj;
};

/**
 * parse string as url to Object
 * @param obj - option object to setup url fields
 * return object with parametrs as fields or table if more than one value comma separated
 * ex. http://fmap.eu/?public&user=test&tracks=12:tet,121:tee,121,12122
 * return {public:,user:'test',tracks:[12:te,121:tet,121,12122]}
 */
String.prototype.parseUrl2Obj = function(obj){
	if(!obj)var obj={};
	obj.sizeof=0;
	var url=decodeURIComponent(this);
	var array=url.split('?');
	obj.url=array[0];
	if(!array[1])return obj; //no query string
	var pars=array[1].split('&'); //split query
	for(var i=0;i<pars.length;i++){
		var key_value=pars[i].split('=');
		var ifArray=key_value[0].split('[]');
		if (typeof key_value[1]== "undefined") { //only field no value 
			obj[ifArray[0]] = true;
			obj.sizeof++;
			continue;
		}
		if(typeof ifArray[1]== "undefined"){ //not array field
			obj[ifArray[0]] = key_value[1];
			obj.sizeof++;
			continue;
		}
		//array field so split it
		var values=key_value[1].split(',');
		obj[ifArray[0]]=[];
		obj.sizeof++;
		for(var j=0;j<values.length;j++){
			var a2=values[j].split(':');
			if(!a2[1])a2[1]='';
			obj[ifArray[0]][a2[0]]=a2[1];
		}
	}
	return obj;
};

String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g, ''); }

String.prototype.validateUser = function(){
	var emailPattern = /^[\w.-@]{2,}$/; 
	return emailPattern.test(this.toString()); 
}

String.prototype.validateEmail = function(){
//	 var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
//		^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$ 
	var emailPattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/; 
	return emailPattern.test(this.toString()); 
}
/** Simple return  Xor String in hex format codec */
var Emask=0xaa; //xor mask
function _hexBackEncode(aText){
		if(!aText) return "";
		var retBuf='';
		for(var i=0;i<aText.length;i++){
			var ch=aText.charCodeAt(i);
			var n=new Number(ch^Emask);
			retBuf=n.toString(16)+retBuf;
		}
		return retBuf;
	}
function _hexBackDecode(aText){
		if(!aText)return "";
		var retBuf='';
		for(var i=0;i<aText.length;i=i+2){
			var ch=parseInt(aText.substring(i, i+2),16)^Emask;
			retBuf=String.fromCharCode(ch).concat(retBuf);

//			retBuf=String.concat(String.fromCharCode(ch),retBuf);
		}
		return retBuf;		
	}
	
/** Log console error if console avalable
 */
function _console(){
    if (typeof console != "undefined"&&console.log&&arguments.length>0) {
		var commands = ["log","error","warn","info","time","timeEnd",
				"debug","track","profile","profileEnd"];
		var ElogCom=4;
		var type=arguments[arguments.length - 1];
//		if(!type) type="log";
//		else arguments.length--;
		var ind=commands.indexOf(type);
		if (ind < 0) { //||!commands[type]) {
			type = "log";
			ind = 0;
		}
		else 
			arguments.length--;
		if(ind<ElogCom)arguments[0]=_now()+' '+arguments[0];
		if(!console[type]){
			//ex. Chrome has no time timeEnd methods
//			if(console.log) console.log("Console has no method:"+type); 
		} else {
			var ev='console.'+type+'(arguments[0]';
			for(var i=1;i<arguments.length;i++)ev+=',arguments['+i+']';
			ev+=')';
			eval(ev);
		}
	}
}
/**
 * setup status info text or html and its type (error,warn,narmal)
 */
function _status(text,type){
	var col={error:'red',warn:'yellow',normal:'green'};
	var e=_e("status");
	if(!e)return;
	e.innerHTML=text;
	color='green';
	if(type in col)color=col[type];
	e.style.color=color;
}
/** return Date_Time String 
 * @param aTS - timestamp in seconds
 */
function _DateAgo(aTS){
	var now = new Date();
	var dif = parseInt(now.getTime() / 1000) - aTS;
	if (Math.abs(dif) < 60) 
		return dif + lSAgo;
	if (Math.abs(dif) < 3600) 
		return parseInt(dif / 60) + lMinAgo;
	return _TS2Date(aTS,' ','-');
}
function _TS2Date(aTS,space,hyphen){
	var ESpace=' ';
	var EHyphen='-';
	if(EMapAPI=='yahoo'){ //only yahoo map support this html characters
		var ESpace='&nbsp;';
		var EHyphen='&#8209;';
	}
	if(!hyphen)hyphen=EHyphen; //non break hyphen
	if(!space)space=ESpace;
    var date = new Date(aTS * 1000);
    var d = date.getDate();
    var day = (d < 10) ? '0' + d : d;
    var m = date.getMonth() + 1;
    var month = (m < 10) ? '0' + m : m;
    var yy = date.getYear();
    var year = (yy < 1000) ? yy + 1900 : yy;
    var hh = date.getHours();
    var hour = (hh < 10) ? '0' + hh : hh;
    var mm = date.getMinutes();
    var min = (mm < 10) ? '0' + mm : mm;
    return year/*.toString().substring(2, 4)*/ + hyphen + month + hyphen + day + space + hour + ':' + min;
}
/**
 * return times aTS in second in format hh:mm or mm:ss if h=0
 * @param {Object} aTS
 */
function _TS2hhmm(aTS){
	var sign="";
	if(aTS<0){
		sign="-";
		aTS=-aTS;
	}
	var mm=Math.floor(aTS/60); //minutes
	var ss=aTS%60;
	var hh=Math.floor(mm/60); //minutes
	mm=mm%60;
	var sec= (ss < 10) ? '0' + ss : ss;
    var hour = (hh < 10) ? '0' + hh : hh;
    var min = (mm < 10) ? '0' + mm : mm;
    if(hh>0)return sign+hour + 'h' + min+'m';
	return sign+min + 'm' + sec+'s';
}

/** return Date String */
function _now(){
    var d = new Date();
	var m=new String(d.getMilliseconds()+1000);
    return d.toLocaleTimeString()+'.'+m.substring(1,m.length);
}
/** make event e compatible with IE .. */
function _event(e){
	if (!e) 
		e = window.event;
	if (!e.target) 
		e.target = e.srcElement; //for IE
	if (e.target.nodeType == 3) 
		e.target = e.target.parentNode; // defeat Safari bug
	if(!e.currentTarget) e.currentTarget=e.target; //IE didn't support it
}

/** show aId element */
function _show(aId){
	_e(aId).style.display = "block";
}
/** hide aId element */
function _hide(aId){
	_e(aId).style.display = "none";
}
/** document.getElementById(aId) */
function _e(aId){
    return document.getElementById(aId);
}

/** document.createElement(aName) */
function _ce(aName){
    return document.createElement(aName)
}

/** document.createTextNode(aName) */
function _ct(aText){
    return document.createTextNode(aText)
}
/** get field name of Object obj which value equals value */
function _indexOf(obj,value){
	for(var key in obj){
		if(obj[key]==value)return key;
	}
	return null;
}
/**
 * for IE&Opera this method need to be implemented
 * @param {Object} a - search object
 * @param {Object} ind - begin index
 */
if (!Array.indexOf) {
    Array.prototype.indexOf = function(a, ind){
        var i = 0;
        if (ind) 
            i = ind;
        while (a !== this[i] && i < this.length) 
            i++;
        if (i >= this.length) 
            return -1;
        return i;
    }
}
/**
 * getElementById Node class extention
 * @return first node with id or null if none
 * @param id string
 * @param ifBlockRec true to block recurency - only one level (faster)
 */
/*if(window.Node)
Node.prototype.getElementById = function(id){
	for(var i=0;i<this.childNodes.length;i++){
		if (this.childNodes[i].id === id) 
			return this.childNodes[i];
		else {
			var n=this.childNodes[i].getElementById(id);
			if(n) return n;
		}
	}
	return null;
}*/

_getElementById = function(elem,id,ifBlockRec){
	if(!elem.childNodes.length)return null;
/*	if(elem.tagName=="FORM"){
		for(var i=0;i<elem.elements.length;i++){
			if(elem.elements[i].id===id)return elem.elements[i]; 
		}
	} */
	for(var i=0;i<elem.childNodes.length;i++){
		if (elem.childNodes[i].id === id) 
			return elem.childNodes[i];
		else if(!ifBlockRec&&elem.childNodes[i].firstChild){
			var n=_getElementById(elem.childNodes[i],id);
			if(n) return n;
		}
	}
	return null;
}
/**
 * getElementByIdBuf Node class extention it make array with all ids
 * @return first node with id or null if none
 * @param id string
 * @param ifBlockRec true to block recurency - only one level (faster)
 */
_getElementByIdBuf = function(elem,id){
	if(typeof elem.ids == "undefined"){
		elem.ids=new Object();
		_getElementByIdMakeIds(elem,elem.ids);
	}
	if(typeof elem.ids[id] == 'object')return elem.ids[id];
	return null;
/*	for(var i in elem.ids){
		if(typeof elem.ids[i] == 'object'&&elem.ids[id]) {
			if(!isNaN(p.course_f)||i=='start')i=this.markers[i]=p; //not for approax points
		}
	}*/
}
/* prepare Ids array */
_getElementByIdMakeIds = function(elem,ids){
	if(!elem.childNodes.length)return;
	for(var i=0;i<elem.childNodes.length;i++){
		if(elem.childNodes[i].nodeType==1){ //ELEMENT_NODE
			if (elem.childNodes[i].id.length) {
				ids[elem.childNodes[i].id]=elem.childNodes[i];
			}
			if(elem.childNodes[i].firstChild){ //next level
				_getElementByIdMakeIds(elem.childNodes[i],ids);
			}
		}
	}
}
/**
 * create XML Document and provide function to use it
 */
function XML(text){
    this.xmlDoc = null;
	if(text) this.xmlDoc=this.parse(text);
}
/**
 * Parse the XML document contained in the string argument and return
 * a Document object that represents it.
 */
XML.prototype.parse = function(text) {
    if (typeof DOMParser != "undefined") {
        // Mozilla, Firefox, and related browsers
        return (new DOMParser()).parseFromString(text, "application/xml");
    }
    else if (typeof ActiveXObject != "undefined") {
        // Internet Explorer.
        var doc = XML.newDocument();  // Create an empty document
        doc.loadXML(text);            // Parse text into it
        return doc;                   // Return it
    }
    else {
        // As a last resort, try loading the document from a data: URL
        // This is supposed to work in Safari. Thanks to Manos Batsis and
        // his Sarissa library (sarissa.sourceforge.net) for this technique.
        var url = "data:text/xml;charset=utf-8," + encodeURIComponent(text);
        var request = new XMLHttpRequest();
        request.open("GET", url, false);
        request.send(null);
        return request.responseXML;
    }
};
XML.prototype.getKMLArray = function (){
	if(!this.xmlDoc)return;
	var list = this.xmlDoc.getElementsByTagName('Placemark');
	var l;
	var name;
	var coords;
	var array=new Array();
	for(var i=0;i<list.length;i++){
		var track=new Array();
		array[i]=track;
		l=list[i].getElementsByTagName('name');
		if(l) name=l[0].firstChild.nodeValue;
		else name=null;
		track.track_name=name;
		track.isSaved=false;
		track.id_track='~'+name;
		track.id_user=gUser.id;
		track.points=new Array();
		track.time=Math.ceil((new Date()).getTime()/1000);
		l=list[i].getElementsByTagName('coordinates');
		var p_ind=0;
		for(var j=0;j<l.length;j++){
			var t_coord=l[j].firstChild.nodeValue.split(new RegExp("[ \n]"));
			for(var k=0;k<t_coord.length;k++){
				if (t_coord[k].trim()) {
					var p = new Object();
					var tab = t_coord[k].split(',');
					if (tab[0]) 
						p.lng = tab[0];
					if (tab[1]) 
						p.lat = tab[1];
					if (tab[2]) 
						p.height = Math.ceil(10*tab[2]);
					if(p) track.points[p_ind++] = p;
				}
			}			
		}
	}	
	return array;
}
function make_blank()
{
document.getElementById('import_box').value = '';	
document.getElementById("box").innerHTML = "";
}
/**
 * create XMLHttpRequest and provide function to use it
 */
function XMLHttp(){
    this.iRequest = null;
	this.EMaxRequestCount = 4;
    try {
        this.iRequest = new XMLHttpRequest();
    } 
    catch (e) {
        var XmlHttpVersions = new Array("MSXML2.XMLHTTP.6.0", "MSXML2.XMLHTTP.5.0", "MSXML2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP");
        for (var i = 0; i < XmlHttpVersions.length && !this.iRequest; i++) {
            try {
                this.iRequest = new ActiveXObject(XmlHttpVersions[i]);
            } 
            catch (e) {
            }
        }
    }
    if (!this.iRequest) {
		_status(lConnError);
		  alert("XMLHttpRequest Error,check internet connection.");
	}
      
}

/**
 * load XML for User Interface
 * @param {Object} url
 * @param {Object} f - callback
 * @param ifXML - fasle - xml; true - text response
 * @param wait - if true wait for request ready State
 */
XMLHttp.prototype.loadXML = function(url,ifText,post,wait, f ){
    var request = this.iRequest;
    _console( " loadXML:", url);
    if (!request) 
        return false;
    //last request wasn't finished
    if (request.readyState != 4 && request.readyState != 0) {
		//wait couldn't be implemented because request.readyState is forozen in loop
		//maybe in future it will be possible
/*		if(wait){
			_console("start waiting for ready State;readState:"+request.readyState,'warn');
			var readyState=request.readyState;
			while(request.readyState != 4 && request.readyState != 0){
				if(this.iRequest.readyState!=readyState){
					readyState=this.iRequestst.readyState;
					_console("readState:"+this.iRequest.readyState,'warn');
				}
			};			
			_console("stop waiting for ready State;readState:"+request.readyState,'warn');
//			return false;
		} */
        _console("url blocked:", url,'warn');
        return false;
    }
    try {
		var ch='?';
		if(url.indexOf('?')>=0)ch='&';
        //fro IE7 XMLRequest must be before onreadystatechange definition
		if (post) {
			request.open("POST", url + ch + Math.floor(100000 * Math.random()), true);
			request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
      		request.setRequestHeader("Content-length", post.length);
      		request.setRequestHeader("Connection", "close")
		}
		else 
			request.open("GET", url + ch + Math.floor(100000 * Math.random()), true);
        if (f) {
            request.onreadystatechange = function(){
                var req = request;
                if (req.readyState == 4) {
					window.clearTimeout(timer);
                    var status = -1, responseXML = null;
                    try {
	                    status = req.status;
				        if (status != 200) {
							if(status==401){ //no session opened
								refreshStop(); //stop refresh
								_status(lAuthRequired,'error');
								_console('Authorization Required');
								if(window.confirm(lSorrySessBroken))
									window.location.reload();
//									dialog_login();
								return;
							}
							_status(lRespError+status,'error');
				            _console("loadXML connection status:" + status,'error');
							_console("Text response:"+req.response);
							return;
				        }
						if (ifText) {
							f(status, req.responseText);
						} else { //XML
	//						if (status != 200) return;
							responseXML = req.responseXML;
							if (!responseXML||!responseXML.firstChild 
								|| responseXML.firstChild.tagName == "parsererror") {
								_status(lParseError, 'error');
								_console("loadXML parser error or data is empty", 'error');
								_console("Text response:" + req.response);
								return;
							}
							f(status, responseXML);
						}
						refreshAds(req.responseText.length); //reload ads if long request
					}
					catch(err)
					{
					  _status(lRequestErr, 'error');
					  _console("XMLHttp error:"+ err.message+"; file:"+err.fileName
					  			+"; line"+err.lineNumber);
					}
                }
            }
        }
        request.send(post);
		var timeout = function(){
			if(request.readyState!=4 && request.readyState!=0){
				_status(lConnTimeOut,'error');
				request.onreadystatechange = function() {};
				request.abort();
				_console('XMLRequest timeout','warn');
			}
		}
		var timer=setTimeout(timeout,10000);
    } 
    catch (e) {
		_status(lConnError,'error');
        _console("Server connection error:" + e.toString(),'error');
        return false;
    }
    return true
}

/**
 * load XML/Text with counter error correcting trials
 * @param {Object} url
 * @param {Object} f - callback
 * @param ifXML - fasle - xml; true - text response
 * @param post - post text to send
 * @param wait - if true wait for request ready State
 * @param counter EMaxRequestCount if null
 * @return false if busy
 */
XMLHttp.prototype.loadXMLCorr = function(url,ifText, post,wait, counter, f ){
	var s=this;
	if(counter===null)counter=this.EMaxRequestCount;
	return this.loadXML(url,ifText,post,wait,function(status,response){
		if(status==200) f(status,response);
		else {
			--counter;
			if(counter>0) s.loadXMLCorr(url,ifText,post,wait,counter,f); //try again
		}
	})
}
/**
 * Load XML data into Array ex. array['tracks']['id'] or array['lastpoint'][0]['id']
 * @param {Object} aXMLurl - url
 * @param {Object} aTagName - First lettere is used as tag name
 * @param wait - if true wait for request ready State
 * @param {Object} func send result array to this function
 */
XMLHttp.prototype.loadXMLArray = function(aXMLurl,wait, func){
    var callBack = func;
    this.loadXML(aXMLurl,false,null,wait, function(status, data){
        //		try {
        var docElem = data.firstChild;
        var result = new Array();
        if(docElem)for (var i_node = 0; i_node < docElem.childNodes.length; i_node++) {
            var childNode = docElem.childNodes[i_node];
            var itemArray = new Array();
            if (!childNode.attributes) 
                continue; // node /n => attributes==null 
            result[childNode.tagName] = itemArray;
            for (var i_attr = 0; i_attr < childNode.attributes.length; i_attr++) {
                itemArray[childNode.attributes[i_attr].nodeName] = childNode.attributes[i_attr].nodeValue;
            }
            var raws = childNode.getElementsByTagName("d");
            for (var i = 0; i < raws.length; i++) {
                var row = new Array();
                for (var j = 0; j < raws[i].attributes.length; j++) {
                    var value = raws[i].attributes[j].nodeValue;
//                    if (value.length == 0) 
//                        value = null;
                    row[raws[i].attributes[j].nodeName] = value.replace(/\\n/g,"\n");
                }
                itemArray[i] = row;
            }
        }
        callBack(result,status);
    });
}
/**
 * Class take care about the same colour Pins (image src,polyline color)
 * @param aParent Pins class with all colors 
 * @param aPar data for this color group
 */
function Pin(aParent,aPar){
	var defaultType="pinl";
	this.parent=aParent; //user for geting icons parameters
	for(var key in aPar){ 	//copy all fields color,iconUrl,iconSize,iconAnchor
							//,iconShadowUrl,iconShadowSize,iconShadowAnchor
		if(typeof i == "function" )continue;
		this[key]=aPar[key];
	}
//	if(this[defaultType].iconUrl)
//		this.iconHide = this[defaultType].iconUrl.substring(0, this[defaultType].iconUrl.lastIndexOf('_')) + '_n.png'
/**
 * return true if normal icon is defined
 */
	this.isDef = function(){
		return !(typeof this[defaultType] == 'undefined');
	}
/**
 * return html tag for image aImg with border
 * @param {Object} aImg
 * @param {Object} border
 */
	this.getImgHTML = function(aImg,border){
		var b=(border?' style="border:1px solid '+this.color+'" ':'');
        return (aImg ? '<img class="cImage" src="' + aImg + '"'+b+'/>':'');
	}
/**
 * return img html source for normal icon with border if defined
 * @param {Object} border
 */
    this.getHTML = function(border){
		if(!this.isDef()) return '';
		return this.getImgHTML(this[defaultType].iconUrl,border);
    }
    this.getTypeHTML = function(aType,border){
		if(!this.isDef()) return '';
		return this.getImgHTML(this[aType].iconUrl,border);
    }
    this.getHideHTML = function(border){
		return this.getImgHTML(this.parent.iconHideUrl,border);
    }
	this.getAllTypeHTML = function(){
		var ret="";
		for(var i in this){
			if(typeof this[i]!= "object") continue;
			if(this[i].iconUrl){
				ret+=this.getImgHTML(this[i].iconUrl);
				ret+=this.getImgHTML(this.parent.param[i].iconShadowUrl);
			}
		}
		return ret;
	}
	this.getAllShadowHTML = function(){
		var ret="";
		for(var i in this.parent.param){
			if(typeof this[i]!= "object") continue;
			if(this.parent.param[i].iconShadowUrl){
				ret+=this.getImgHTML(this.parent.param[i].iconShadowUrl);
			}
		}
		return ret;
	}
	this.getIconUrl = function(ifHide){
		if(ifHide)return this.getIconHideUrl();
		if (this[defaultType].iconUrl) return this[defaultType].iconUrl;
		return '';
	}
	this.getIconTypeUrl = function(aType,ifHide){
		if(ifHide)return this.getIconHideUrl();
		if (this[aType]) return this[aType].iconUrl;
		return '';
	}
/**
 * return all icon and shadow parameter (url,size,anchor)
 * @param {Object} aType dot,pinl ..
 * @param {Object} ifHide true if hide(transparent) icon
 */
	this.getIconTypePar = function(aType,ifHide){
		if(!this[aType])return null;
		var iconUrl=this.getIconHideUrl();
		if (!ifHide)  iconUrl=this[aType].iconUrl;
		var ret= {'iconUrl': iconUrl};
		for(var i in this.parent.param[aType]){  //copy all proporties
			if(i == "indexOf")continue;
			ret[i]=this.parent.param[aType][i];
		}
		return ret;
	}
	this.getIconHideUrl = function(){
		if(this.parent.iconHideUrl) return this.parent.iconHideUrl;
    	return '';
	}
}

/**
 * Pins class take care about markers datas and associations
 */
function Pins(aPins){
	this.iconHideUrl='img/pins/pinl_n.png'; //image dimentions is not importent it'd siply empty image
    this.pins = new Array();
	this.param = aPins["param"];
	var iconHideCache=true; //hide icon cache only once
    var lastUsed = -1;
//    var div_pin = _e(divName);
//    var imgElems = div_pin.getElementsByTagName('img');
    var elem=_e("pins_cache");
	if (!elem) {
		elem=_ce("div");
		document.body.appendChild(elem);
		elem.style.display='none';
	}
	var innerHtml=elem.innerHTML;
	
    for (var i in aPins) {
		if(i == "indexOf")continue;
		if(i=="param")continue;
		var pin=new Pin(this,aPins[i]);
		this.pins.push(pin);
		innerHtml+=pin.getAllTypeHTML(); //load into HTML cache
		if (iconHideCache) {
			innerHtml += pin.getHideHTML(); //load into HTML cache
			innerHtml += pin.getAllShadowHTML(); //load into HTML cache
			iconHideCache=false;
		}
	}
	elem.innerHTML=innerHtml;
	
	
    this.next = function(){
        lastUsed++;
        if (lastUsed >= this.pins.length) 
            lastUsed = 0;
        return this.pins[lastUsed];
    }
}

/**
 * User class gover data and fuction off user/friend
 */
function User(array, parent,index){
	this.copyFields = function(array){
	    this.id_user = array["id_user"];
		this.id_user_friend = array["id_user_friend"];
		this.friend_id_privacy = array["friend_id_privacy"];
		this.user_id_privacy = array["user_id_privacy"];
		this.friend_name = array["friend_name"];
	    this.user_name = array["user_name"];
	    this.state = array["state"];
	    this.start = array["start"];
	    this.state_time = array['state_time'];
		if(this.state_time>0)parent.ifG=true; //online user
    	this.stateTimeStr = _TS2Date(this.state_time);
	    this.s_time = array['s_time'];
		this.id_point = array['id_point'];
		this.setTrackSrc(array['id_track']);
		this.points_limit =array['points_limit'];
		this.points_count =array['points_count'];
	}
	this.cType='pinl';
    this.parent = parent;
	this.copyFields(array);

	if (this.id_user==gUser.id){ //&&(!this.friend_mask || this.friend_mask.length == 0)) {
//		this.friend_mask = null; //user add sb as a friend but wasn't add by him
		this.id = this.id_user_friend;
		this.name = this.friend_name;
		this.id_privacy = this.user_id_privacy;
	}else {
		this.id = this.id_user;
		if (gUser.id && gUser.id!=-1 && gUser.id != this.id_user_friend) {
			_console('Curent User(' + gUser.id + 
				') inconsistent with new user_friend(' +
				this.id_user_friend +')', 'error');
		}
	    this.name = this.user_name;
		this.id_privacy = this.friend_id_privacy;
	}
	this.index = this.id;
	if(index)this.index = index;

//	this.track_source = null;


    this.pin = new Pin();
	this.marked=false;
    ;
    this.autoPanning = false;
    this.point = new Point(array, this,null,this.cType);

	/** create track for store received user points */
    this.init = function(array){
		if(!array)array=this;
        if(this.isValid()&&!this.pin.isDef())this.pin = gPins.next();
		if(!this.parent.d['tracks'].array[this.name]){
			var now = (new Date()).getTime() / 1000;
	        this.track = this.parent.d['tracks'].newFixElem(this.name, array);
			this.setTrackSrc();
			this.track.id=null;
			this.track.isSaved =false;
	        this.track.name = '_' + this.name;
	    	this.track.time = Math.ceil(now);
	    	this.track.timeStr = _TS2Date(this.track.time,' ','-');
			if(this.state_time > now - 15 * 60 && this.state=='ok'){ //if OK add first point 
				this.track.addP(this.point); //first point
				if(this.pin.isDef())this.track.setPin(this.pin); //autoshow track
			}

		}
 //       this.show();
    }
}

/** check if Item delete is forbiden or can be done only locally
 * @return 0-ok item can be deleted
 * 		1 - only reset 
 * 		2 - only locally
 * 		3 - none item is locked ex. user save datas to the track
 */ 
User.prototype.forbidDel = function() {
//	if (array[i].id==array[i].id_user_friend) return 3; // user can't delete ourself
	if (this.id==this.id_user_friend) return 3; // user can't delete ourself
	return 0;
}
/** return true if user is online */
User.prototype.isOnline = function(){
	return this.state=='ok';
}
/** set track source (current saved track) if track id_track is on track list */
User.prototype.setTrackSrc = function(id_track){
	if(typeof id_track=="undefined") id_track=this.id_track;
	else if(this.idTrack==id_track)return; //nothing change
	//unlink old track
	if (this.track_source) {
		this.track_source.link_track = null;
	}
	this.id_track=id_track;
	//link new id_track;
	if(id_track&&this.id_point>0){ 
		var track=this.parent.d['tracks'].array[this.id_track]
		if (track) {
			track.load();
			this.track_source = track;
			track.link_track = this.track;
		} else {
			this.track_source = null;
		}
	}else{
		this.track_source=null;
	}
	if(this.track&&!this.track.count&& this.pin.isDef()){
		this.track.setPin(this.pin); //autoshow track
	}
}

/** return name ifi autoPanning is on */
User.prototype.getIdNameAutoPanning = function(){
	if(this.autoPanning) return this.getIdName();
	return '';
}
/** return name */
User.prototype.getIdName = function(){
	return this.name;
}
/** return true if object has valid datas */
User.prototype.isValid = function(){
	if (typeof this.point=='undefined'||!this.point.isValid())return false;
	return true;
}
/** erase this instance from local memory */
User.prototype.eraseLocal = function(){
	this.hide();
    this.point.erase();
}
/** change autoPanning flag */
User.prototype.setAutoPanning = function(aAutoPanning){
	if (typeof aAutoPanning != 'undefined') 
		this.autoPanning = aAutoPanning;
	else 
		this.autoPanning = !this.autoPanning;
	if (this.autoPanning) 
		this.setPin();
}
/** change autoPanning flag,refresh and Center */
User.prototype.setAutoPanningCenter = function(){
	this.autoPanning=!this.autoPanning;
	this.parent.table.refresh();
	if(this.autoPanning)this.point.Center();
}
/** return bounding box */
User.prototype.getBoundingBox = function(){
	if(!this.pin.isDef()||!this.isValid()) return null;
	var p=this.point;
	if(Math.abs(p.lat)<.1&&Math.abs(p.lng)<.1) return null;
	return new BoundingBox(p.lat,p.lng,p.lat,p.lng);
}
/** center and Zoom at this elem */
User.prototype.centerZoom = function() {
	var b=this.getBoundingBox();
	if(b) gMap.setBounds(b);
}

/** replace old record and add old to track */
User.prototype.replace = function(n){
	//copy fields
	this.copyFields(n);
    if (this.point.time != n.point.time) { //other point
        this.point.erase();
    	if(!this.track_source) { //new possition so add to track if no source track
//			this.setTrackSrc(this.id_track); //setup again after load tracks
			if(!this.track.count){ //first point 
//				this.track.addP(this.point); //first point
				if(this.pin.isDef())this.track.setPin(this.pin); //autoshow track
			}
			var nn = new Point(n.point,this.track,null,'dot');
	        this.track.addP(nn,1); //this.point);
	        //update track if exist
		}
    }
    this.point.erase(); //stop blinking and remove marker
    this.point = n.point;
    this.point.parent = this;
    if (this.pin.isDef()) {
        this.point.show();
        this.point.blink(true);
        if (this.autoPanning) 
            this.point.Center();
    }
	return false; //don't change element
}

/** return Label string used in point's market label */
User.prototype.getLabel = function(){
    return this.name;
}
var EStateCol = {
    'ok': '#1B2', //green
    'on': 'blue',
    'off': 'red',
    'no GPS': 'yellow',
    'blocked': 'purple',
    'no signal': '#DB0', //gold
    'no connection': 'crimson',
	'?':'fuchsia',
	'wait4inv':'#88d',
	'fwait4inv':'#Fc2'
};
/** hide point and Pin */
User.prototype.hidePin=function(){
    this.hide();
    this.pin = new Pin();
}
/** return row (all cells) as html*/
User.prototype.getHTML = function(aField){
    var r = '';
	var now = (new Date()).getTime() / 1000;
	var col='black';
	var onmouseover = '';
	var title = '';
	var state = lStateArray[this.state];
	if(gUser.id==-1) { //public 
		if (this.state_time > 0) {
			if (this.state_time < now - 15 * 60 && this.state != 'off') 
				this.state = '?'; //LAST UPDATE >15min. so state undef.
			onmouseover = 'onmouseover="this.title=\''+lState+':' + state +
			'; '+lLastUpdate+':\'+_DateAgo(' +
			this.state_time +');"';
			col=EStateCol[this.state]; //setup color
		}
		else //hide online info for non FAGPS user
			title = ' title="'+'"' ;
	} else if (typeof this.friend_id_privacy!= 'undefined' && this.friend_id_privacy!=null) {
		if (this.state_time > 0) {
			if (this.state_time < now - 15 * 60 && this.state != 'off') 
				this.state = '?'; //LAST UPDATE >15min. so state undef.
			onmouseover = 'onmouseover="this.title=\''+lState+':' + state +
			'; '+lLastUpdate+':\'+_DateAgo(' +
			this.state_time +')+\'; '+lRights+':' +_PrivacyDict(this.id_privacy,gLang) +'\';"';
			col=EStateCol[this.state]; //setup color
		}
		else //hide online info for non FAGPS user
			title = ' title="'+lRights+':' +_PrivacyDict(this.id_privacy,gLang) +'"' ;
	} else if(this.id_user==gUser.id) { //you wait for invitation 
		if (this.start) 
			onmouseover = 'onmouseover="this.title=\''+lWait4Invitation +
			'\'+_DateAgo(' + this.start +')+\'); '+lRights+':' +_PrivacyDict(this.id_privacy,gLang) +'\';"';
		else 
			title = ' title="'+lAbnormlFriendConn+'"';
		col=EStateCol['wait4inv'];
	} else { //Your friend wait for invitation 
		if (this.start) 
			onmouseover = 'onmouseover="this.title=\''+lFriendWait4Inv +
			'\'+_DateAgo(' + this.start +')+\'); '+lRights+':' +''+'\';"';
		else //it shouldn't happen
			title = ' title="'+lAbnormlFriendConn+'"';
		col=EStateCol['fwait4inv'];
	}
	r += '<TD ' + onmouseover + title + '><div style="color:' +
	col +
	'">' +
	this.name +
	'</div></TD>';
	r += '<TD ' + onmouseover + title + '>' + this.pin.getHTML(this.autoPanning) + '</TD>';
	r += '<TD onclick="data_onclick(event);return false;" style="text-align:center"><A>&raquo;</A></TD>';
    return r;
}
/** setup new Pin */
User.prototype.setPin=function(aPin){
	if(!aPin)aPin=gPins.next();
    this.pin = aPin
    this.show();
}
/** return header html */
User.getHeader = function(){
    var r = '';
    r += '<TH title="'+lNameUserFriend+'">'+lUser+'</TH>';
    r += '<TH title="'+lClick2ChoosePin+'">&bull;</TH>';
    r += '<TH onclick="data_onclick(event);return false;" title="'+lMenu+'"><A>&raquo;</A></TH>';
    return r;
}
User.prototype.onclick = function(aField, td){
    switch (aField) {
        case 1://pin
        	if (!this.isValid())return false;
            td.innerHTML = '';
            if (!this.pin.isDef()) {
                this.setPin();
                td.innerHTML = this.pin.getHTML();
            }
            else { //empty
                this.hidePin();
            }
            return false;
		case 2:
			return false; //no selection
    }
	if (this.marked) {
		this.parent.d['tracks'].deleteUserId(this.id);
		this.parent.d['locs'].deleteUserId(this.id);
	} else {
		this.parent.d['tracks'].addUserId(this.id);
		this.parent.d['locs'].addUserId(this.id);		
	}
    return true;
}
/** show market */
User.prototype.show = function(){
    if (this.point == null) 
        return;
    this.point.show(true);
}
/** hide market */
User.prototype.hide = function(){
    if (this.point == null) 
        return;
    this.point.hide();
}
/**
 * User location class gover data and fuction off user/friend
 */
function Loc(array, parent, index){
	this.cType="flag";
//	_copyFields(array,this);
	this.id = array["id"];
	this.name = array["name"];
	this.id_user = array["id_user"];
    this.user_name = array['user_name'];
    this.id_privacy = array['id_privacy'];
    this.id_s_user = array['id_s_user'];
    this.temp = array['temp'];
    this.description = array['description'];
	
	this.index = this.id;
	if (index) 
		this.index = index;
	this.point = new Point(array, this,null,this.cType);
	//    this.lastPoint = new Point(array, this);
	this.parent = parent;
	this.pin = new Pin();
	this.marked = false;
	
	this.init = function(){
		if (this.isValid())this.pin = gPins.next();
//		this.show();
	}
}
/** static function used to add new location and send it on server */
Loc.addLoc = function (name,lat,lng,alt){
	if(gDialog)return; //use gDialog to be sure only one dialog is open
	var options={name:name||'',id_privacy:gPrivacyDefault,id_s_user:0, lat:lat||'', lng:lng||'',alt:alt||''};
	gDialog = new Dialog('add_loc_dialog',options,function(ret,target){
		if(!ret) { //Cancel,Public
			gDialog=null;
			return true;
		}
		//trim all field
		for (var i in ret){
			if(typeof ret[i] =='string')ret[i]=ret[i].trim();	
		}
		var id=null;
		var mes='';
		if(ret.name==options.name&&ret.lat==options.lat&&ret.lng==options.lng
				&&ret.alt==options.alt) {
			//nothing change
			mes=lNothingChange;
			id='nothing';
//			gDialog=null;
//			return true;
		}
	    else if (!ret.name.validateUser()) {
			mes=lPleaseCorrentUser;
			id='name';
	    } else if (ret.lat>90||ret.lat<-90) {
	        mes=lLatNotCorr;
			id='lat';
	    } else if (ret.lng>180||ret.lng<-180) {
	        mes=lLonNotCorr;
			id='lng';
	    } else if (ret.alt<-20000||ret.alt>100000) {
	        mes=lAltNotCorr;
			id='alt';
		}else if (ret.control!=eval(_getElementById(gDialog.elem,'lcontrol').innerHTML)){
	        mes=lBotOrHuman;
			id='control';			
		}
		if (id) {
			gDialog.innerHTML('info', mes, "color:red;visibility:visible");
			if(id!='nothing')gDialog.showError(id);
			return false;
		}
		var data='add_locs&p1='+escape(ret.name)+'&p2='
			+escape(ret.id_privacy+','+ret.id_s_user+','+ret.lat+','
				+0+ret.lng+','+(ret.alt?ret.alt*10:'NULL'));
		gDialog.innerHTML("info",lPleaseWait,"color:black;visibility:visible");
		gXMLRequestUI.loadXMLCorr(EEditData+data
				,true,null,false,null,function(status,response){
			if(status!=200){
				gDialog.innerHTML("info",lConnError+' ('+status+')'
					,"color:red;visibility:visible");
				return;
			}
			if(response.indexOf('Ok')==0){
				gDialog.hide();
				gDialog=null;
				refreshA();
				return;
			} else {//NOK
				gDialog.innerHTML("info",lAddLocFail
					,"color:red;visibility:visible");
				if(gDebug)window.alert(response);
				return;
			}
		});
	});
	gDialog.innerHTML('lcontrol',Math.ceil(Math.random()*10)+'+'+
		Math.ceil(Math.random()*10));
}
/** check if Item delete is forbiden or can be done only locally
 * @return 0-ok item can be deleted
 * 		1 - only reset 
 * 		2 - only locally
 * 		3 - none item is locked ex. user save datas to the track
 */ 
Loc.prototype.forbidDel = function() {
	return 0;
}
/** return name */
Loc.prototype.getIdName = function(){
	return this.name;
}
/** erase this instance from local memory */
Loc.prototype.eraseLocal = function(){
	this.hide();
    this.point.erase();
}
/** return bounding box */
Loc.prototype.getBoundingBox = function(){
	if(!this.pin.isDef()||!this.isValid())return null;
	var p=this.point;
	if(Math.abs(p.lat)<.1&&Math.abs(p.lng)<.1) return null;
	return new BoundingBox(p.lat,p.lng,p.lat,p.lng);
}
/** center and Zoom at this elem */
Loc.prototype.centerZoom = function() {
	var b=this.getBoundingBox();
	if(b) gMap.setBounds(b);
}

/** return Label string used in point's market label */
Loc.prototype.getLabel = function(){
    return this.name
}

/** return row (all cells) as html*/
Loc.prototype.getHTML = function(aField){
    var r = '';
	var n = this.name 
	if(this.user_name) n+= '(' + this.user_name + ')';
//	if (this.parent.d['users'].array[this.id_user] != undefined) {
//		n +=  '(' + this.parent.d['users'].array[this.id_user].name + ')';
//	}
	var title_n=n;
	var s='';
	if (this.temp == "yes") {
			s = 'style="font-weight: bold;color:#999;"';
			title_n=lTemp+'!! '+title_n;
		}
	if(this.id_privacy<32) {
			s='style="font-weight: bold;color:green;"';
			title_n=lPublic+'!! '+title_n;
		}
    r += '<TD title="' + title_n + '" '+s+'>' + n + '</TD>';
    r += '<TD>' + this.pin.getTypeHTML(this.cType) + '</TD>';
	r += '<TD onclick="data_onclick(event);return false;" style="text-align:center"><A>&raquo;</A></TD>';
    return r;
}
/** return header html */
Loc.getHeader = function(){
    var r = '';
    r += '<TH title="'+lLocNameUser+'">'+lLocation+'</TH>';
    r += '<TH title="'+lClick2ChoosePin+'">&bull;</TH>';
    r += '<TH onclick="data_onclick(event);return false;" title="'+lMenu+'"><A>&raquo;</A></TH>';
    return r;
}
/** return static or dynamic title name*/
Loc.prototype.getTitle = function(aField){
    switch (aField) {
        case 'name':
            return this.name + "(" + this.user_name + ")";
        //        case 'id_user':
        //            return 'Location name';
        case 'pin':
            return lShowOnMap;
    }
    return false;
}
/** return true if location is valid */
Loc.prototype.isValid = function(){
	if (typeof this.point=='undefined'||!this.point.isValid())return false;
	return true;
}
/** setup new Pin */
Loc.prototype.setPin=function(aPin){
	if(!aPin)aPin=gPins.next();
    this.pin = aPin
    this.show();
}
/** hide point and Pin */
Loc.prototype.hidePin=function(){
    this.hide();
    this.pin = new Pin();
}
Loc.prototype.onclick = function(aField, td){
    switch (aField) {
        case 1://pin
        	if (!this.isValid())return false;
            td.innerHTML = '';
            if (!this.pin.isDef()) {
                this.setPin();
                td.innerHTML = this.pin.getTypeHTML(this.cType);
            }
            else {
                this.hidePin();
            }
            return false;
    	case 2:
			return false; //no selection
		}
    return true;
}
/** show market */
Loc.prototype.show = function(){
    if (this.point == null) 
        return;
    this.point.show();
}
/** hide market */
Loc.prototype.hide = function(){
    if (this.point == null) 
        return;
    this.point.hide();
}
Loc.prototype.replace = function(n){
//	var show=false;
	n.pin=this.pin;
	n.marked=this.marked;
	if(this.pin.isDef())n.show;
	return true; //replace this on n
}

/**
 * Table class used to store aElem datas and show it in aDivId
 * @param {Object} aDivID div area id
 * @param {Object} aElem
 */
function Datas(aDivID, aElem, gData){
	/** inits arrays */
	this.init = function(){
		this.fixCount=0; //number of fixed element always on top of the list
		this.array=new Array();
		this.ordArray=new Array();
	/** list of selected elements */
		this.selList=new Array();
		this.selList.counter=0;
	/** selected users id */
		this.id_user=new Array();
		this.id_user.counter=0;
		this.ifG = (this.index!='users'); //online user
	}
	
	this.refreshOrd=true; //false; //if true refresh table on the end of data update
	this.index=aDivID;
	this.init();
    this.elem = aElem;
    /** global Datas table */
    this.d = gData;
	/** table used to show array on screen */
    this.table = new Table(aDivID, this);
	
}
/** setup options list in ee Element */
Datas.prototype.addOptions = function(ee){
	if(!this.array)return;
	for(var i in this.ordArray){
		if(i == "indexOf") continue;
		// do not show current user
		if(this.ordArray[i].id_user_friend
			&&this.ordArray[i].id_user_friend==this.ordArray[i].id_user) continue;
		var optn = document.createElement("OPTION");
		optn.text = this.ordArray[i].name;
		optn.value = this.ordArray[i].id;
		ee.options.add(optn);
	}
}
/** get element by Id */
Datas.prototype.getElemById= function(aId){
	if(!this.array)return;
	return(this.array[aId]);
}
/** get element by Name */
Datas.prototype.getElemByName= function(aName){
	if(!this.array)return;
	for(var i in this.array){
		if(i == "indexOf") continue;
		if(this.array[i].name==aName)return this.array[i];
	}
	return null;
}
/** get element by Id or Name */
Datas.prototype.getElemByIdOrName= function(aIdName){
	if(!this.array)return;
	if(this.array[aIdName])return this.array[aIdName];
	return this.getElemByName(aIdName); 
}
Datas.prototype.hideShow= function(aArray){
	if(!aArray)return;
	for(var i in this.array){
		if(i == "indexOf") continue;
		if(typeof aArray[i]=="undefined"
		 &&typeof aArray[this.array[i].name]=="undefined") this.array[i].hidePin();
		else this.array[i].setPin();
	}
}
/** order table refresh on the end of data updating/adding */
Datas.prototype.refreshOrder = function(){
	this.refreshOrd = true; 
}

/** add new user id for selection and refresh table*/
Datas.prototype.addSelId = function(id_sel){
	if(!id_sel||id_sel in this.selList) return;
	this.selList[id_sel]='';
	this.selList.counter++;
//	gNewUrl.updateLocation();
}
/** remove new user id for selection and refresh table*/
Datas.prototype.deleteSelId = function(id_sel){
	if(!id_sel||typeof this.selList[id_sel]=="undefined")return;
	if(!delete this.selList[id_sel]) return;
	this.selList.counter--;
//        this.table.refresh();
}
/** get id's/names list of AutoPanning on elements */
Datas.prototype.getAutoPanningList = function(){
	if(!this.array||!this.elem.getIdNameAutoPanning)return ''; //only for users
	var ret='';
	for(var i in this.array){
		if(i == "indexOf")continue;
		var l=this.array[i].getIdNameAutoPanning();
		if(l)ret+=l+',';
	}
	if(ret)ret=ret.slice(0,ret.length-1);
	return ret;
}
/** get id's/names list of selected elements; return null if all is selected */
Datas.prototype.getSelList = function(){
//	if(this.ordArray.length==this.selList.counter)return ''; //all selected is default
	var ret='';
	var ifAll=true; //all selected is default for users and locs
	for(var i in this.array){
		if(i == "indexOf")continue;
		if (this.array[i].pin.isDef()&&this.array[i].getIdName()) {
			ret += this.array[i].getIdName() + ',';
		} else {
			ifAll=false;
		}
	}
	if(ret)ret=ret.slice(0,ret.length-1);
	if(ifAll)return null;
	else return ret;
}

/** get id's list of loaded elements */
Datas.prototype.selListJoin = function(){
	var ret='';
	for(var i in this.selList){
		if(i == "indexOf")continue;
		if(i!='counter')ret+=i+',';
	}
	if(ret)ret=ret.slice(0,ret.length-1);
	return ret;
}
/** add new user id for selection and refresh table*/
Datas.prototype.addUserId = function(id_user){
	if(id_user in this.id_user) return;
	this.id_user[id_user]='';
	this.id_user.counter++;
    this.table.refresh();
}
/** remove new user id for selection and refresh table*/
Datas.prototype.deleteUserId = function(id_user){
	if(!delete this.id_user[id_user]) return;
	this.id_user.counter--;
    this.table.refresh();
}
/** unmark all elements except iE */
Datas.prototype.unMark = function(iE){
	for(var i in this.array){
		if (i == "indexOf") continue;			
		if(i==iE)continue;
		if(this.array[i].marked){
			this.array[i].marked=false;				
		}
	}
}
/** true for records connected with selected user 
 * or if no user selected
 * false otherwise or if data is not valid (no point in track)
 * @param {Object} i - data id
 */
Datas.prototype.ifHide = function(i){
    if (this.array[i].ifHide&&this.array[i].ifHide())return true;
    if (typeof this.array[i].id_user == "undefined"||this.id_user.counter==0) 
        return false; //show_all
    return !(this.array[i].id_user in this.id_user);
    }
/** create and add new fix element on top of the list */
Datas.prototype.newFixElem = function(id, array){
    var n = new this.elem(array, this,id);
	this.addFixElem(n,id);
    return n;
}
/** create and add new elemenet on top of the list */
Datas.prototype.newElem = function(id, array){
    var n = new this.elem(array, this,id);
	this.addElem(n,id);
    return n;
}
/** delete one element from list and elem ourself */
Datas.prototype.deleteElem = function(id){
	var elem = this.array[id];
	if (!elem) 
		return;
	elem.eraseLocal();
	this.delElem(id);
}
/** delete one element only from list */
Datas.prototype.delElem = function(id){
	var elem = this.array[id];
	this.array[id]=undefined;
	var i;
	for (i in this.ordArray) {
		if(i == "indexOf")continue;
		if (this.ordArray[i] == elem) {
			this.ordArray.splice(i, 1);
			if (i < this.fixCount) 
				this.fixCount--;
		}
	}
}
/** refresh table if it was ordered */
Datas.prototype.refreshIfOrd = function (){
	if(this.refreshOrd) {
//		this.table.refresh();
		this.show();
		this.refreshOrd=false;
	}
}
Datas.prototype.getBoundingBox = function(aBBox){
	var b=null;
	if(!b)b=aBBox;
	for (var i in this.array) {
		if(i == "indexOf") continue;
		if(!this.array[i])continue;
		var b1 = this.array[i].getBoundingBox();
		if (b1) {
			if (b) {
				b.extend(b1.getNorthEast());
				b.extend(b1.getSouthWest());
			}
			else {
				b = b1;
			}
		}
	}
	return b;
}
Datas.prototype.centerZoom = function(){
		var b=this.getBoundingBox();
		if(b) { 
			gMap.setBounds(b);
			gUrlLink.setAutoZoom(this.index);
		}
}
Datas.prototype.show = function (){
	for (var i in this.array) {
//		if (i == "indexOf") continue;			
		if (!this.array[i] || typeof this.array[i] != "object") continue;			
        this.array[i].show();
    }
	this.table.refresh();
}

Datas.prototype.reset = function (){
	for (var i in this.array) {
//		if (i == "indexOf") continue;			
		if (!this.array[i] || typeof this.array[i] != "object") continue;			
        this.array[i].hide();
    }
	this.init();
	this.table.refresh();
}
/** add new normal element on top of the list */
Datas.prototype.addFixElem = function(elem,id){
	if(!this.array[id]){
		this.ordArray.splice(0,0,elem);
		this.fixCount++;
	}
	this.array[id]=elem;
	elem.index=id;
	this.refreshOrder();
}
/** add or replace new normal element on top of the list */
Datas.prototype.addElem = function(elem,id){
	if(!this.array[id])this.ordArray.splice(this.fixCount,0,elem);
	this.array[id]=elem;
	elem.index=id;
	this.refreshOrder();
}
Datas.prototype.add = function(array){
    _console("datas.add "+this.index,'time');
    if (array) {
        for (var i=array.length-1;i>=0;i--) {
            if (array[i] instanceof Array) {
                var p = new this.elem(array[i], this); //create instance of new element
                var old = this.array[p.id]; //is there record with such id
				var add=true;
                if (typeof old != "undefined") 
                    add=old.replace(p); //replace fields or prepare object to add
                if(add){
					this.addElem(p,p.id); //add or replace if exist 
                    p.init(array[i]); //show;icon..
                }
            }
        }
    }
	this.refreshOrder();
   	_console("datas.add "+this.index,'timeEnd');;
//    if(refresh)this.table.refresh(this);
}

/**
 * This engine take care about marker blinking(show/hide)
 * @param {Object} array
 * @param {Object} aParent
 */
function Blink(){
    this.points = new Array();
    this.flag = true;
	var s=this;
    //	var f=true;
	var refreshCall = function(){
		refresh.call(s);
	}
    var refresh = function(){
        try {
            if (this.flag) {
                for (var i = 0; i < this.points.length; i++) 
                    this.points[i].marker.changeIcon(this.points[i].parent.pin.getIconHideUrl());
                window.setTimeout(refreshCall, 500);
            }
            else {
                for (var i = 0; i < this.points.length; i++) 
                    this.points[i].marker.changeIcon(this.points[i].parent.pin.getIconTypeUrl(this.points[i].type));
                window.setTimeout(refreshCall, 1000);
            }
            this.flag = !this.flag;
        } 
        catch (e) {
            _console("Blink refresh error:", e,'log');
            window.setTimeout(refreshCall, 500);
        }
    }
    this.add = function(p){
        if (!p.marker) 
            return;
        var test = this.points.indexOf(p, 1);
        if (this.points.indexOf(p) > -1) 
            return;
        if (typeof p.marker == "undefined" || p.marker == null) 
            return;
        this.points.push(p);
    }
    this.remove = function(p){
        var i = this.points.indexOf(p);
        if (i >= 0) 
            this.points.splice(i, 1);
    }
    var gTimer = setTimeout(refreshCall, 5000);
}

/**
 * Point class gover data of single point(from Server and local ex. marker)
 * and fuctions to manage it
 * @param array - array define point proporties (lng,lat..)
 * @param aParent - parent object
 * @param index
 * @param aType - point/market type (start,pause,pinl..) 
 */
function Point(array, aParent, index, aType,aPrevPoint){
	this.cPauseTime=60; //pause time down limit is seconds
	this.copyFields = function(array){
	    if(array["id"])this.id = array["id"];
		this.index = index;
	    if(array["id_point"])this.id = array["id_point"];
	    this.lng = array["lng"];
	    this.lat = array["lat"];
	    this.height = array["height"];
		this.course = array['course'];
	    this.speed = array['speed'];
	    this.height_f = parseFloat(array["height"]);
		this.course_f = parseFloat(array['course']);
	    this.speed_f = parseFloat(array['speed']);
	    this.accuracy = array['accuracy'];
	    this.sat = array['sat'];
	    this.PDOP = array['PDOP'];
	    this.delta = array['delta'];
		this.dl_db = array['dl'];
	    this.time = array['time'];
	    this.end_time = array['end_time'];
	    this.s_time = array['s_time'];
	    this.id_track = array['id_track'];
	    this.id_user = array['id_user'];
	}
	
	this.copyFields(array);
	this.index = index;
    this.marker = null;
	if (aType) {
		this.type = aType; //pinl,start,stop used for pin names
	} else {
		this.type = null;
		if(this.end_time-this.time>this.cPauseTime)
			this.type='pause';
		if(!array['course']||(this.height_f+this.course_f+this.speed_f ==0)){
			this.type='approx';
			this.height_f=Number.NaN; //some point have 0 value
			this.course_f=Number.NaN;
			this.speed_f=Number.NaN;
		}
	}
    this.isBlink = false;
    this.parent = aParent; //use getLabel();pin.src;
    this.setParent(aParent);
    this.setPrevPoint(aPrevPoint,array["dist"]);
    var EPropArray = ['lat','lng','height','course','speed','accuracy','time','end_time'];
	var EPropTime = [0,0,0,0,0,0,1,1];
	/** return DB proporties label */
	this.getPostProp = function(){
		var r='_(';
		for(var i=0;i<EPropArray.length;i++) r=r+EPropArray[i]+',';
		r=r.substr(0,r.length-1)+')';
		return r;
	}
	/** return DB proporties values */
	this.getPostVal = function(){
		var r='_(';
		for (var i = 0; i < EPropArray.length; i++) {
			if (this[EPropArray[i]]) {
				if(EPropTime[i]) r = r +'FROM_UNIXTIME('+ this[EPropArray[i]] + '),';
				else r = r + this[EPropArray[i]] + ',';
			}
			else 
				r = r + '0,';
		}
		r=r.substr(0,r.length-1)+')';
		return r;
	}
}
/** set new parent and update it's timePause */
Point.prototype.setParent = function(aParent){
	this.parent=aParent;
	if (this.parent) {
		if(typeof this.parent.timePause!='undefined')this.parent.timePause +=this.end_time-this.time;//update track puase time
		if(this.parent.end_time<this.end_time)this.parent.end_time=this.end_time;
		if(this.parent.time>this.time)this.parent.time=this.time;
	}
}
/** set new PrevPoint and update parent dist.,dl,dist */
Point.prototype.setPrevPoint=function(aPrevPoint,aDist){
    this.dist=0;
	this.dl=0;
	this.dl2=0;
	if (aPrevPoint) {
		//cancel single approx point
		if(!aPrevPoint.course&&aPrevPoint.prev&&aPrevPoint.prev.course) {
			this.prev=aPrevPoint.prev;
			if (this.parent) this.parent.dist-=aPrevPoint.dl; //cancel distant to approax. point
		} else {
			this.prev = aPrevPoint;
		}
		this.dist = this.prev.dist;
	    if (aDist) {
			this.dist = aDist; //distance from use datas is more accure
		} else {
			this.dl = this.distance(aPrevPoint);
			this.dl2 = this.distance2(aPrevPoint);
			this.dist += this.dl; //distance from begining
		}
	}
	else 
		this.prev = null;
	if (this.parent) this.parent.dist = this.dist; //update track distant data
}
/** distance between this and linked point */
/**
 * Calculates the geodetic distance between the two points according to the
 * ellipsoid model of WGS84. Altitude is neglected from calculations.
 *
 * The implementation shall calculate this as exactly as it can. However, it
 * is required that the result is within 0.35% of the correct result.
 *
 * @param to
 *            the Coordinates of the destination
 * @return the distance to the destination in meters
 * @throws java.lang.NullPointerException
 *             if the parameter is null
 */
Point.prototype.distance2= function(aPoint) {
	return this.distance_azimuth(aPoint,false);
}
/**
 * Calculate distance between last and current point result valid only for
 * short distance!!!
 * @param isAzimuth=true return Azimuth otherwise distance in meters
 */
Point.prototype.distance_azimuth = function(to, isAzimuth){
	if (to == null) return 0;
	var lat2 = parseFloat(to.lat) * Math.PI / 180.0;
	var lon2 = parseFloat(to.lng) * Math.PI / 180.0;
	var lat1 = parseFloat(this.lat) * Math.PI / 180.0;
	var lon1 = parseFloat(this.lng) * Math.PI / 180.0;

	var R = 6371000; // m
	var r2 = Math.cos(lat1) * R; // radius of parallel of latitude
	var a = (lat2 - lat1) * R; //Latitude distance
	var b = (lon2 - lon1) * r2; //Longitude distance
	if (isAzimuth) {
		a = (Math.atan2(b, a) * 180 / Math.PI);
		if (a < 0) 
			return 360 + a;
		return a;
	}
	a = a * a;
	b = b * b;
	//			r2 = to.iAltitude-this.iAltitude; //big error on Altitude disturb distant accuracy
	//			r2= r2 * r2;
	a = Math.sqrt(a + b /*+ r2*/);
	return a;
}
/*
 * Haversine Formula (from R.W. Sinnott, "Virtues of the Haversine", Sky
 * and Telescope, vol. 68, no. 2, 1984, p. 159):
 *
 * See the following URL for more info on calculating distances:
 * http://www.census.gov/cgi-bin/geo/gisfaq?Q5.1
 */

Point.prototype.distance = function(to){
//	var to=this.linkedPoint;
	if (to == null) return 0;
	var lat2 = parseFloat(to.lat) * Math.PI / 180.0;
	var lon2 = parseFloat(to.lng) * Math.PI / 180.0;
	var lat1 = parseFloat(this.lat) * Math.PI / 180.0;
	var lon1 = parseFloat(this.lng) * Math.PI / 180.0;

	var earthRadius = 6371000; //km

	var dlon = (lon2 - lon1);
	var dlat = (lat2 - lat1);

	var a = (Math.sin(dlat / 2)) * (Math.sin(dlat / 2))
			+ (Math.cos(lat1) * Math.cos(lat2) * Math.sin(dlon / 2)* Math.sin(dlon / 2));

	var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));

	var km = earthRadius * c;

	return km ;
}
/** set type function */
Point.prototype.setType = function(aType){
	if (this.type != aType) {
		this.removeMarker(); //erase old marker	
		this.type = aType;	
	}
}
/** get type function */
Point.prototype.getType = function(){
	return this.type;
}
/**
 * true if coordinates are valid (not null, undefined..)
 */
Point.prototype.isValid = function(){
    if (typeof this.lng=='undefined'||typeof this.lat=='undefined'
		||this.lat === null || this.lng === null) return false;
    return true;
}
Point.prototype.toLatLonPoint = function(){
    var lat = parseFloat(this.lat);
    if (lat == 0 && this.lng == 0) 
        lat += 0.000001; //maps don't show polylines if 0,0
    return new LatLonPoint(''+lat, this.lng);
}
Point.prototype.zoomIn = function() {
	var b= new BoundingBox(this.lat,this.lng,this.lat,this.lng);
	gMap.setBounds(b);
}
Point.prototype.Center = function(){
    if (!this.isValid()) 
        return;
    gMap.setCenter(this.toLatLonPoint());
}
Point.prototype.blink = function(ifBlink){
    if (!this.isValid()) 
        return;
    this.isBlink = ifBlink;
    if (this.isBlink) 
        gBlink.add(this);
    else 
        gBlink.remove(this);
}
Point.prototype.show = function(ifBlink,ifHide){
    if (!this.isValid()||!this.type) 
        return;
    if (!this.marker) {
        this.createMarker(this.parent.pin.getIconTypePar(this.type,ifHide));
        if (!this.marker) 
            return;
    }
    this.marker.changeIcon(this.parent.pin.getIconTypeUrl(this.type,ifHide));
    this.marker.show();
    if (ifBlink) 
        this.blink(true);
}
Point.prototype.hideBubble = function(){
	if(this.marker)this.marker.closeBubble();
}
Point.prototype.hide = function(){
    if (this.marker == null) 
        return;
    if (this.isBlink) 
        gBlink.remove(this);
    this.marker.hide();
}
Point.prototype.removeMarker = function(){
    if (this.marker == null) 
        return;
    this.hide();
    gMap.removeMarker(this.marker);

	this.marker=null;
}
/** erase type and marker remove */
Point.prototype.erase = function(){
	this.setType(null);
    this.removeMarker();
}
function _zoomIn(id_point,id_array,id_data){
	var p = gData[id_data].array[id_array];
	if(p.point) p = p.point;
	else p = p.points[id_point];
	p.hideBubble();
	p.zoomIn();
}
function _addLoc(id_point,id_array,id_data){
	var p = gData[id_data].array[id_array];
	if(p.point) p = p.point;
	else p = p.points[id_point];
	Loc.addLoc('',p.lat,p.lng,p.height/* /10 */);
	p.hideBubble();
}
Point.prototype.createMarker = function(aIconPar){
	function row(key,value,unit) {
		if(!unit)unit='';
		if(!value&&value!=0)return;
		var t=value;
		if(unit=='Date'){
			unit='';
			t=_TS2Date(t);
		} else if (unit=='hhmm'){
			unit='';
			t=_TS2hhmm(t);
		}
		//for debug
		if(t>10000000&&(key.indexOf("time")>=0||key.indexOf("start")>=0)) t=_TS2Date(t)+' ('+t+')';
        address +='<dt>'+ key + ':</dt><dd>' + t +unit+ '</dd><br/>';
	}
    if (aIconPar == null || !aIconPar.iconUrl ||aIconPar.iconUrl.length < 2) 
        return;
	if (typeof this.lat=='undefined'||typeof this.lat=='undefined')return;
    var name = '';
    name = this.parent.getLabel();
    //    if (this.user) 
	switch(this.getType()){
		case 'stop':
		case 'start':
		case 'dot':name+=" ("+(this.dist/1000).toFixed(1)+" km)"; break;
		case 'down':name=lLowest+" ("+(this.height_f)+" m)"; break;
		case 'up':name=lHighest+" ("+(this.height_f)+" m)"; break;
		case 'speedup':name=lFastest+" ("+(this.speed_f)+" km/h)"; break;
		case 'pause': break; //name="Stop ("+Math.floor((this.end_time-this.time)/60)+" min.)"; break;
		case 'approx':name+=" ("+lApprox+")"; break;
	}
	if(this.end_time-this.time>this.cPauseTime)
		name+=" "+lStop+" ("+Math.floor((this.end_time-this.time)/60)+" min.)";
    if (typeof this.end_time != "undefined" && this.end_time > 0) 
        name += " " + _TS2Date(this.end_time);
	var ids="'"+this.index+"','"+this.parent.index+"','"+this.parent.parent.index+"'";
    var address = '<div class="bubble">';
	address += '<p id="title">'+this.parent.name+'</p><dl>';
	if(gDebug) { //print all proporties
	    for (var key in this){
			if (typeof this[key] == "number"||typeof this[key] == "string") {
				row(key, this[key]);
			}
		} 
	} else {
		switch(this.getType()){
			case 'stop':
			case 'start':
				if (this.parent&&this.parent.end_time) {
					row(lDistance,(this.parent.dist/1000).toFixed(1)+" "+lKm);
					var time=this.parent.end_time-this.parent.time-this.parent.timePause;
					row(lTime, time,'hhmm');
					row(lPause,this.parent.timePause,'hhmm');
					row(lSumTime,this.parent.timePause+time,'hhmm');
					if(time>0)row(lAvgSpeed,(this.parent.dist/time*3600/1000).toFixed(1),' km/h');
					row(lStart,this.parent.time,'Date');
					row(lEnd,this.parent.end_time,'Date');
				};
				break;
			default:
				if(this.dist)row(lDistance,(this.dist/1000).toFixed(1)+" "+lKm);
				if (this.parent&&this.parent.time) {
					var time=this.time-this.parent.time;
					if(time<0)time=0;
					row(lTime, _TS2hhmm(time));
				}
				if(this.end_time-this.time>60) row('pause',_TS2hhmm(this.end_time-this.time));
				row(lLatitude,this['lat']);
				row(lLongitude,this['lng']);
				row(lSpeed,this['speed'],' '+lKmh);
				row(lCourse,Math.ceil(this['course']),'&deg;');
				row(lAltitude,Math.ceil(this['height']),' '+lM);
				row(lDate,this['time'],'Date');

				break;
		}
	}
	if(this.parent.description)row(lDescription,this.parent.description);
	address+='</dl><p>';
	address+='<a href="javascript:_zoomIn('+ids+');" title="'+lZoomCenter+'">Zoom In</a>';
	address+='<a href="javascript:_addLoc('+ids+');" title="'+lAddLocation+'">Add</a>';
	address+='</p>';
	address+='</div>';
    //    var point = new LatLonPoint(this.lat, this.lng);
    
    this.marker = new Marker(this.toLatLonPoint());
    this.marker.setLabel(name);
    this.marker.setInfoBubble(address); //, type);
    //            marker.setIcon('http://labs.google.com/ridefinder/images/mm_20_red.png', new Array(12, 20), new Array(6, 20));
    //            marker.setShadowIcon('http://labs.google.com/ridefinder/images/mm_20_shadow.png', new Array(22, 20), new Array(6, 20));
    this.marker.setIcon(aIconPar.iconUrl, aIconPar.iconSize,aIconPar.iconAnchor); //new Array(14,18), new Array(12, 17));
    this.marker.setShadowIcon(aIconPar.iconShadowUrl,aIconPar.iconShadowSize); //' ');
    gMap.addMarker(this.marker);
}
/** data_onclink is handler for click event in last column in tables
 * it is twice quicker to use it than DOM
 * @param {Object} e - event
 */
function data_onclick(e){
	_event(e)
	var elem=e.target; //.parentNode;
	if(elem.tagName=='A')elem=elem.parentNode;
		var tab=elem.parentNode.id.split('_');
		if(elem.tagName=='TD')
			gData[tab[1]].table.tbodyMenu.show(e,e.target);
		else
			gData[tab[1]].table.theadMenu.show(e,e.target);
}
/**
 * Track class gover data and fuction of  track
 *
 */
function Track(array, parent, index){
	this.copyFields=function(array){
	    this.id = array['id_track'];
	    this.id_track = array['id_track'];
	    this.id_user = array['id_user'];
	    this.user_name = array['user_name'];
	    this.name = array['track_name'];
	    this.track_name = array['track_name'];
	    this.time = array['time'];
	    this.s_time = array['s_time'];
	    this.id_privacy = array['id_privacy'];
	    this.id_s_user = array['id_s_user'];
	    this.temp = array['temp'];
	    this.description = array['description'];
	}
	this.cMaxMarkers=50; //maksimum visible markers
	this.cMinMarkersDist=50; //m
	this.copyFields(array);
	//do not copy it for raplace
    this.count = 0; //PHP Bug? for 0 return ''
    if (array['count']) this.count = parseInt(array['count']);
	this.isSaved=true; //track is loaded from DB or was saved on it
	if(typeof array['isSaved']!= 'undefined')this.isSaved=array['isSaved'];
	
	var thisTrack=this;
    this.parent = parent;
    this.link_track = null; //linked track new point will send to this track
	this.index = this.id; 
	if(index)this.index = index;
    this.timeStr = _TS2Date(this.time,' ','-');
    this.pin = new Pin();
	this.marked=false;
	this.dist=null; //track distance
	this.time_pause=0; // for save null is forbidden
	this.timePause=0; // sum of all paused time in second
	this.end_time=0; // last point time
	this.lastMarkedDist=0; //last point with marker; used to distance sensitive market show
	if(typeof array['dist']!="undefined")this.dist=array['dist'];
	/** list of different marker category; order is important first is rewritten with next elem. */
	this.markers={'start':null,'stop':null,'down':null,'speedup':null,'up':null,
		set:function(aType,aPoint){ //setup new point and its type
//			if(this[aType]&&this[aType].getType()==aType) {
//				this[aType].setType('dot');
//			}
			this.unset(aType);
			this[aType]=aPoint;
//			aPoint.setType(aType);
		},
		unset:function(aType){ //hide this marker type
			if(this[aType]&&this[aType].getType()==aType) {
				this[aType].setType('dot');
				this[aType]=null;
			}
		}
	};

    this.points = new Array();
    this.polyline = null;
	if(array.points)this.addPoints(array.points);
    this.init = function(){
    }
}
/** check if Item delete is forbiden or can be done only locally
 * @return 0-ok item can be deleted
 * 		1 - only reset 
 * 		2 - only locally
 * 		3 - none item is locked ex. user save datas to the track
 */ 
Track.prototype.forbidDel = function() {
	if (!this.id) return 1; //only reset
	if (!this.isSaved) return 2; //delete only locally
	if (this.link_track) return 3; // track is used
	return 0;
}
/** return name */
Track.prototype.getIdName = function(){
	return this.id;
}
/** return true to hide track from list */
Track.prototype.ifHide = function(){
	if (typeof this.points=='undefined'||!this.count)return true;
	return false;
}
/** return true if track is valid and Pin can be setup */
Track.prototype.isValid = function(){
	if (typeof this.points=='undefined'||!this.count)return false;
	return true;
}
/** return bounding box */
Track.prototype.getBoundingBox = function(){
	if(!this.isValid()||!this.pin.isDef()||!this.points.length)return null;
	var b = new BoundingBox(90,180,-90,-180);
	for (var i in this.points) {
		if (typeof this.points[i] != "object") continue;			
		b.extend(this.points[i].toLatLonPoint());
	}
	return b;
}
/** return Label string used in point's market label */
Track.prototype.getLabel = function(){
//	if(this.parent.d['users'].array[this.id_user]==undefined) return "";
    if(this.user_name)return this.user_name;
    if(this.name)return this.name;
	return '';
}

/** return row (all cells) as html*/
Track.prototype.getHTML = function(aField){
    var r = '';
		var onmouseover = '';
	var title = '';
	if(this.time)
		onmouseover='onmouseover="this.title=_DateAgo(' + this.time + ');"';
	else title=' title="'+lNoData+'"';
	var s='';
	var n = this.name
	if(this.user_name) n+= '(' + this.user_name + ')';
	var title_n=n;
	if(!this.isSaved) s+='font-style:italic;color:#0aa;';
	if (this.temp == "yes") {
			s += 'font-style: italic;color:#999;';
			title_n=lTemp+' '+title_n;
		}
	if(this.id_privacy<32) {
			s+='font-weight: bold;color:green;';
			title_n=lPublic+' '+title_n;
		}
	if(s)s='style="'+s+'"'
    r += '<TD title="' + title_n + '" '+s+'>' + n + '</TD>';
    r += '<TD '+onmouseover+title+'>' + this.timeStr.substring(0, 11) + '</TD>';
    r += "<TD>" + this.count + '</TD>';
    r += '<TD>' + this.pin.getTypeHTML("ball") + '</TD>';
	r += '<TD onclick="data_onclick(event);return false;" style="text-align:center"><A>&raquo;</A></TD>';
    return r;
}
/** return header html */
Track.getHeader = function(){
    var r = '';
    r += '<TH title="'+lTrackOwner+'">'+lTrackUser+'</TH>';
    r += '<TH title="'+lTrackTime+'">'+lStartTime+'</TH>';
    r += '<TH title="'+lAmountTrack+'">&hellip;</TH>';
    r += '<TH title="'+lClickPin+'">&bull;</TH>';
    r += '<TH onclick="data_onclick(event);return false;" title="'+lMenu+'"><A>&raquo;</A></TH>';
    return r;
}
/** setup new Pin */
Track.prototype.setPin=function(aPin){
	if(!aPin)aPin=gPins.next();
    this.pin = aPin
    this.load_show();
}
Track.prototype.hidePin=function(){
    this.hide();
    this.pin = new Pin();
}
Track.prototype.onclick = function(aField, td){
    switch (aField) {
        case 3: //pin
        	if (!this.isValid())return false;
            td.innerHTML = '';
            if (!this.pin.isDef()) {
                this.setPin();
                td.innerHTML = this.pin.getTypeHTML("ball");
            }
            else { //empty
                this.hidePin();
            }
            return false;
		case 4:
			return false; //no selection
    }
    return true;
}
Track.prototype.centerZoom = function() {
	if(!this.count)return; //empty track
	var b=this.getBoundingBox();
	if(b) gMap.setBounds(b);
}
Track.prototype.load_show = function(){
	if(!this.count)return; //empty track
    if (this.points.length == 0) {
        this.load();
        return; //show will be excecuted after points loading
    }
	this.show();
}
Track.prototype.show = function(){
	if (!this.pin.isDef())return;
	this.copyMarkersType();
	//show dot markers in background
    for (var i = 0; i < this.points.length; i++) {
        if(this.points[i].getType()=='dot')this.points[i].show();
    }
	//other in foreground
    for (var i = 0; i < this.points.length; i++) {
		var type=this.points[i].getType();
        if(type!='dot'&&!this.markers[type])this.points[i].show();
    }
	this.showMarkers();
    var polyPoints = [];
	var lastPointInd=0;
	if (this.polyline){
    	gMap.removePolyline(this.polyline);
		polyPoints = this.polyline.points;
		if(this.points.last_length)lastPointInd=this.points.last_length;
	}
    for (var i=lastPointInd; i < this.points.length; i++) {
		// if only one approx. pos. connect GPS point directly
		if(i>1&&!this.points[i-1].course&&this.points[i-2].course) 
			polyPoints.push(this.points[i-2].toLatLonPoint()); 
		polyPoints.push(this.points[i].toLatLonPoint())
	}
	this.points.last_length=this.points.length;
    if (!this.polyline)this.polyline = new Polyline(polyPoints);
    this.polyline.addData({
        color: this.pin.color,
        width: 5,
        opacity: 0.6
    });
    gMap.addPolyline(this.polyline);
}
Track.prototype.hide = function(){
    for (var i = 0; i < this.points.length; i++) {
        this.points[i].hide();
    }
    gMap.removePolyline(this.polyline);
	delete this.polyline;
}
/** 
 * reset track - erase all point from memory
 */
Track.prototype.reset = function(){
	if(this.isSaved||!this.id)this.eraseLocal();
	this.hide();
	this.pin = new Pin();

	if(!this.id)this.count=0; //local history
	this.parent.deleteSelId(this.id);
}
/**
 * copy markers type to linked point
 * order in markers list is important; first elements are rewrite with next
 */
Track.prototype.copyMarkersType = function(){
	for(var i in this.markers){
		if(typeof this.markers[i] == 'object'&&this.markers[i]) {
			this.markers[i].setType(i);
		}
	}
}
/**
 * show markers in defined order
 * order in markers list is important; first elements are rewrite with next
 */
Track.prototype.showMarkers = function(){
	for(var i in this.markers){
		if(typeof this.markers[i] == 'object'&&this.markers[i]) {
			this.markers[i].show();
		}
	}
}
/** set all field in markers table on null */
Track.prototype.initMarkers = function(){
	for(var i in this.markers){
		if(typeof this.markers[i] == 'object') {
			this.markers[i]=null; 
		}
	}
}

/**
 * update markers list according point parameters
 * @param {Object} p
 * @param noStop if defined last point is not set as stop type
 */
Track.prototype.updateMarkers = function(p,noStop){
	if(this.markers['start']==null){ //init all marker if first point
		for(var i in this.markers){
			if(typeof this.markers[i] == 'object') {
				if(!isNaN(p.course_f)||i=='start')i=this.markers[i]=p; //not for approax points
			}
		}
		p.setType('start');
		return;
	}
	if(!p.getType()&&!noStop)this.markers.set('stop',p);
	else this.markers.unset('stop');
	if(p['height']&&!isNaN(p['height_f'])&&(!this.markers.up
		||this.markers.up['height_f']<p['height_f'])) this.markers.set('up',p);
	if(p['height']&&!isNaN(p['height_f'])&&(!this.markers.down
		||this.markers.down['height_f']>p['height_f']))this.markers.set('down',p);
	if(p['speed']&&!isNaN(p['speed_f'])&&(!this.markers.speedup
		||this.markers.speedup['speed_f']<p['speed_f']))this.markers.set('speedup',p);
	if(!p.getType()){ //make dot at specific distant
		if(p.dist>this.lastMarkedDist){
			p.setType('dot');
			this.lastMarkedDist+=Math.max(this.cMinMarkersDist,this.dist/this.cMaxMarkers);
		} else {
			p.setType('');
		}
	}				

//	if(p['end_time']-p['time']>this.cPauseTime)this.markers.set('pause',p);
	
}
/** 
 * add new Point to track
 * @param {Point} p - point
 * @param noStop if defined Stop market is not set at the end
 */
Track.prototype.addP = function(p,noStop){
	if(this.link_track)this.link_track.addP(new Point(p),noStop);
	p.setParent(this);
	if(this.points.length)p.setPrevPoint(this.points[this.points.length-1]);
	p.index = this.points.length;
    if (this.count == this.points.length) {
		this.points.push(p); //add only if track was loaded
		p.erase(); //remove marker
	}
    this.count++;
	this.updateMarkers(p,noStop);
    if (this.pin.isDef()) 
        this.load_show();
	this.parent.refreshOrder();
//	this.parent.table.refresh(this);
}
/** add new Point from aArray
 * @param {Object} aArray
 * @param {Object} aIndex - start index
 * @return end index (an other id_track)
 */
Track.prototype.addPoints = function(aArray,aIndex){
	if(!aArray||!aArray.length){
		return; //empty array
	}
	ifAdd2LinkTrack=true; //add only for not empty link track
	if (typeof aIndex=='undefined') { //load track so don't copy it to temp track
		aIndex = 0;
		if (this.link_track&&!this.link_track.points.length)ifAdd2LinkTrack=false;
	} 
	if (this.link_track && this.link_track.addPoints&&ifAdd2LinkTrack) { 
		this.link_track.addPoints(aArray, aIndex);
	}
	var id=this.id;
	if(!id)id=aArray[aIndex].id_track;
	if(!this.points.length)this.parent.addSelId(this.id);
	var lastCount=this.points.length;
	var prev=null
	var index=aIndex; //read point from last possition in the array
	if(this.points.length){
		prev=this.points[lastCount-1];
		//find next point
		while(prev.time > aArray[index].time&&index<aArray.length){
			if(aArray[index].id_track!=id)break; //other track
			index++;
		}
		//skip first point if it is the same like last in track
		if (prev.time == aArray[index].time) {
			prev.copyFields(aArray[index]);
			index++;
		}
	}
    for (index; index < aArray.length; index++) {
		if(aArray[index].id_track!=id)break;
		var p =new Point(aArray[index], this, this.points.length,null,prev);
		this.points.push(p);
		prev=p;
	}
	this.count=this.points.length; //+=index-aIndex;
    for (var i = lastCount; i < this.count; i++) {
		this.updateMarkers(this.points[i]);
	}
    if (this.pin.isDef()&&this.points.length) this.load_show();
	this.parent.refreshOrder();
	return index;
}
/**
 * return track and point as post datas ready to send
 */
Track.prototype.post = function() {
	var post="t0="+escape("_(name,time)")			
	   +"&t1="+escape("_('"+this.name+"',FROM_UNIXTIME("+this.time+"))");
	var post=post+'&p0='+escape(this.points[0].getPostProp())+'&p1=';
	for(var i=0;i<this.points.length;i++){
		post=post+escape(this.points[i].getPostVal())+',';
	}
	return post.substr(0,post.length-1);
}
/** send/store temp track to data base */
Track.prototype.save = function(){
	if (this.isSaved) return false;
	if (this.points.length<=0) return false;
    var thisTrack = this;
	//change track name for online user track
	var oldTrackName=thisTrack.name;
	var newTrackName=thisTrack.name;
	if(!thisTrack.id){
		newTrackName+=" "+lSaved;
		thisTrack.name=newTrackName;
	}
	gXMLRequestUI.loadXMLCorr(ESaveTrack,true,this.post(),false,null,function(status,response){
		thisTrack.name=oldTrackName; //change back track name in case of error
		if(status!=200){
			window.alert(lConnErr+' ('+status+')');
			return;
		}
		switch(response.key_value('ret')) {
			case 'NOKlimit':
				window.alert(lSorryTrackTry);
				return;
			case 'OK':
				var id_track=response.key_value('id');
				if(id_track){
					var ifOnlineTrack=!thisTrack.id;
					thisTrack.id=id_track; //change temp id
					thisTrack.id_track=id_track;
					thisTrack.name=newTrackName;
					thisTrack.track_name=newTrackName;
					thisTrack.isSaved=true;
					if(ifOnlineTrack) { //user online track
						thisTrack.parent.delElem(thisTrack.index); 
						//order (first delele than addElem is important
						thisTrack.parent.addElem(thisTrack,id_track); //
						thisTrack.parent.d.users.array[thisTrack.id_user].init(); //new online track and links
					}
					thisTrack.parent.table.refresh();
					window.alert(lTrack+':'+thisTrack.name+' '+lWasSaved);
				}else
					window.alert(lNoIdResponse);
				return;
			default:
				window.alert(lUnknownResp+':'+response);
		}
	})

	return true;
}
Track.prototype.load = function(){
    if (!this.id||!this.isSaved||this.points.length) 
        return;
    var thisTrack = this;
    gXMLRequestUI.loadXMLArray(EPHP_TrackPoints + "&i=" + this.id,true, function(aArray){
		thisTrack.count=0;
        thisTrack.addPoints(aArray['points']);
		thisTrack.parent.table.refresh();
		thisTrack.parent.addSelId(thisTrack.id);
		thisTrack.centerZoom();
    });
}
/** pin replase */
Track.prototype.replace = function(n){
	this.copyFields(n);
	return false; //don't replace
}
/** deselect item,erase points,polylines,initMarkers */
Track.prototype.eraseLocal = function(){
	this.hide();
	this.parent.deleteSelId(this.id);
    for (var i = 0; i < this.points.length; i++) {
        this.points[i].erase();
    }
	this.polyline=null;
    this.points.length = 0;
	this.points.last_length= 0; //used in show()
	this.initMarkers();
}
Track.prototype.erase = function(){
	if (!this.isSaved) {
		this.eraseLocal();
		return;
	}
    gXMLRequestUI.loadXMLArray(EPHP_TrackPoints + "&i=" + this.id + "&c=erase",false, function(aArray){
        if (aArray['track']['status'] == 'ok') {
			this.eraseLocal();
        }
    });
}
var gInnerTR=false; //if TR.innerHTML is read/write

/** TR element.innerHTML=inner for IE in this case innerHTML is readonly so we need walk 
 * around liki this 
 * @param {Object} TR
 * @param {Object} inner
 */
function _innerTR(TR, inner){
	if(gInnerTR){
		TR.innerHTML=inner; //faster for Genco
		return;
	}
	//for IE much slower :-(
	var div = _ce("div");
	div.innerHTML = "<table><tbody><tr>" + inner + "</tr><tbody></table>";
	while(TR.hasChildNodes())TR.removeChild(TR.firstChild);
	var divTR=div.firstChild.firstChild.firstChild;
	while(divTR.hasChildNodes())TR.appendChild(divTR.firstChild)
}

/**
 * create http table in specified div
 * @param {Object} aDivId
 */
function Table(aDivId, aArrayEngine){
    this.divElem = _e(aDivId);
    this.thead = _e('tr_'+aDivId + '_thead');

    this.tbody = _e(aDivId + '_tbody');
    this.arrayEngine = aArrayEngine;
	try {
		this.thead.innerHTML = "";
		gInnerTR = true;
	} 
	catch (e) {
	}
	_innerTR(this.thead,this.arrayEngine.elem.getHeader());
	var s=this;
	var arrayEngine = this.arrayEngine;
	var ref;
	this.tbodyMenu = new PopupMenu('popup', onPopupShow);
	this.theadMenu = new PopupMenu('popup', onPopupShow);
	var tbodyMenu = this.theadMenu

	this.theadMenu.bind(this.thead, 0x1);//only contex menu
	this.tbodyMenu.bind(this.tbody, 0x1);
	this.theadMenu.bind(this.thead.cells[this.thead.cells.length - 1], 0x2);

	this.initMenu = function(){
		if(this.tbodyMenu.items.length>0&&aDivId!='users') return;
		
		this.tbodyMenu.clear();
		this.theadMenu.clear();		
		//item popup menu
		if (this.arrayEngine.ifG) 
			this.tbodyMenu.add(lAutozoom, centerZoom);
		if (aDivId == 'users' && this.arrayEngine.ifG) 
			this.tbodyMenu.add(lPanningOnOff, autoPan);
		if (this.arrayEngine.ifG) 
			this.tbodyMenu.addSeparator();
		if (aDivId == 'tracks') {
			this.tbodyMenu.add(lImportTracks, importTracks);
			this.tbodyMenu.add(lSaveTrack, saveTrack);
			this.tbodyMenu.addSeparator();
		}
		if (aDivId == 'tracks') 
			this.tbodyMenu.add(lResetTrack, resetTrack);
		if (aDivId == 'users') 
			this.tbodyMenu.add(lAddFriend, addFriend);
		this.tbodyMenu.add(lEdit, editItem);
		this.tbodyMenu.add(lDelete, deleteItems);
		if (aDivId == 'locs') {
			this.tbodyMenu.addSeparator();
			this.tbodyMenu.add(lAddNew, addLoc);
		}
		
		if (this.arrayEngine.ifG) {
			this.theadMenu.add(lAutozoom, centerZoom);
			this.theadMenu.addSeparator();
		}
		if (aDivId == 'users') 
			this.theadMenu.add(lAddFriend, addFriend);
		if (aDivId == 'tracks') {
			this.theadMenu.add(lImportTracks, importTracks);
			//		this.theadMenu.add('Save tracks', saveTrack); //we need http request cache
			this.theadMenu.addSeparator();
		}
		if (aDivId == 'tracks') 
			this.theadMenu.add(lResetAllTracks, resetTrack);
		this.theadMenu.add(lDelSelected, deleteItems);
		if (aDivId == 'locs') {
			this.theadMenu.addSeparator();
			this.theadMenu.add(lAddNew, addLoc);
		}
		
	}

/** executed when popup is shown */
	function onPopupShow(target) {
		ref=getTargetId(target); //class static var
		var array = s.arrayEngine.array;
		if (ref.td_h.tagName == 'TH') return; //group operation
		//inactive delete/edit menu item if user not own track/locs or its local temp
		for(;true;){
			if(s.divElem.id !== 'users'){ //tracks,locs
				if(!array[ref.id].id_user)
					break; //unknown user so hide
				if(s.arrayEngine.d['users'].array[array[ref.id].id_user].user_id_privacy>=gPrivacyWithSett)
					return; //user with privacy and settings right so do not hide
				if(array[ref.id].id_user != gUser.id) 
					break; //user is not owner
				else if(!array[ref.id].id) 
					break;
			} else { //users
				if(array[ref.id].id_user_friend&&array[ref.id].id_user_friend != gUser.id) 
					break; //user is not owner
				else if(array[ref.id].id == array[ref.id].id_user_friend)
					break; //friend wait for your invitation
				else if(typeof array[ref.id].id_privacy == "undefined")
					break; //friend wait for your invitation
			}
			return; //do not deactivate any command
		}
		this.itemDeactivate(lDelete);
		this.itemDeactivate(lEdit);
/*		if ((s.divElem.id !== 'users' && 
			((array[ref.id].id_user&& array[ref.id].id_user != gUser.id)|| !array[ref.id].id))
		 || (s.divElem.id === 'users' && 
		    (array[ref.id].id == array[ref.id].id_user_friend
			 ||array[ref.id].id_user!=gUser.id))
		 || gUser.id==-1) //public user
			{
				this.itemDeactivate(lDelete);
				this.itemDeactivate(lEdit);
		}*/
	}
/**
 * add Location  menu task
 * @param {Object} target
 */
	function addLoc(target){
		Loc.addLoc();	
	}
/**
 * add friend  menu task
 * @param {Object} target
 */
	function addFriend(target){

		var friendName='';
		if(ref){
			var array = s.arrayEngine.array;
			if (ref.td_h.tagName == 'TD' && array[ref.id].id) {
				friendName=array[ref.id].name;
			} 
		}
		var options = {bar:lAddNewFriend,
						l1:lFriendName+':' //,
//						v1:friendName,
//						l2:'Friend mask:'
						}
		new Dialog('dialog_addFriend',options,function(ret){
			if(!ret)return true; //Cancel
			gXMLRequestUI.loadXMLCorr(EEditData+'add_users&p1='+ret.v1
					+'&id_privacy='+ret.id_privacy,true,null,false,null,function(status,response){
					if(response.indexOf('Ok')!=0){
						window.alert(lAddFriendFail+'('+status+')');
						_status('Add new friend failed('+status+')','error')
					} else {
						refreshA(); //load new friend
					}
			})
			return true;
		})
	}
/**
 * Import track  menu task
 * @param {Object} target
 */
	function importTracks(target){

		var dialog = new Dialog('import_dialog',null,function(ret){
			if(!ret)return true; //Cancel
			if (ret.box) {
				var doc = new XML(ret.box);
				if(!doc.xmlDoc) {
					dialog.innerHTML('info',lBadFormat+'!!',"color:red;visibility:visible")
					return false;
				} else if (doc.xmlDoc.firstChild.tagName==="parsererror"){
					dialog.innerHTML('info',lXMLParsingErr
						,"color:red;visibility:visible")
					return false;					
				}
				var arrayTrack = doc.getKMLArray();
				s.arrayEngine.add(arrayTrack);
				s.refresh();
				return true;
			} else {
				dialog.innerHTML('info',lFileEmpty+'!!',"color:red;visibility:visible")
				return false;
			}
		})
	}
	/** used in delete Items */
	function checkIfForbidden(i,parms){
		var array = s.arrayEngine.array;
		var fDel=array[i].forbidDel();
		switch(fDel){
		case 0:
			parms.items.push(array[i].id);
			break; //it's ok
		case 1: //track only in local memory
			array[i].reset(); 
			parms.local_counter++;
			break;
		case 2:	//only local delete
			s.arrayEngine.deleteElem(i);
			parms.local_counter++;
			break;
		case 3:  // item is locked
			parms.itemsLocked+=array[i].name+',';
			break;
		default:
			_console('Unknown forbidDel return value:'+fDel);
		}
	}
/**
 * delete Item or Items menu task
 * @param {Object} target
 */
	function deleteItems(target){

//		var local_counter=0;
		if(!ref)return;
		if(!window.confirm(lReallyDelete)) return;
		var array = s.arrayEngine.array;
//		var items = new Array();
		var parms = {
			itemsLocked : '',
			local_counter: 0,
			items: [] 
			}
		if (ref.td_h.tagName == 'TH') { //delete all marked
			for (var i in array) {
				if(i == "indexOf") continue;
				if(!array[i]||!array[i].marked)continue;
				checkIfForbidden(i,parms);
			}
		} else { 
			checkIfForbidden(ref.id,parms);
		}
		if(parms.local_counter>0)s.refresh(); //refresh if deleted locally
		if(parms.itemsLocked) window.alert('Items:'
			+parms.itemsLocked.substr(0,parms.itemsLocked.length-1)+' can not be deleted. '
			+' They are pernamently or temporary locked.');
		if(parms.items.length==0)return;
	    var type='delete_'+s.divElem.id;
		gXMLRequestUI.loadXMLCorr(EEditData+type+'&p1='+parms.items.join(','),true,
			null,false,null,function(status,response){
				if(response.indexOf('Ok')==0){
					for (var i = 0; i < parms.items.length; i++) {
						s.arrayEngine.deleteElem(parms.items[i]);
					}
					s.refresh();
				} else {
					window.alert(lDeleteFails);
					_status(lDelFails,'error')
				}
		})
	}
	function saveTrack(target){

		if(!ref)return;
		var array = s.arrayEngine.array;
		if (ref.td_h.tagName == 'TH') {
			for (var i in array) {
				if(i == "indexOf") continue;
				array[i].save();
			}
		} else { 
			array[ref.id].save();
		}
		
	}
	function resetTrack(target){

		if(!ref)return;
		var array = s.arrayEngine.array;
		if (ref.td_h.tagName == 'TH') {
			for(var i in array) {
				if(i == "indexOf") continue;
				array[i].reset();
			} 
		} else { 
			array[ref.id].reset();
		}
		s.refresh();
	}
/** return item id;td/th and tr element */
	var getTargetId = function(target){
            var td = target;
            while (td != null && td.tagName != "TD" && td.tagName != "TH") 
                td = td.parentNode;
            if (td == null||td.parentNode==null) { //it shouldn't happen
                _console('onClick abnormal event', 'error');
                return;
            }
            var tr = td.parentNode;
            var tab = tr.id.split('_'); //find row id
		return {
			id: tab[2],
			td_h: td,
			tr:tr
		}
	}
    var onclick = function(e){
			_event(e)
			var ref_l=getTargetId(e.target);
			if(!ref_l)return;
			var array = s.arrayEngine.array;
            if (array[ref_l.id].onclick(ref_l.td_h.cellIndex, ref_l.td_h)) { //set active element
            	array[ref_l.id].marked=!array[ref_l.id].marked;
//				arrayEngine.unMark(ref_l.id);
                var className = ref_l.tr.className;
                var ind = className.indexOf("marked");
                if (ind < 0) {
                    ref_l.tr.className = className + ' marked';
                }
                else {
                    ref_l.tr.className = className.substring(0, ind);
                }
            }
			return false;
      }
	_addEventListener(this.tbody,"click",onclick,false);

	; //html table DOM
	function centerZoom(target){

		if(!ref)return;
		var array = s.arrayEngine.array;
		var b = null;
		if (ref.td_h.tagName == 'TH') { //each showing element
			s.arrayEngine.centerZoom();
		} else {
			b=array[ref.id].centerZoom();
		}
	}
	/** map center follow for user/friedn */
	function autoPan(target){

		if(!ref)return;
		var array = s.arrayEngine.array;
		var b = null;
		if (ref.td_h.tagName == 'TD') { 
			array[ref.id].setAutoPanningCenter();
		}
	}
	/** edit Item */
	function editItem(target) {
		if(gDialog)return; //use gDialog to be sure only one dialog is open
		if(!ref)return;
		var array = s.arrayEngine.array;
		var text='';
		var name='';
		var dialogName;
		var options;
		switch(s.divElem.id){
			case 'tracks':
				dialogName="edit_trackloc_dialog";
				options={name:'',id_s_user:0, 'id_privacy':gPrivacyDefault,temp:'',description:'',bar:lBarEditTrack};
				break;
			case 'locs':
				dialogName="edit_trackloc_dialog";
				options={name:'',id_s_user:0, 'id_privacy':gPrivacyDefault,temp:'',description:'',bar:lBarEditLoc};
				break;
			case 'users':
				if (ref.id == gUser.id) {
					window.alert(lUserCouldNotEdit);
					return;
				}
				dialogName="edit_privacy_dialog";
				options={id_privacy:gPrivacyDefault,bar:lBarEditFriend};
				break;
			default: return;
		}
		for(var i in options){
			if(i == "indexOf")continue;
			if(array[ref.id][i])options[i]=array[ref.id][i];
		}
		gDialog = new Dialog(dialogName,options,function(ret,target){
			if(!ret) { //Cancel,Public
				gDialog=null;
				return true;
			}
			//trim all field
			for (var i in ret){
				if(typeof ret[i] =='string')ret[i]=ret[i].trim();	
			}
			gDialog.innerHTML("info",lPleaseWait+' ...',"color:black;visibility:visible");
	    	sendEditItem(s.divElem.id,array[ref.id],ret);
			gDialog=null;
			return true;
	    })
	}
	/* send edit items new values and setup it locally */ 
	function sendEditItem(id,record,newValues){
		if(!newValues) return;
	    var url=EEditData+'edit_'+id+'&p1='+record.id;
	    for(var key in newValues){
			if(typeof newValues[key] =='string') url+='&'+key+'='+encodeURIComponent(newValues[key]);
		}
	    
		gXMLRequestUI.loadXMLCorr(url,true,
			null,false,null,function(status,response){
				if(response.indexOf('Ok')==0){
				    for(var key in newValues){
						if(typeof newValues[key] =='string') record[key]=newValues[key];
					}
					s.refresh();
					_status(lOK); 
				} else {
					window.alert(lEditFail+'('+status+')');
					_status(lEditFail+'('+status+')','error')
				}
		})
		
	}
}

/**
 * add/replace table using array values
 */
Table.prototype.refresh = function(){
	this.initMenu();
    var array = this.arrayEngine.array;
	var ordArray = this.arrayEngine.ordArray;
	// create header if not create yet
    _console("refresh table "+this.arrayEngine.index,'time');

    // refresh and add new items
    var odd = false;
    
    var iRow = 0;
//    for (var i in array) {
    for (var ind=0;ind<ordArray.length;ind++) {
//    for (var ind=ordArray.length-1;ind>=0;ind--) {
		i=ordArray[ind].index;
        if (i == "indexOf"||typeof array[i]=="undefined") 
            continue;
        if (this.arrayEngine.ifHide(i)) 
			continue;
        if (iRow >= this.tbody.rows.length) {
            this.tbody.insertRow(-1);
        }
        var tr = this.tbody.rows[iRow++];
        tr.setAttribute('id', this.Id('tr', i));
        tr.className = (odd ? 'odd' : 'even')+(array[i].marked?' marked':'');
        odd = !odd;
        var iCell = 0;
        _innerTR(tr,array[i].getHTML());
        //            this.popup.bind(tr);
//		this.tbodyMenu.bind(tr.cells[tr.cells.length-1],0x2); //take much time    
    }
	// if more row erase them
	while(iRow<this.tbody.rows.length)
        this.tbody.deleteRow(iRow);
    _console("refresh table "+this.arrayEngine.index,'end_time');
}
/**
 * create aTag id
 * @param {Object} aTag
 * @param {Object} aId
 */
Table.prototype.Id = function(aTag, aId){
    return 'id' + aTag + '_' + this.divElem.id + '_' + aId;
}
/**
 * remove tr node with id=aId
 * @param {Object} aId
 */
Table.prototype.replace = function(aId, e){
    var tr = _e(this.Id('tr', aId))
    if (tr == null) {
		if (e != null) 
			this.table.tbody.appendChild(e);
	}
	else {
		if (e == null) 
			tr.parentNode.removeChild(tr);
		else 
			this.table.tbody.replaceChild(e, tr);
		tr = null;
	}
}
/**
 * remove tr node with id=aId
 * @param {Object} aId
 */
Table.prototype.remove = function(aId){
    var tr = _e(this.Id('tr', aId))
    if (tr == null) 
        return;
    tr.parentNode.removeChild(tr);
	tr = null;
}
Table.prototype.removeAll = function(aId){
    this.table.tbody.removeChild();
}

/**
 * create and show Text Dialog Window
 * @param width,height - text box width ang height;0 default
 * @param options - optional text field ex. {bar:"Help"}
 * @param url - source html url
 * @param f_ok - callback function after OK button
 */
function DialogHTML(width, height,options, url, f_ok){
	this.dialog= new Dialog("textbox",options,f_ok);
	var box=_getElementById(this.dialog.elem,'box');
	if(width)box.style.width=width;
	if(height)box.style.height=height;
	box.innerHTML='Please wait ...';
	box.style.color='green';
	gXMLRequestUI.loadXMLCorr(url
				,true,null,false,null,function(status,response){
				if(status==200){
					box.innerHTML=response;
				} else {
					box.innerHTML='There is no connection ('+status+')';
					box.style.color='red';
				}
		})
}
/**
 * create and show Dialog Window
 * @param elem - pattern element
 * @param f_ok - callback function after button click
 */
var gDialog; //common dialog to prevent multidialog
function Dialog(elem,options,f_ok){
	var me=this;
    if (typeof elem == 'string') {
        elem = document.getElementById(elem);
    }
	if(!elem){
		_console("Dialog bad element/name");
		return;
	}
	this.elem=elem.cloneNode(true);
	var elem=this.elem;
	//hide ads not to fade dialog
	var ads=_e('ads_top_object');
	if(ads)ads.style.visibility="hidden";
	document.body.appendChild(elem);
	elem.style.display='block';
//	_getElementById(elem,"v1").focus();
	this.f_ok=f_ok;
	// setup content
	if(options){
		for(var key in options){
			if(key == "indexOf") continue;
			var ee=_getElementByIdBuf(this.elem,key);
			if(!ee)continue;
			if(ee.tagName==='INPUT') {
				var value=options[key];
				if(ee.type=='checkbox'&&typeof value == "string") {
					ee.checked=(value=="yes"); //yes for true
					ee.value="yes"; //used during value retrieving - convert boolean to yes/no string
				}
				else ee.value=value;
			} else if (ee.tagName==='SELECT'){
				if(ee.id=='id_s_user'){ //first create friends list
					var optn = document.createElement("OPTION");
					optn.text = 'none';
					optn.value = '0';
					ee.options.add(optn);

					gData['users'].addOptions(ee,gData['users'].id_user);
				}
				for(var ii=0;ii<ee.options.length;ii++){
					var opt=ee.options[ii];
					if(opt.value&&opt.value==options[key]){
						opt.selected=true;
						break;
					}
				}
/*				for(var opt in ee.options){ //do not uses in IE and Chrome
					if(ee.options[opt].value&&ee.options[opt].value==options[key]){
						ee.options[opt].selected=true;
						break;
					}
				}*/
			} else {
				ee.innerHTML=options[key];
			}
		}
	}
	var inputs=this.elem.getElementsByTagName('input');
	inputs=_joinNodeList(inputs,this.elem.getElementsByTagName('select'));
	inputs=_joinNodeList(inputs,this.elem.getElementsByTagName('textarea'));
	if(inputs[0])inputs[0].focus();
	var onclick = function(e){
		_event(e);
		if (e.target.id.toLowerCase().indexOf("_hide")>=0) {
			me.hide();
//			document.body.removeChild(elem);
//			elem = null;
		}
		if (e.target.id.toLowerCase() == "cancel") {
			if (f_ok(null, e.target.id, e)) {
				me.hide();
	//			if(elem)document.body.removeChild(elem);
	//			elem = null;
			}
			return;
		}
		var ret=[];
		for (var key in inputs) {
			if(key == "indexOf") continue;
			if (inputs[key].tagName === 'INPUT') {
				switch (inputs[key].type) {
					case 'text':
					case 'password':
						inputs[key].style.border = '';
						ret[inputs[key].id] = inputs[key].value;
						break;
					case 'checkbox':
						if(inputs[key].value=="yes") 
							ret[inputs[key].id] = (inputs[key].checked?"yes":"no");
						else
							ret[inputs[key].id] = inputs[key].checked;
						break;
					case 'ratio':
						ret[inputs[key].id] = inputs[key].checked;
						break;
				}
			}
			else if (inputs[key].tagName === 'TEXTAREA') {
				ret[inputs[key].id]=inputs[key].value;
			} else if (inputs[key].tagName==='SELECT'){
				ret[inputs[key].id]=inputs[key].options[inputs[key].options.selectedIndex].value;
			}
		}
		if (f_ok(ret, e.target.id, e)) {
			me.hide();
//			if(elem)document.body.removeChild(elem);
//			elem = null;
		}
	}
//	_addEventListener(_getElementById(e,'form'),'submit',onclick,false);
	for (var key in inputs){
		if(key == "indexOf") continue;
		if (inputs[key].type) switch(inputs[key].type){
		case 'button':
			_addEventListener(inputs[key],'click',onclick,false);
			break
		case 'submit':
			_addEventListener(inputs[key],'click',onclick,false);
			break
		}
	}
	
	this.hide = function(){
		if(elem)document.body.removeChild(elem);
		elem = null;
		//show ads not to fade dialog
		var ads=_e('ads_top_object');
		if(ads)ads.style.visibility="visible";
	}
}
/** getElementById from dialog */
Dialog.prototype.setValue = function(id,value){
	var e=this.getElementById(id);
	if(e&&e.value)e.value=value;
}
/** getElementById from dialog */
Dialog.prototype.getElementById = function(id){
	return _getElementByIdBuf(this.elem,id);
}
/** setup new innerHTML and stle for element id */
Dialog.prototype.innerHTML = function(id,html,style){
	var e=_getElementByIdBuf(this.elem,id);
	if(!e) return;
	if(html) e.innerHTML=html;
	else return e.innerHTML;
	if(style) e.style.cssText=style;
}
/** focus on id element */
Dialog.prototype.focus = function(id) {
	_getElementByIdBuf(this.elem,id).focus();
}
/** show error message */
Dialog.prototype.showError = function(id){
	if(!id)return;
	var e = _getElementByIdBuf(this.elem,id);
	if(!e) return;
	e.focus();
	e.style.border="2px red solid";
}
/**
 * login procedures
 * @param {Object} p
 */
var _lll = function(){
	return {
		cook: _cook,ccc:_ccc
	}
	function _cook(p){
	
		var b = document.cookie.search("SID=") + 4;
		var value = "";
		if (b < 0) 
			value = "none";
		else {
			var e = document.cookie.indexOf(";", b);
			if (e == -1) 
				e = document.cookie.length;
			value = document.cookie.substring(b, e);
		}
		return c(p, value);
	//}
	}
	function c(s1, s2){
		var c_s1 = "";
		var c_s2 = "";
		if (s1) 
			c_s1 = _ccc(s1);
		if (s2) 
			c_s2 = _ccc(s2);
		return _ccc(c_s1 + c_s2);
	}

	function _ccc(s){
		function Z(n, c){
			return (n << c) | (n >>> (32 - c))
		}
		function Y(q, a, b, x, s, t){
			return X(Z(X(X(a, q), X(x, t)), s), b)
		}
		function A(a, b, c, d, x, s, t){
			return Y((b & c) | ((~ b) & d), a, b, x, s, t)
		}
		function B(a, b, c, d, x, s, t){
			return Y((b & d) | (c & (~ d)), a, b, x, s, t)
		}
		function C(a, b, c, d, x, s, t){
			return Y(b ^ c ^ d, a, b, x, s, t)
		}
		function D(a, b, c, d, x, s, t){
			return Y(c ^ (b | (~ d)), a, b, x, s, t)
		}
		function X(x, y){
			var l = (x & 0xFFFF) + (y & 0xFFFF), m = (x >> 16) + (y >> 16) + (l >> 16);
			return (m << 16) | (l & 0xFFFF)
		}
		function R(s){
			var r = "";
			for (var i = s.length - 1; i > -1; i--) 
				r += s.charAt(i);
			return r;
		}
		var w = s.length * 8, i, hx = "0123456789abcdef", L = (((w + 64) >>> 9) << 4) + 15, x = Array(L + 15);
		for (i = 0; i < x.length; ++i) 
			x[i] = 0;
		for (i = 0; i < w; i += 8) 
			x[i >> 5] |= (s.charCodeAt(i / 8) & 255) << (i % 32);
		x[w >> 5] |= 0x80 << ((w) % 32);
		x[L - 1] = w;
		var a = 1732584193, b = -271733879, c = -1732584194, d = 271733878;
		for (i = 0; i < L; i += 16) {
			var oa = a, ob = b, oc = c, od = d;
			a = A(a, b, c, d, x[i], 7, -680876936);
			d = A(d, a, b, c, x[i + 1], 12, -389564586);
			c = A(c, d, a, b, x[i + 2], 17, 606105819);
			b = A(b, c, d, a, x[i + 3], 22, -1044525330);
			a = A(a, b, c, d, x[i + 4], 7, -176418897);
			d = A(d, a, b, c, x[i + 5], 12, 1200080426);
			c = A(c, d, a, b, x[i + 6], 17, -1473231341);
			b = A(b, c, d, a, x[i + 7], 22, -45705983);
			a = A(a, b, c, d, x[i + 8], 7, 1770035416);
			d = A(d, a, b, c, x[i + 9], 12, -1958414417);
			c = A(c, d, a, b, x[i + 10], 17, -42063);
			b = A(b, c, d, a, x[i + 11], 22, -1990404162);
			a = A(a, b, c, d, x[i + 12], 7, 1804603682);
			d = A(d, a, b, c, x[i + 13], 12, -40341101);
			c = A(c, d, a, b, x[i + 14], 17, -1502002290);
			b = A(b, c, d, a, x[i + 15], 22, 1236535329);
			a = B(a, b, c, d, x[i + 1], 5, -165796510);
			d = B(d, a, b, c, x[i + 6], 9, -1069501632);
			c = B(c, d, a, b, x[i + 11], 14, 643717713);
			b = B(b, c, d, a, x[i], 20, -373897302);
			a = B(a, b, c, d, x[i + 5], 5, -701558691);
			d = B(d, a, b, c, x[i + 10], 9, 38016083);
			c = B(c, d, a, b, x[i + 15], 14, -660478335);
			b = B(b, c, d, a, x[i + 4], 20, -405537848);
			a = B(a, b, c, d, x[i + 9], 5, 568446438);
			d = B(d, a, b, c, x[i + 14], 9, -1019803690);
			c = B(c, d, a, b, x[i + 3], 14, -187363961);
			b = B(b, c, d, a, x[i + 8], 20, 1163531501);
			a = B(a, b, c, d, x[i + 13], 5, -1444681467);
			d = B(d, a, b, c, x[i + 2], 9, -51403784);
			c = B(c, d, a, b, x[i + 7], 14, 1735328473);
			b = B(b, c, d, a, x[i + 12], 20, -1926607734);
			a = C(a, b, c, d, x[i + 5], 4, -378558);
			d = C(d, a, b, c, x[i + 8], 11, -2022574463);
			c = C(c, d, a, b, x[i + 11], 16, 1839030562);
			b = C(b, c, d, a, x[i + 14], 23, -35309556);
			a = C(a, b, c, d, x[i + 1], 4, -1530992060);
			d = C(d, a, b, c, x[i + 4], 11, 1272893353);
			c = C(c, d, a, b, x[i + 7], 16, -155497632);
			b = C(b, c, d, a, x[i + 10], 23, -1094730640);
			a = C(a, b, c, d, x[i + 13], 4, 681279174);
			d = C(d, a, b, c, x[i], 11, -358537222);
			c = C(c, d, a, b, x[i + 3], 16, -722521979);
			b = C(b, c, d, a, x[i + 6], 23, 76029189);
			a = C(a, b, c, d, x[i + 9], 4, -640364487);
			d = C(d, a, b, c, x[i + 12], 11, -421815835);
			c = C(c, d, a, b, x[i + 15], 16, 530742520);
			b = C(b, c, d, a, x[i + 2], 23, -995338651);
			a = D(a, b, c, d, x[i], 6, -198630844);
			d = D(d, a, b, c, x[i + 7], 10, 1126891415);
			c = D(c, d, a, b, x[i + 14], 15, -1416354905);
			b = D(b, c, d, a, x[i + 5], 21, -57434055);
			a = D(a, b, c, d, x[i + 12], 6, 1700485571);
			d = D(d, a, b, c, x[i + 3], 10, -1894986606);
			c = D(c, d, a, b, x[i + 10], 15, -1051523);
			b = D(b, c, d, a, x[i + 1], 21, -2054922799);
			a = D(a, b, c, d, x[i + 8], 6, 1873313359);
			d = D(d, a, b, c, x[i + 15], 10, -30611744);
			c = D(c, d, a, b, x[i + 6], 15, -1560198380);
			b = D(b, c, d, a, x[i + 13], 21, 1309151649);
			a = D(a, b, c, d, x[i + 4], 6, -145523070);
			d = D(d, a, b, c, x[i + 11], 10, -1120210379);
			c = D(c, d, a, b, x[i + 2], 15, 718787259);
			b = D(b, c, d, a, x[i + 9], 21, -343485551);
			a = X(a, oa);
			b = X(b, ob);
			c = X(c, oc);
			d = X(d, od);
		}
		b = [a, b, c, d];
		s = "";
		for (i = 0; i < 16; i++) 
			s += hx.charAt((b[i >> 2] >> ((i % 4) * 8 + 4)) & 0xF) + hx.charAt((b[i >> 2] >> ((i % 4) * 8)) & 0xF);
		return R(s);
	}
}()
