/*
Copyright (c) 2010, Kinetic Data Inc. All rights reserved.
http://www.kineticdata.com
$Rev: 581 $
$Date: 2010-04-22 13:41:52 -0500 (Thu, 22 Apr 2010) $
*/
/**
 * This file is to be used for adding client-side functionality to Kinetic Survey and Kinetic Request.
 * @module kd_util
 *
 */

// setup shortcuts
if (typeof Dom == "undefined") { Dom = YAHOO.util.Dom; }


/**
 * The KD global namespace object
 * @class KD
 * @static
 */
if (typeof KD == "undefined") {
    KD = {};
}
if (typeof KD.utils == "undefined") {
    KD.utils = {};
}

if (! KD.utils.Util){

    /**
UTIL CLASS
     */
    KD.utils.Util= new function(){

	this.labelIDCache = new Array();

	/**
         * Pass in an object to see its properties in an alert.
         * @param obj : Any object
         * @return An alert with the object properties
         */
	this.debugProperties = function(obj){
            if (obj){
                var props="Object Properties Available:\n";
                props += "Name: "+obj.name +"\n";
                props += "ID: "+obj.id +"\n";
                props += "Type: "+obj.type + "\n";
                for (var prop in obj){
                    props += prop + "="+ eval("obj."+prop)+"\n";
                    //props += prop +"\n";
                }
		alert(props);
            }else{
                alert("The object sent was null");
            }
	}

	/*  Get the instance Id of the element from the element ID
         *  @param id : Element Id
         *  @return instanceId
         */
	this.getIDPart = function(id){
            if(!id){
		return;
            }
            if (id.indexOf("QLAYER")!=-1){return id.substring("QLAYER_".length);}
            if (id.indexOf("DYNAMIC_TEXT")!=-1){return id.substring("DYNAMIC_TEXT_".length);}
            if (id.indexOf("IMAGE")!=-1){return id.substring("IMAGE_".length);}
            if (id.indexOf("BUTTON")!=-1){ return id.substring("BUTTON_".length);}
            if (id.indexOf("SRVQSTN")!=-1){return id.substring("SRVQSTN_".length);}
            if (id.indexOf("SECTION")!=-1){return id.substring("SECTION_".length);}
            if (id.indexOf("PAGE")!=-1){return id.substring("PAGE_".length);}
            if (id.indexOf("month_") != -1){ return id.substring("month_".length);}
            if (id.indexOf("day_") != -1){ return id.substring("day_".length);}
            if (id.indexOf("year_") != -1) { return id.substring("year_".length);}
            return id;
	}

	/**
         * Pass in an HTML element or event object to get the related source element.
	 * Useful if a function doesn't know whether an element or event has triggered the function.
         * @param obj : An event object or HTML object
         * @return An element object (if event) or the object itself if something other than an event.
         */
	this.getElementFromObject = function(obj){
            return YAHOO.util.Event.getTarget(obj);
	}

	/**
         * This will pad zeros on the front of an object.
         * @param obj : Typically a number or a string number
	 * @param totalDigits: The total number of digits, including the zeros, needed
         * @return A string with padded zeros.
         */
	this.padZeros = function(obj, totalDigits){
            obj = obj.toString();
            var pd = '';
            if (totalDigits >obj.length){
                for (var i=0; i < (totalDigits-obj.length); i++){
                    pd += '0';
                }
            }
            return pd + obj.toString();
	}
	/*
         */
	this.locateIDByLabel = function(parent, label, fullID) {
            if(parent && label){
                var children = parent.childNodes;
                for (var idx=0; idx < children.length; idx++) {

                    if (children[idx].attributes && children[idx].getAttribute("label")==label) {
                        if(fullID){
                            return children[idx].getAttribute("id");
                        }else {
                            return KD.utils.Util.getIDPart(children[idx].getAttribute("id"));
                        }
                    }

                    if (children[idx].childNodes && children[idx].childNodes.length > 0) {
                        var id = KD.utils.Util.locateIDByLabel(children[idx], label, fullID);
                        if (id != "") return id;
                    }
                }
            }
            return "";
	}

	/*
         */
	this.labelCache = function(label, id){
            KD.utils.Util.label = label;
            KD.utils.Util.id = id;
	}

	/*
         */
	this.setInCache = function(label, id){
            var labelIDCache=KD.utils.Util.labelIDCache;
            labelIDCache[labelIDCache.length] = new KD.utils.Util.labelCache(label, id);
	}

	/*
         */
	this.loadFromCache = function(label){
            var labelIDCache=KD.utils.Util.labelIDCache;
            for (var idx=0; idx < labelIDCache.length; idx++) {
		if (KD.utils.Util.labelIDCache[idx].label == label) {
                    return KD.utils.Util.labelIDCache[idx].id;
		}
            }
            return "";
        }

	this.getPrefixFromType = function(type){
            if(!type){
		return "no type given";
            }
            if (type.indexOf("Question") != -1){
		return "QLAYER_";
            }
            if (type.indexOf("Section") != -1 ){
		return "SECTION_";
            }
            if (type.indexOf("Page") != -1){
		return "PAGE_";
            }
            if (type.indexOf("Dynamic Text") != -1){
		return "DYNAMIC_TEXT_";
            }
            if (type.indexOf("Button") != -1){
		return "BUTTON_";
            }
            if (type.indexOf("Image") != -1){
		return "IMAGE_";
            }

            return "unknown prefix";
	}

	/* Finds the label attribute by walking up from the answer element.  Useful as checkboxes have more parents
         * than other answers
         */
	this.getLabelFromAnswerEl = function(answerEl){
            var thisEl = answerEl;
            var theLabel = "";
            while(thisEl){
                theLabel=thisEl.parentNode.getAttribute("label");
                if(theLabel && theLabel != ""){
                    return theLabel;
                }else{
                    thisEl = thisEl.parentNode;
                }
            }
            return null;
	}

	this.getElementObject = function(label_id, type) {
            if (label_id.length > 28 && (label_id.indexOf("KS") == 0 || label_id.indexOf("AG")==0)) {
                if(!type){
                    type=KD.utils.Util.getPrefixFromType(KD.utils.ClientManager.getElementType(label_id));
                }
                var obj = Dom.get(type+label_id);
            } else {
                var idVal = KD.utils.Util.loadFromCache(label_id);
                if (idVal== "") {
                    if (type) {
                        idVal = KD.utils.Util.locateIDByLabel(document, label_id);
                    } else {
                        // We want the Full ID, not the stripped version
                        idVal = KD.utils.Util.locateIDByLabel(document, label_id, true);
                    }
                    if (idVal){
			KD.utils.Util.setInCache(label_id, idVal);
                    } else {
			return;
                    }
                }
                if (type) {
                    obj = Dom.get(type+idVal);
                } else {
                    obj = Dom.get(idVal);
                }
            }
            return obj;
        }

        /**
         * Get the object that represents the Answer layer (which contains the Input field(s)).
         * @param label_id : Either the Label name (Not the question name) OR the InstanceID for the Question
         * @return The <DIV> element object
         */
	this.getAnswerLayer = function(label_id) {
            var obj = KD.utils.Util.getElementObject(label_id, "QANSWER_");
            if (obj && obj != "") {
            } else {
		alert("function ks_getAnswerLayer - Unable to locate the Object for :"+label_id);
            }
            return obj;
	}


        /**
         * Get the object that represents the Question label layer (DIV).
         * @param label_id : Either the Label name (Not the question name) OR the InstanceID for the Question
         * @return The <DIV> element object
         */
	this.getQuestionLabel = function(label_id) {
            var obj = KD.utils.Util.getElementObject(label_id, "QLABEL_");
            if (obj && obj != "") {
            } else {
		alert("function getQuestionLabel - Unable to locate the Object for :"+label_id);
            }
            return obj;
	}

        /**
         * Get the object that represents the Question layer (Label and Answer layers and Input field(s)).
         * @param label_id : Either the Label name (Not the question name) OR the InstanceID for the Question
         * @return The <DIV> element object
         */
	this.getQuestionLayer = function(label_id) {
            var obj = KD.utils.Util.getElementObject(label_id, "QLAYER_");
            if (obj && obj != "") {
            } else {
		alert("function ks_getQuestionLayer - Unable to locate the Object for :"+label_id);
            }
            return obj;
	}

        /**
         * Get the Input element(s) of the Question (Ie, <input type="text"...)
         * @param label_id : Either the Label name (Not the question name) OR the InstanceID for the Question
         * @return The Input element object or any array (for radio buttons or checkboxes)
         */
	this.getQuestionInput = function(label_id) {
            var obj = KD.utils.Util.getElementObject(label_id, "QANSWER_");
            if (obj){
                var nodes = obj.childNodes;
            } else {
                //Try getting it directly--used for checkboxes
                obj =Dom.get("SRVQSTN_"+label_id);
                if(obj){
                    return obj;
                } else { return;}
            }
            var ret = new Array();
            for (var i=0;i<nodes.length;i++){
                var nodeType=nodes[i].tagName;
                var theNode=nodes[i];
                //Go down a level, probably a checkbox
                if (nodeType && nodeType.toUpperCase() == "DIV"){
                    theNode = nodes[i].firstChild;
                    nodeType=theNode.tagName;
                }
                if (nodeType && (nodeType.toUpperCase()=="INPUT" || nodeType.toUpperCase()=="SELECT" || nodeType.toUpperCase()=="TEXTAREA")){
                    ret.push(theNode);
                }
            }
            if(ret.length == 1){
                return ret[0];
            }
            if (ret && ret != "") {
            } else {
		alert("function getQuestionInput - Unable to locate any input elements for :"+label_id);
            }
            return ret;
	}

        /**
         * Get the DIV object that represents the Dynamic Text element
         * @param label_id : Either the Label name (Not the question name) OR the InstanceID for the Question
         * @return The <DIV> tag that represents the Dynamic Text object
         */
	this.getTextObject = function(label_id) {
            var obj = KD.utils.Util.getElementObject(label_id, "DYNAMIC_TEXT_");
            if (obj && obj != "") {
            } else {
		alert("function ks_getTextObject - Unable to locate the Object for :"+label_id);
            }
            return obj;
	}

        /**
         * Get the DIV object that represents an Image
         * @param label_id : Either the Label name (Not the question name) OR the InstanceID for the Question
         * @return The <DIV> tag that represents an Image
         */
	this.getImageObject = function(label_id) {
            var obj = KD.utils.Util.getElementObject(label_id, "IMAGE_");
            if (obj && obj != "") {
            } else {
		alert("function ks_getImageObject - Unable to locate the Object for :"+label_id);
            }
            return obj;
	}

        /**
         * Get the DIV object that represents a Button
         * @param label_id : Either the Label name OR the InstanceID button
         * @return The button DIV Layer
         */
	this.getButtonObject = function(label_id) {
            var obj = KD.utils.Util.getElementObject(label_id, "BUTTON_");
            if (obj && obj != "") {
            } else {
		alert("function getButtonObject - Unable to locate the Object for :"+id);
            }
            return obj;
	}

	/**
         * Checks to see if an object is an array.  Not completely foolproof as some non-array objects have a length property
         *
         */
	this.isArray = function(obj) {
            if (obj == null) {
                return false;
            }
            return obj.constructor == Array;
	}

	this.trimString = function(sInString){
            sInString = sInString.replace( /^\s+/g, "" );// strip leading
            return sInString.replace( /\s+$/g, "" );// strip trailing
	}

        this.getKeyPressed = function(evt){
            var key = YAHOO.util.Event.getCharCode(evt);
            return key;
	}

	this.getElementType = function(elId) {
            if (elId.indexOf("QLAYER_") != -1 || elId.indexOf("SRVQSTN_") != -1 || elId.indexOf("QLABEL_") != -1 || elId.indexOf("QANSWER_") != -1){
		return "Question";
            }
            if (elId.indexOf("SECTION_") != -1 ){
		return "Section";
            }
            if (elId.indexOf("PAGE_") != -1){
		return "Page";
            }
            if (elId.indexOf("DYNAMIC_TEXT") != -1){
		return "Dynamic Text";
            }
            if (elId.indexOf("BUTTON_") != -1){
		return "Button";
            }
            if (elId.indexOf("IMAGE_") != -1){
		return "Image";
            }

            return "unknown type"

	}

        this.getCheckboxParentId = function(answerEl){
            var thisEl = answerEl;
            var parentId = "";
  	
            // verify this is a checkbox question
            if (thisEl && thisEl.type.toLowerCase() == "checkbox") {
                while (thisEl) {
                    parentId = thisEl.parentNode.getAttribute("id");
                    if (parentId && parentId != "") {
                        parentId = parentId.replace("QANSWER_", "");
                        parentId = parentId.replace("QLABEL_", "");
                        return parentId;
                    } else {
                        thisEl = thisEl.parentNode;
                    }
                }
                return null;
            }
            return null;
        }

	this.setCookie = function (cookieName,cookieValue,time) {
            var today = new Date();
            var expire = new Date();
            expire.setTime(today.getTime() + time);
            document.cookie = cookieName+"="+escape(cookieValue)
                + ";expires="+expire.toGMTString();
	}


	this.getCookieVal = function(offset) {
            var endstr = document.cookie.indexOf (";", offset);
            if (endstr == -1)
                endstr = document.cookie.length;
            return unescape(document.cookie.substring(offset, endstr));
	}

	this.getCookie = function(name){
            var arg = name + "=";
            var alen = arg.length;
            var clen = document.cookie.length;
            var i = 0;
            while (i < clen) {
                var j = i + alen;
                if (document.cookie.substring(i, j) == arg)
                    return KD.utils.Util.getCookieVal (j);
                i = document.cookie.indexOf(" ", i) + 1;
                if (i == 0) break;
            }
            return null;
	}


	this.deleteCookie = function(name,path,domain) {
            if (KD.utils.Util.getCookie(name)) {
                document.cookie = name + "=" +
                    ((path) ? "; path=" + path : "") +
                    ((domain) ? "; domain=" + domain : "") +
                    "; expires=Thu, 01-Jan-70 00:00:01 GMT";
            }
	}

	this.unloadCookie = function() {
            var pageID = Dom.get("pageID").value;
            KD.utils.Util.deleteCookie("KDCACHE-CHECK"+pageID);

            KD.utils.Util.setCookie("KD_PAGE", pageID, 5000);
	}

	this.resetCachePageValues = function() {
            KD.utils.Util.unloadCookie();
	}


	this.checkCachePageLoad = function() {
            window.history.forward(1);
            var fromPage  = KD.utils.Util.getCookie("KD_PAGE");
            if (fromPage && fromPage != "") {
                KD.utils.Util.deleteCookie("KD_PAGE");
                return;
            } else {
                KD.utils.Util.checkCacheLoadStatus();
            }
	}

	this.checkCacheLoadStatus = function() {
            var pageID = Dom.get("pageID").value;
            if (!KD.utils.Util.getCookie("KDCACHE-CHECK"+pageID)) {
                window.location.reload();
            }
	}
	
	
	this.cloneObj = function(obj, deep){
            if(obj == null || typeof(obj) != "object"){
                return obj;
            }
            var newObj = new Object();
            for(var prop in obj){
                try{
                    if(deep){
			newObj[prop] = KD.utils.Util.cloneObj(obj[prop]);
                    }else{
			newObj[prop] = obj[prop];
                    }
                }catch(e){}
            }
            return newObj;
	}

        /**
         * Checks to see if a question expects a date type answer.
         * @param el Element to check.  Should be a question.
         * @return boolean True if question is a date type, otherwise false.
         */
        this.isDate = function(el){
            if (el) {
                var id = KD.utils.Util.getIDPart(el.id);
                if(Dom.get('year_'+id)){
                    return true;
                }
            }
            return false;
        }

        // regular expression to replace special characters 
        this._escapeSpecialChars = function(val) {
            if (!val) {
                return val;
            }
      
            var specialChars = { "'": "%27" };
            var re;
    
            for(key in specialChars) {
                re = new RegExp(key, "g");
                val = val.toString().replace(re, specialChars[key]);
            }
            return val;
        };

        // regular expression to replace special characters 
        this._unescapeSpecialChars = function(val) {
            if (!val) {
                return val;
            }
            
            var specialChars = { "%27": "'" };
            var re;
    
            for(key in specialChars) {
                re = new RegExp(key, "g");
                val = val.toString().replace(re, specialChars[key]);
            }
            return val;
        };
  
        /*
         * function getParameters
         * Returns array of parameters from the URL string
         */
        this.getParameters = function () {
            var parms = [];

            /* Get the URL parameters */
            var sGet = window.location.search;
            if (sGet)
            {
                /* cut off the question mark (?) */
                sGet = sGet.substr(1);

                /* Generate a string array of the name value pairs. */
                var sNVPairs = sGet.split('&');

                /* Extract each name-value pair */
                for (var i = 0; i < sNVPairs.length; i++)
                {
                    /* Assign the pair to the GETDATA array. */
                    var sNV = sNVPairs[i].split('=');
                    parms[sNV[0]] = sNV[1];
                }
            }
            return parms;
        };

        /* 
         * function getParameter
         * Parameter: key - name of the parameter
         * Returns the value of the parameter, or null if it doesn't exist
         */
        this.getParameter = function (key) {
            var retVal = null;
            var parms = this.getParameters();
            if (parms[key]) { retVal = parms[key]; }
            return retVal;
        };


        /*
         * Determine if a checkbox item is checked
         * function isCheckboxItemChecked
         * @param label_id : Either the Label name (Not the question name) OR the InstanceID for the Question
         * @param cb_item : The label of the cb item to test
         * @return true if the item is checked, otherwise false
         */
        this.isCheckboxItemChecked = function (label_id, cb_item) {
            var cb = KD.utils.Util.getQuestionInput(label_id);
            if (cb) {
                for (var i=0; i<cb.length; i++) {
                    if (cb[i].value === cb_item && cb[i].checked) {
                        return true;
                    }
                }
            }
            return false;
        };

	/**
         * Pass in an HTML element or ID to get an array of all elements that
         * belong to the class name.
         * @param className <String> The class name to match against
         * @param tag <String> (optional) The tag name of the elements being collected
         * @param root <String | HTMLElement> (optional) The HTMLElement or an ID to use as the starting point
         * @param apply <Function> (optional) A function to apply to each element when found
         * @returns Array An array of elements that have the given class name
         */
	this.getElementsByClassName = function (className, tag, root, apply){
            return Dom.getElementsByClassName(className, tag, root, apply);
	}

    };
}


