/* Copyright (C) 2007 con terra GmbH (http://www.conterra.de)
 * All rights reserved
 * $Id: ct-util.js,v 1.4 2007/07/18 13:08:38 reiprecht Exp $
 */
/**************************************************/
// File contains base utility functions.
// This is the base file of all other ct-*.js files.
//
// package dependencies: none.
//
/**************************************************/
// Namespaces
/**************************************************/
/* define the conterra namespace */
if (!conterra) {
    var conterra = {};
}
/* define the conterra.util namespace */
if (!conterra.util) {
    conterra.util = {};
}
/* define the conterra.util.dom namespace */
if (!conterra.util.dom) {
    conterra.util.dom = {};
}
/* define the conterra.util.log namespace */
if (!conterra.util.log) {
    conterra.util.log = {};
}
/**************************************************/
// Utility Functions
/**************************************************/
/** An alternative typeOf function,
 returning 'array' for Arrays and 'null' for null and for all others 'typeof value'.
 See http://javascript.crockford.com/remedial.html for details. */
conterra.util.typeOf = function(value) {
    var type = typeof value;
    if (type === 'object') {
        if (value) {
            if (value instanceof Array) {
                type = 'array';
            }
        } else {
            type = 'null';
        }
    }
    return type;
}
/** Function returns true if v is an object containing no enumerable members.
 See http://javascript.crockford.com/remedial.html for details. */
conterra.util.isEmpty = function(o) {
    var i, v;
    if (conterra.util.isObject(o)) {
        for (i in o) {
            v = o[i];
            if (!conterra.util.isUndefined(v) && !conterra.util.isFunction(v)) {
                return false;
            }
        }
    }
    return true;
}
/** returns true if o is undefined. */
conterra.util.isUndefined = function (o) {
    return 'undefined' === conterra.util.typeOf(o);
}
/** returns true if o is a function. */
conterra.util.isFunction = function (o) {
    return 'function' === conterra.util.typeOf(o);
}
/** returns true if o is a number. */
conterra.util.isNumber = function (o) {
    return 'number' === conterra.util.typeOf(o);
}
/** returns true if o is a string. */
conterra.util.isString = function (o) {
    return 'string' === conterra.util.typeOf(o);
}
/** returns true if o is a boolean. */
conterra.util.isBoolean = function (o) {
    return 'boolean' === conterra.util.typeOf(o);
}
/** returns true if o is a object. */
conterra.util.isObject = function (o) {
    return 'object' === conterra.util.typeOf(o);
}
/** returns true if o is a array. */
conterra.util.isArray = function(o) {
    return 'array' === conterra.util.typeOf(o);
}
/** test for null or undefined. Returns true if o is null or undefined otherwise false.*/
conterra.util.isNull = function (o) {
    return 'null' === conterra.util.typeOf(o) || conterra.util.isUndefined(o);
}
/** Thats like isNull, but if argvalue is not null it returns argValue and if it is null it returns the given defaultValue.
 The param evalDefaultValue, says that defaultValue must be evaluated with the 'eval' function bevor it is returned.*/
conterra.util.chkNull = function(argValue, defaultValue, evalDefaultValue) {
    if (!conterra.util.isNull(argValue)) return argValue;
    if (evalDefaultValue) {
        return eval(defaultValue);
    } else {
        return defaultValue;
    }
}
/** This converts an array to a string.
 usage:  var arr = [1,2,3];
 var arrstr = conterra.util.arrToStr(arr);
 -> arrstr has value: '1,2,3';
 var arrstr = conterra.util.arrToStr(arr,':');
 -> arrstr has value: '1:2:3';
 */
conterra.util.arrToStr = function(arr, seperator) {
    seperator = conterra.util.chkNull(seperator, ',');
    return arr.join(seperator);
}
/** This converts an object to a string.
 usage:  var obj = new ... //(a obj)
 var objstr = conterra.util.objToStr(obj,name);
 --> objstr has value: '{ name  property:value, ...}'
 */
