/**
 * lsjs mini library,
 * Создание неймспейсов, транспортные функции, наследование в JS, сокращения часто используемых фрагментов кода.
 *  
 * @author asuslx
*/
var _validateNS = function(NSstr) {
    NSa = NSstr.split(".");
    var cNSref = null;
    var sNS = '';
    for(var i = 0; i < NSa.length; i++) {
       if(i == 0) 
           sNS = NSa[i];
       else 
           sNS += '.'+NSa[i];
       if(eval("typeof("+sNS+")") == 'undefined') eval(sNS+" = new Object();");    
    }
};

_validateNS("lsjs");
_validateNS("LSJS");

/**
 * @function lsjs.system.validateNamespace
 * 
 * Создает пространство имен, если оно не существует.
 * 
 * @param NSSrting - имя пространства имен (ns1.ns2.ns3...) 
 * 
 * @return void
 *
 * @deprecated use lsjs.namespace("...");
*/

lsjs.system = function () {	
	
	var traced = new Array();
	
	var _traceObject = function(d, l){		
	
		if (l == null){ 
        	l = 1; 
        	traced[traced.length] = new Array();
        }
        var s = '';

        traced[traced.length] = d;
        
        if (typeof(d) == "object") {
            s += typeof(d) + " {<br/>";
            for (var k in d) {
                for (var i=0; i<l; i++) s += "&nbsp;&nbsp;&nbsp;&nbsp;";
                try {
                	
                	if(lsjs.inArray(d[k], traced)) return;                                	
                  	s += k+":&nbsp;&nbsp;&nbsp;&nbsp;" + _traceObject(d[k],l+1);                      
                
                	
                } catch (e){
                	s += "<br/>" + "Error:" + e.message;
                }
                
            }
            for (var i=0; i<l-1; i++) s += "&nbsp;&nbsp;&nbsp;&nbsp;";
            s += "}<br/>"
        } else {
            s += "" + d + "<br/>";
        }

        return s;
    }; 
		
	return {
		traceObject : _traceObject,
		validateNamespace : _validateNS		
	};
	
}();

lsjs.namespace = _validateNS;

lsjs.var_dump = function (x, max, sep, l) {

	l = l || 0;
	max = max || 10;
	sep = sep || '   ';

	if (l > max) {
		return "[...]";
	}
    if(l == 0)
        lsjs.var_dump_traced = new Array();

	var
		i,
		r = '',
		t = typeof x,
		tab = '';

	if (x === null) {
		r += "(null)";
	} else if (t == 'object') {

        if(lsjs.inArray(x, lsjs.var_dump_traced)) return '<cicle ref>';
        lsjs.var_dump_traced[lsjs.var_dump_traced.length] = x;

		l++;

		for (i = 0; i < l; i++) {
			tab += sep;
		}



		if (x && x.length) {
			t = 'array';
		}

		r += '(' + t + ") :\n";

		for (i in x) {
			try {
				r += tab + '[' + i + '] : ' + lsjs.var_dump(x[i], max, sep, (l + 1)) + '\n';
			} catch(e) {
				r += tab + '[' + i + '] : (ERROR) ' + e + "\n";
			}
		}

	} else {
        if( t == 'function') {

            r += '(' + t + ') ' + '{...}' + "";

        } else {

            if (t == 'string') {
			    if (x == '') {
				    x = '(empty)';
			    }
            }
            r += '(' + t + ') ' + x + "";
        }

	}
	return r;
};



/**
 * function lsjs.transport.asyncRequest
 * 
 * Создает асинхронный запрос к серверу. Используется пул XMLHttpRequest.
 * 
 * @param url - URL
 * @param method - метод запроса (GET или POST)
 * @param data - POST данные
 * 
 * @param callback - функция при изменении статуса запроса :
 * 	  void callback(status, request object, user parameter)
 * 	     status - статус запроса, строка. значения:
 * 	 	    send - отправлен, ожидание,
 *          complete - завершен,
 *          error - проихошла ошибка.
 *               	
 * @param param - параметр пользователя, значение будет передаваться в callback. используется замыкание.   
*/