/**
 * @class KD.utils.Hash
 * @constructor
 * @description:  A Java-like Hash implementation that will not have collision problems
 *                present using associative arrays/standard Array class and prototype.
 */
KD.utils.Hash=function(){
    this.length = 0;
    this.items = new Array();
    for (var i = 0; i < arguments.length; i += 2) {
        if (typeof(arguments[i + 1]) != 'undefined') {
            this.items[arguments[i]] = arguments[i + 1];
            this.length++;
        }
    }

    this.removeItem = function(in_key)
    {
        var tmp_value;
        if (typeof(this.items[in_key]) != 'undefined') {
            this.length--;
            var tmp_value = this.items[in_key];
            delete this.items[in_key];
        }

        return tmp_value;
    }

    this.getItem = function(in_key) {
        return this.items[in_key];
    }

    this.setItem = function(in_key, in_value) {
        if (typeof(in_value) != 'undefined') {
            if (typeof(this.items[in_key]) == 'undefined') {
                this.length++;
            }

            this.items[in_key] = in_value;
        }

        return in_value;
    }

    this.hasItem = function(in_key)
    {
        return typeof(this.items[in_key]) != 'undefined';
    }
};

/**
 * @class KD.utils.Client
 * @constructor
 * @description:  A singleton that includes the important fields for the form.
 *
 */
KD.utils.Client = function(){
    this.requiredFields = new KD.utils.Hash(); //{[field,message],...}
    this.patternFields = new KD.utils.Hash();  //{[field, pattern, message],...}
    this.eventFields = new KD.utils.Hash(); //{[field, event, action]}
};