conterra.util.objToStr = function(obj, name, functions) {
    var res = '{';
    if (!conterra.util.isNull(name)) {
        res.concat(name).concat(' ');
    }
    var props = conterra.util.propsToStr(obj, functions, ',', ':');
    return res.concat(props).concat('}');
}
/** This converts the properties of an object to a string.
 usage:  var obj = new ... //(a obj)
 var propstr = conterra.util.propsToStr(obj,false,',',':');
 --> propstr has value: 'property:value, ...'
 params:
 obj         : the object
 functions   : flag if function shall be displayed
 propsep     : the property seperator
 vsep        : the name-value seperator
 */
conterra.util.propsToStr = function(obj, functions, propsep, vsep) {
    var res = '';
    for (var prop in obj) {
        var value = obj[prop];
        if (conterra.util.isFunction(value) && !functions) continue;
        res = res.concat(prop)
                .concat(vsep)
                .concat(conterra.util.isFunction(value) ? 'function' : String(value))
                .concat(propsep);
    }
    return res.substring(0, res.length - 1);
}
/** appends px to a number or string.
 usage:
 var str = conterra.util.toPx(10);
 //after that str has value '10px'
 */
conterra.util.toPx = function(pixval) {
    var result = String(pixval);
    return result.lastIndexOf('px') > -1 ? result : result + 'px';
}
/** Get browser window dimensions.
 It returns an object with properties 'width' and 'height'.
 */
conterra.util.winSize = function() {
    return {'width': conterra.util.winWidth(), 'height': conterra.util.winHeight()};
}

/** Gets the window width */
conterra.util.winWidth = function() {
    var mapFrameWidth = window.innerWidth;
    if (mapFrameWidth == null) {
        if (document.documentElement && document.documentElement.clientWidth) {
            mapFrameWidth = document.documentElement.clientWidth
        } else {
            mapFrameWidth = document.body.clientWidth;
        }
    }
    return mapFrameWidth;
}

/** Gets the window height */
conterra.util.winHeight = function () {
    var mapFrameHeight = window.innerHeight;
    if (mapFrameHeight == null) {
        if (document.documentElement && document.documentElement.clientHeight) {
            mapFrameHeight = document.documentElement.clientHeight;
        } else {
            mapFrameHeight = document.body.clientHeight;
        }
    }
    return mapFrameHeight;
}

/** This chains a list of functions and creates a new function, wich when called will execute all other functions.
 The execution chain is interruppted if one of the functions returns false.
 usage sample:
 var newfunc = conterra.util.chain(func1,func2,func3);
 newfunc(param); -> executes func1(param) and func2(param) and func3(param).
 */
conterra.util.chain = function () {
    var functions = [];
    // check if all arguments are functions.
    for (var i = 0,l = arguments.length; i < l; ++i) {
        if (conterra.util.isFunction(arguments[i])) functions.push(arguments[i]);
    }
    // return a new "chaining" function.
    return function () {
        var res = true;
        for (var i = 0,l = functions.length; i < l && (!conterra.util.isBoolean(res) || res );
             ++i) {
            res = functions[i].apply(this, arguments);
        }
        return res;
    };
}
/**************************************************/
// Logging Functions
/**************************************************/
// global flags for enable/disable logging levels.
conterra.util.log._isDebug = true;
conterra.util.log._isInfo = true;
conterra.util.log._isError = true;

// a nothing/empty logger
conterra.util.log._emptyLog = function() {
};
// an alert logger
conterra.util.log._alert = function (msg) {
    alert(msg);
}
// an textbox logger
conterra.util.log._textbox = function(msg, clear) {
    var elem = conterra.util.dom.element('DebugOutput');
    if (!elem) {
        elem = conterra.util.dom.element('MapDebugBox');
    }
    if (elem) {
        if (clear) {
            elem.value = '';
        } else {
            elem.value = elem.value.concat(msg).concat('\n');
        }
    }
}
// check if _textbox logger can log
conterra.util.log._isTextbox = function() {
    return conterra.util.dom.element('DebugOutput') != null
            || conterra.util.dom.element('MapDebugBox') != null;
}
// clear the logging in the textbox
conterra.util.log.clearOutput = function() {
    conterra.util.log._textbox(null, true);
}
// redirect the esri output in the textbox
conterra.util.log.enableEsri = function(enable) {
    if (enable) {
        var elem = conterra.util.dom.element('DebugOutput');
        if (elem) {
            elem.id = 'MapDebugBox';
        }
    } else {
        var elem = conterra.util.dom.element('MapDebugBox');
        if (elem) {
            elem.id = 'DebugOutput';
        }
    }
}
// gets the available logger textbox or alert
conterra.util.log._getLogger = function() {
    if (conterra.util.log._isTextbox()) {
        return conterra.util.log._textbox;
    }
    return conterra.util.log._alert;
}