lsjs.transport = function () {

   var _requestsPool = _requestsPool || new Array();
   var _requestsPoolSize = 40;

   var _createRequestObj = function() {
	   var xhr = false;
	   try {
		   xhr = new ActiveXObject("Msxml2.XMLHTTP");
	   } 
	   catch (e) {
		   try {
			   xhr = new ActiveXObject("Microsoft.XMLHTTP");
		   } 
		   catch (E) {
			   xhr = false;
		   }
	   } 
	   if (!xhr && typeof XMLHttpRequest!='undefined') {
		   try {
			   xhr = new XMLHttpRequest();
		   } 
		   catch (e) {
			   xhr = false;
		   }
	   }
	   if(!xhr && window.createRequest) {
		   try {
			   xhr = window.createRequest();
		   } 
		   catch (e) {
			   xhr = false;
		   }
	   }
	   return xhr;
   };

   var _createCallback = function(xhr,callback,param) {
	 
	   var f = function() {
		   if(xhr.req.readyState == 4) {
			   
			   if(xhr.req.status == 200)
				   callback('complete',xhr.req,param);                       
			   else
				   callback('error',xhr.req,param);                              

			   xhr.working = 0;

		   }
	   };
	   return f;
   };

   var _getXhrFromPool = function() {

	   for(var i=0; i < _requestsPool.length; i++) {
		   if (_requestsPool[i].working == 0) return _requestsPool[i];
	   }
	   
	   if(_requestsPool.length < _requestsPoolSize) {
		   var newRequest = _createRequestObj();
		   var req = {working:0,req:newRequest};
		   _requestsPool.push(req);
		   return req;
	   } else throw 'Pool of requests is full. Try later.';

   };

   var _asyncRequest = function(url,method,data,callback,param) {
	   
	   var xhr = _getXhrFromPool();
	   xhr.working = 1;
	   callback('send',xhr.req,param);                              
	   xhr.req.open(method,url,true);
	   xhr.req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
	   xhr.req.onreadystatechange = _createCallback(xhr,callback,param);
	   xhr.req.send(data);
   };

   var _arrayToHTTPQuery = function( arr ) {
	   var data = '';
	   for(var name in arr) {
			data += (data?'&':'') + name + '=' + arr[name];
	   }
	   return data;
   };

   var _abort = function() {
        for(var i = 0; i < _requestsPool.length; i++) {
            if(_requestsPool[i].working) {
                try{
                    _requestsPool[i].req.abort();    
                } catch(e) {}
            }

        }
   };
   
   return {
	   asyncRequest : _asyncRequest,
       abort : _abort,
	   arrayToHTTPQuery : _arrayToHTTPQuery
   };
   
}();

/**
 * URL Factory
 * Useable for url parsing and making. 
 *  
 * @returns URL object
 */
lsjs.URL = function() {
	
	var __url = new Object();
		
	__url.protocol = 'http';	
	__url.host = false;
	__url.port = false;
	__url.path = false;
	__url.params = false;
    __url.arrSeparator = ',';
	
	__url.fromString = function (url) {
		
		var _a = lsjs.createElement('a', {href: url});
		
		this.protocol = _a.protocol.replace(':','');
		this.host = _a.hostname;        
		this.path = _a.pathname;
		this.port = _a.port;
		this.params = (function(){			
			var ret = {}, seg = _a.search.replace(/^\?/,'').split('&'),	len = seg.length, i = 0, s;			
			for (;i<len;i++) {			
				if (!seg[i]) continue; 			
				s = seg[i].split('=');			
				ret[s[0]] = s[1];
			}		
			return ret;
		}());
		
		return this;
	};
	
	var __joinParams = function (params) {
		var result = '';
		for (var name in params) {
            var value;

  		    if(lsjs.isArray(params[name]))
		    	value = params[name].join(__url.arrSeparator);
		    else if(lsjs.isObject(params[name]))
		    	value = lsjs.objJoin(params[name], __url.arrSeparator);
		    else
		    	value = params[name];

			result += (result?'&':'') + name  + '=' + value;
		}
		return result;
	};
	
	__url.toString = function () {
        var url = (this.host?(this.protocol+'://'+this.host+((this.port && this.port != 80 && this.port != '0' && this.port != 0)?(':'+this.port):'')):'') +
                ((!lsjs.empty(this.path) && this.path.charAt(0)=='/')?'':'/') + this.path +
                ((!lsjs.empty(this.params))?('?'+__joinParams(this.params)):'');
		return url;
	};
		
	return __url;
};