/** test for enabled log levels */
conterra.util.log.isDebug = function () {
    return  conterra.util.log._DLog() != conterra.util.log._emptyLog;
}
conterra.util.log.isInfo = function () {
    return  conterra.util.log._ILog() != conterra.util.log._emptyLog;
}
conterra.util.log.isError = function () {
    return  conterra.util.log._ELog() != conterra.util.log._emptyLog;
}

/** log debug statement */
conterra.util.log.debug = function (msg, obj) {
    if (conterra.util.log.isDebug()) {
        conterra.util.log._DLog()('DEBUG: ' + (conterra.util.isNull(obj) ? msg :
                                               msg + String(obj)));
    }
}
/** log info statement */
conterra.util.log.info = function (msg, obj) {
    if (conterra.util.log.isInfo()) {
        conterra.util.log._ILog()('INFO: ' + (conterra.util.isNull(obj) ? msg : msg + String(obj)));
    }
}
/** log error statement */
conterra.util.log.error = function (msg, obj) {
    if (conterra.util.log.isError()) {
        conterra.util.log._ELog()('ERROR: ' + (conterra.util.isNull(obj) ? msg :
                                               msg + String(obj)));
    }
}
/* The debug logger, logs never in alert! */
conterra.util.log._DLog = function() {
    if (conterra.util.log._isDebug) {
        var logger = conterra.util.log._getLogger();
        //if (logger != conterra.util.log._alert) return logger;
        return logger;
    }
    return conterra.util.log._emptyLog;
}
/* The info logger, logs never in alert! */
conterra.util.log._ILog = function() {
    if (conterra.util.log._isInfo) {
        var logger = conterra.util.log._getLogger();
        //if (logger != conterra.util.log._alert) return logger;
        return logger;
    }
    return conterra.util.log._emptyLog;
}
/* The error logger */
conterra.util.log._ELog = function() {
    if (conterra.util.log._isError) {
        var logger = conterra.util.log._getLogger();
        return logger;
    }
    return conterra.util.log._emptyLog;
}

/**************************************************/
// Dom Functions/Helper
/**************************************************/
// some small methods for usage in the dom tree.
/** returns true if the node is an element. */
conterra.util.dom.isElement = function (node) {
    return node.nodeType == 1;
}
/** returns true if the node is an attribute. */
conterra.util.dom.isAttribute = function (node) {
    return node.nodeType == 2;
}
/** returns true if the node is text. */
conterra.util.dom.isText = function (node) {
    return node.nodeType == 3;
}
/** returns true if the node is CDATA. */
conterra.util.dom.isCDATA = function (node) {
    return node.nodeType == 4;
}
/** return true if name is the name of the node.*/
conterra.util.dom.hasName = function (node, name) {
    return node.nodeName.toLowerCase() == name.toLowerCase();
}
/* Recursive traverse of the child nodes of node and call visitfunc(childnode) for all nodes in the subtree.
   The visitfunc must return true or the traversing is stopped.
*/
conterra.util.dom.visitpreorder = function(node, visitfunc) {
    if (conterra.util.isNull(node)) {
        conterra.util.log.error('conterra.util.dom.visitpreorder - parameter node must not null');
    }
    var nodes = node.childNodes;
    if (conterra.util.isNull(nodes) || nodes.length == 0) return true;
    for (var i = 0,l = nodes.length; i < l; ++i) {
        var child = nodes[i];
        if (!visitfunc(child) || !conterra.util.dom.visitpreorder(child, visitfunc)) {
            return false;
        }
    }
    return true;
}
/** Searches the element for the id
 and displays an error if the element ist not found.
 returns the element or null.
 if the function is called with an element instead of an id, the element will be returned.
 usage:
 var elem = conterra.util.dom.element('aId'); //alerts nothing but returns the element if present.
 or  var elem = conterra.util.dom.element('aId',true); //logs a default error message if element not found.
 or  var elem = conterra.util.dom.element('aId',true,'Error element not found.'); //logs the given error message if element not found.
 */
conterra.util.dom.element = function (id, showmsg, errormsg) {
    return conterra.util.dom.elementFromDoc(document,id, showmsg,errormsg);
}
/** Searches the element for the id in the given document
 and displays an error if the element ist not found.
 returns the element or null.
 if the function is called with an element instead of an id, the element will be returned.
 This method is needed for cross frame programming.
 usage:
 var elem = conterra.util.dom.elementFromDoc(document,'aId'); //alerts nothing but returns the element if present.
 or  var elem = conterra.util.dom.elementFromDoc(document,'aId',true); //logs a default error message if element not found.
 or  var elem = conterra.util.dom.elementFromDoc(document,'aId',true,'Error element not found.'); //logs the given error message if element not found.
 */
conterra.util.dom.elementFromDoc = function (doc,id, showmsg, errormsg) {
    if ('object' == typeof id) {
        return id;
    } // if id is an element return it.
    var elem = doc.getElementById(id);
    if (!elem) {
        if (showmsg) {
            conterra.util.log.error((errormsg ? errormsg :
                                     'Element for id \'' + id + '\' not found.'));
        }
        return null;
    }
    return elem;
}
/** Set the visibility of an element and also his display style.
 If no setter value is given the method returns the visibility of the element.
 usage:
 conterra.util.dom.visible(aElement,true); //shows an element (display:block)
 conterra.util.dom.visible(aElement,true,'inline');//shows an element (display:inline)
 conterra.util.dom.visible(aElement,false); //hides an element (display:none)
 var isvisible = conterra.util.dom.visible(aElement); //reads the visibility state (true|false).
 */
conterra.util.dom.visible = function(elem, visible, display) {
    elem = conterra.util.dom.element(elem, true);
    if (conterra.util.isUndefined(visible)) {
        return elem.style.visibility != 'hidden' && elem.style.display != 'none';
    }
    elem.style.visibility = visible ? 'visible' : 'hidden';
    elem.style.display = visible ? display ? display : 'block' : 'none';
}
/** Positions an element (changes attributes, top,left,right,bottom,width or height.
 usage:
 conterra.util.dom.posElement(elem, {top:1px, left:2px, width:200px });
 */
conterra.util.dom.posElement = function(elem, pos) {
    with (conterra.util) {
        elem = dom.element(elem, true);
        if (!isNull(pos.top)) {
            elem.style.top = toPx(pos.top);
        }
        if (!isNull(pos.left)) {
            elem.style.left = toPx(pos.left);
        }
        if (!isNull(pos.right)) {
            elem.style.right = toPx(pos.right);
        }
        if (!isNull(pos.bottom)) {
            elem.style.bottom = toPx(pos.bottom);
        }
        if (!isNull(pos.width)) {
            elem.style.width = toPx(pos.width);
        }
        if (!isNull(pos.height)) {
            elem.style.height = toPx(pos.height);
        }
    }
}
/** Function connects a text input field with a button
 and fires the button if 'enter' is pressed.
 usage:
 <input type="text" onkeydown="conterra.util.dom.invokeButton('abutton',event);"/>
 <input type="submit" id="abutton"/>
 */