lsjs.isIE = function () {
	return !-[1,]; 
};

lsjs.defined = function (variable) {
	return (typeof(variable) != 'undefined');
};

lsjs.isObject = function (variable) {
	return (typeof(variable) == 'object');
};

lsjs.isArray = function (variable) {
	return lsjs.isObject(variable) && variable instanceof Array;
};

lsjs.isString = function (variable) {
	return (typeof(variable) == 'string');
};

lsjs.notNull = function (variable) {
	return (lsjs.defined(variable) && variable !== null);
};

lsjs.empty = function (mixed_var) {
    
    var key;    
    if (mixed_var === "" ||
        mixed_var === 0 ||
        mixed_var === "0" ||
        mixed_var === null ||  mixed_var === false || mixed_var === [] ||
        typeof mixed_var === 'undefined'
    ){
        return true;
    } 
    if (typeof mixed_var == 'object') {
        for (key in mixed_var) {
            return false;
        }        return true;
    }
 
    return false;
}

lsjs.dieMessage = function (exception, message) {
	if(lsjs.defined(message))
		alert(message);
	throw exception;	
};

lsjs.inArray = function (what, where) {
    for(var i=0; i<where.length; i++)
        if(what == where[i]) 
            return true;
    return false;
};

lsjs.inObject = function (what, where) {
    for(var i in where)
        if(what == where[i]) 
            return true;
    return false;
};

lsjs.arrayRemove = function (arrayName, arrayElement)
{
   for(var i=0; i < arrayName.length;i++ )
   { 
      if(arrayName[i]==arrayElement)
          arrayName.splice(i,1); 
   } 
};

lsjs.arrayMerge = function (array1, array2) {
	
   for(var i = 0; i < array2.length; i++ ) {
	   array1[array1.length] = array2[i];
   }
   
   return array1;
};

lsjs.objJoin = function (obj, sep) {
	var res = '';
	for (var i in obj) {
		res += (res?sep:'') +  obj[i];
	}
	return res;
};

/**
 *  lsjs.range
 *
 *     example 1: range ( 0, 12 );
 *     returns 1: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
 *     example 2: range( 0, 100, 10 );
 *     returns 2: [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]    // *     example 3: range( 'a', 'i' );
 *     returns 3: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
 *     example 4: range( 'c', 'a' );
 *     returns 4: ['c', 'b', 'a']
 */
lsjs.range = function(low, high, step) {

    var matrix = [];    var inival, endval, plus;
    var walker = step || 1;
    var chars = false;

    if (!isNaN(low) && !isNaN(high)) {        inival = low;
        endval = high;
    } else if (isNaN(low) && isNaN(high)) {
        chars = true;
        inival = low.charCodeAt(0);        endval = high.charCodeAt(0);
    } else {
        inival = (isNaN(low) ? 0 : low);
        endval = (isNaN(high) ? 0 : high);
    }
    plus = ((inival > endval) ? false : true);
    if (plus) {
        while (inival <= endval) {
            matrix.push(((chars) ? String.fromCharCode(inival) : inival));            inival += walker;
        }
    } else {
        while (inival >= endval) {
            matrix.push(((chars) ? String.fromCharCode(inival) : inival));            inival -= walker;
        }
    }

    return matrix;}