conterra.util.dom.invokeButton = function (elem, evt) {
    var lBtn = conterra.util.dom.element(elem);
    if (evt.keyCode == 13 || evt.which == 13) {
        evt.returnValue = false;
        evt.cancel = true;
        lBtn.click();
    }
}
/** Function creates a hidden field in a form */
conterra.util.dom.ensureHidden = function(form, name, value) {
    if (!form.elements[name]) {
        // field not present -> create it.
        var input = document.createElement("input");
        input.type = "hidden";
        input.name = name;
        if (value) input.value = value;
        form.appendChild(input);
    } else {
        // field is present -> only change the value.
        if (value) {
            form.elements[name].value = value;
        }
    }
}
/** appends a text node to a parent node*/
conterra.util.dom.appendTextNode = function(parent, text) {
    parent = conterra.util.dom.element(parent, true);
    parent.appendChild(document.createTextNode(text));
}
/**************************************************/
// Event-Handling Functions/Helper
/**************************************************/
// Event related methods
/** registers an eventlistener to an element. */
conterra.util.registerEventListener = function(elem, evt, func) {
    elem = conterra.util.dom.element(elem, true);
    if (elem.addEventListener) {//w3c
        elem.addEventListener(evt, func, false);
    } else if (elem.attachEvent) {//microsoft
        elem.attachEvent('on' + evt, func);
    } else {//alternativ
        elem['on' + evt] = conterra.util.chain(elem['on' + evt], func);
    }
}
/** Adds a new onload function to the window.onload eventhandlers. */
conterra.util.addOnLoadEvent = function(win,func) {
    // if function only called with on parameter, than is the parameter the function.
    if (arguments.length == 1){
        conterra.util.registerEventListener(window, 'load', arguments[0]);
    }else{
        conterra.util.registerEventListener(arguments[0], 'load', arguments[1]);
    }
}
/** Creates a new Event-Function.
 Thats a helper to enable the definition of event handlers within objects.
 usage:
 1. implement a object and a eventhandler method. e.g: var obj = { 'evtmethod': function (e){ alert(e); }; }
 2. register evthandler:
 var htmlelement = conterra.util.dom.element('aId');
 htmlelement.onmouseclick = conterra.util.evtFunc(obj,obj.evtmethod);
 -> if the htmlelement is clicked a alert box with the event is shown.
 */
conterra.util.evtFunc = function (obj, method) {
    var _obj = obj, _method = method;
    return function (e) {
        var evt = e ? e : event;
        return _method.call(_obj, evt);
    };
}
/** Creates a new Delegate-Function.
 Thats like evtFunc but used to implement the delegate pattern also for other usages than events.*/
conterra.util.delegateFunc = function (obj, method) {
    var _obj = obj,_method = method;
    return function () {
        return _method.apply(_obj, arguments);
    }
}
conterra.util.isInRange = function (val, lowerLmt, upperLmt) {
	if (val > lowerLmt && val < upperLmt) {
		return true;
	}
	return false;
}

conterra.util.formatNumber = function (number) {
	if (!Number(number)) {
		return " ";
	}
	var ret = String(number);
	if (ret.indexOf(".") > 0) {
		var lDezStr = ret.substring(ret.indexOf(".") + 1);
		if (lDezStr.length == 1) {
			ret = ret.concat("0");
		}
		ret = ret.replace(/\./g, ",");
	}
	else if (ret.length > 0) {
		ret = ret.concat(",00");
	}
	else {
		ret = " ";
	}
	return ret;
}

conterra.util.isIntNumber = function (string) {
	var len = string.length;
    for (var i = 0; i <= len; i++) {
        var car = string.charAt(i);
        if (isNaN(car)) {
			return false;
		}
    }
    return true;
}

conterra.util.writeInnerHtml = function (targetId, tagname, content) {
	var target_internal;
	if(document.layers) {
		target_internal = document.layers[targetId];
		target_internal.document.open();
		target_internal.document.write(content);
		target_internal.document.close();
	} 
	else if(document.all)  {
    	target_internal = document.all.tags(tagname)[targetId];
       	target_internal.innerHTML = content;
	} 
	else if(document.getElementById) {
 		target_internal = document.getElementById(targetId);
 		target_internal.innerHTML = content;
	}
}

// Example:
// writeCookie("myCookie", "my name", 24);
// Stores the string "my name" in the cookie "myCookie" which expires after 24 hours.

function writeCookie(name, value, hours){
          var expire = "";
          if(hours != null)  {
            expire = new Date((new Date()).getTime() + hours * 3600000);
            expire = "; expires=" + expire.toGMTString();
          }
          document.cookie = name + "=" + escape(value) + expire;
}

// Example:

// alert( readCookie("myCookie") );

function readCookie(name)
{
  var cookieValue = "";
  var search = name + "=";
  if(document.cookie.length > 0){
    offset = document.cookie.indexOf(search);
    if (offset != -1){
      offset += search.length;
      end = document.cookie.indexOf(";", offset);
      if (end == -1) end = document.cookie.length;
      cookieValue = unescape(document.cookie.substring(offset, end))
    }
  }
  return cookieValue;
}