/**
 * @deprecated use lsjs.dom.create(); 
 */
lsjs.createElement = function(tagName, attrs, parentNode) { 
	
	var element = document.createElement(tagName);
	if(lsjs.isArray(attrs) || lsjs.isObject(attrs)) {		
		for (var attrName in attrs) {
			switch(attrName) {
			
				case 'id' :
				case 'Id' :
				case 'ID' :						
					element.id = attrs[attrName];
				break;	
				
				case 'value' :
				case 'Value' :
					element.value = attrs[attrName];
				break;
			
				case 'type' :
				case 'Type'	:
					element.type = attrs[attrName];
				break;	
				
				case 'name' :
				case 'Name' :
					element.name = attrs[attrName];
				break;
				
				case 'click' :
				case 'onclick' :
				case 'onClick' :	
					element.onclick = attrs[attrName];
			    break;
			    
				case 'change' :
				case 'onchange' :
				case 'onChange' :	
					element.onchange = attrs[attrName];
			    break;
			    
			    
				case 'checked' :
				case 'Checked' :
					element.checked = attrs[attrName];
				break;	
                
                case 'selected' :
				case 'sel' :                  
					element.selected = attrs[attrName]?'selected':false;
				break;
                										
				case 'class' :
				case 'className' :
					element.className = attrs[attrName];
				break;
				
				case 'html':
				case 'innerHTML':
					if(tagName == 'option' && lsjs.isIE())
						element.text = attrs[attrName];
					else	
						element.innerHTML = attrs[attrName];
				break;	
			
				case 'text' :
					if(lsjs.isIE())
						element.text = attrs[attrName];
					else
						element.innerHTML = attrs[attrName];
				break;	
				default : 
					element.setAttribute(attrName, attrs[attrName]);
			}
		}	
	}
	
	if(lsjs.notNull(parentNode)) {
		if((tagName == 'option') && lsjs.isIE()) {			
			parentNode.add(element);
		} else {			
			parentNode.appendChild(element);
		}	
	};	
	
	return element;
	
};

/**
 * converts associative array to url string
 * 
 * @deprecated - use lsjs.URL
 */
lsjs.assocToURL = function (assoc, prefix) {
	var result = '';
	if(lsjs.notNull(prefix))
		result = prefix;
	
	for (var i in assoc) {
		result += (result.indexOf('?')>=0?'&':'?') + i  + '=' + assoc[i];
	}
	return result;
};

/**
 * 
 * @deprecated use lsjs.dom.hide()
 */
lsjs.hideElement = function(element) {
	element.style.display = 'none';
};

/**
 * 
 * @deprecated use lsjs.dom.show()
 */
lsjs.showElement = function(element) {
	element.style.display = '';
};

/**
 * 
 * @deprecated use lsjs.dom.hidden()
 */
lsjs.elementHidden = function(element) {
	return (element.style.display == 'none');
};


lsjs.disableControls = function(parentElement, disabled) {
	
	var inputs = parentElement.getElementsByTagName('input');
	for(var i = 0; i < inputs.length; i++) {
		inputs[i].disabled = disabled;
	}
	var inputs = parentElement.getElementsByTagName('button');
	for(var i = 0; i < inputs.length; i++) {
		inputs[i].disabled = disabled;
	}
	var inputs = parentElement.getElementsByTagName('select');
	for(var i = 0; i < inputs.length; i++) {
		inputs[i].disabled = disabled;
	}
	var inputs = parentElement.getElementsByTagName('textarea');
	for(var i = 0; i < inputs.length; i++) {
		inputs[i].disabled = disabled;
	}

 // ....	
};

lsjs.timer = function() {

	var timers = new Array();
	
	var _start = function(name) {
		timers[name] = (new Date).getTime();
	};
	
	var _end = function(name) {
		if(timers[name])
			return (new Date).getTime() - timers[name];
		else return false;
	};
	
	return {
		start :	_start,
		end :	_end	
	};
	
}();

lsjs.messageBox = function(caption, html, width, height, left, top) {

	if(!lsjs.defined(width)) width = 500;
	if(!lsjs.defined(height)) height = 200;

    var wwidth=(window.innerWidth)?window.innerWidth:
    ((document.all)?document.body.offsetWidth:null);
    var wheight=(window.innerHeight)?window.innerHeight:
    ((document.all)?document.body.offsetHeight:null);

    if(!lsjs.defined(left)) left = wwidth / 2 - width / 2;
    if(!lsjs.defined(top)) top = wheight / 2 - height / 2;

    var win = lsjs.dom.create('div',{
        id: 'lsjs_message_window',
        html : '<table width="100%" style="margin-bottom: 5px;"><tbody><tr><td width="99%" style="background-color:#555555; color: white; padding-left:10px;">'+caption+'</td><td onclick="document.body.removeChild(this.parentNode.parentNode.parentNode.parentNode);" style="background-color: white; color: black; cursor:pointer;"><b>&nbsp;X&nbsp;</b></td></tr></tbody></table>\
        <div style="width:100%; overflow:auto; height: 95%">'+html+'</div>'
    });
    win.style.position = 'absolute';
    win.style.backgroundColor = '#EEEEEE';
    win.style.border = '1px solid black';
    win.style.width = width + 'px';
    win.style.height = height  + 'px';
    win.style.top = top  + 'px';
    win.style.left = left  + 'px';

    document.body.appendChild(win);

};

/**
 * @deprecated use lsjs.css.exists
 */
lsjs.checkForClass = function(element, nameOfClass) {
    if (typeof element == 'string') { element = document.getElementById(element); }

    if (element.className == '') {
        return false;
    } else {
        return new RegExp('\\b' + nameOfClass + '\\b').test(element.className);
    }
};

/**
 * @deprecated use lsjs.css.exists
 */
lsjs.classExists = function(element, nameOfClass) {
    if (typeof element == 'string') { element = document.getElementById(element); }

    if (element.className == '') {
        return false;
    } else {
        return new RegExp('\\b' + nameOfClass + '\\b').test(element.className);
    }
};


/**
 * @deprecated use lsjs.css.add
 */
lsjs.addClass = function(element, nameOfClass) {
    if (typeof element == 'string') { element = document.getElementById(element); }

    if (!lsjs.checkForClass(element, nameOfClass)) {
        element.className += (element.className ? ' ' : '') + nameOfClass;
        return true;
    } else {
        return false;
    }
};


/**
 * @deprecated use lsjs.css.remove
 */
lsjs.removeClass = function(element, nameOfClass) {
    if (typeof element == 'string') { element = document.getElementById(element); }

    if (lsjs.checkForClass(element, nameOfClass)) {
        element.className = element.className.replace(
            (element.className.indexOf(' ' + nameOfClass) >= 0 ? ' ' + nameOfClass : nameOfClass),
            '');
        return true;
    } else {
        return false;
    }
};


/**
 * @deprecated use lsjs.css.replace
 */
lsjs.replaceClass = function(element, class1, class2) {
    if (typeof element == 'string') { element = document.getElementById(element); }

    if (FM.checkForClass(element, class1)) {
        FM.removeClass(element, class1);
        FM.addClass(element, class2);
        return true;
    } else {
        return false;
    }
};


/**
 * @deprecated use lsjs.css.toggle
 */
lsjs.toggleClass = function(element, nameOfClass) {
    if (typeof element == 'string') { element = document.getElementById(element); }

    if (lsjs.checkForClass(element, nameOfClass)) {
    	lsjs.removeClass(element, nameOfClass);
    } else {
    	lsjs.addClass(element, nameOfClass);
    }

    return true;
};

