// ************************************* EDITOR OBJECT ****************************************************
// This is the base class for editor bones.  An editor represents a "mini-window" that allows users to edit
// some other component on the page.  Examples: object browser, sort dialog.
// ********************************************************************************************************
//<SCRIPT>

// properties
mstrEditorImplScript = true;
mstrEditorImpl.INPUT_TYPE_PRINTER = '101';
mstrEditorImpl.INPUT_TYPE_FILENAME = '102';
mstrEditorImpl.INPUT_TYPE_EMAILADDR = '103';
mstrEditorImpl.INPUT_TYPE_FOLDERPATH = '104';
mstrEditorImpl.INPUT_TYPE_DATE = '201';
mstrEditorImpl.prototype = new mstrDialogImpl();
mstrEditorImpl.prototype.doSlide = false;
mstrEditorImpl.prototype.maskFor = null;
mstrEditorImpl.prototype.maskArea = null;
mstrEditorImpl.prototype.navigateOnSubmit = null;
mstrEditorImpl.prototype.okBtnId = null;
mstrEditorImpl.prototype.type = microstrategy.OBJTYPE_EDITOR;
mstrEditorImpl.prototype.CHECKBOX_UNSELECTED = "checkOff";
mstrEditorImpl.prototype.CHECKBOX_SELECTED = "checkOn";
mstrEditorImpl.prototype.CHECKBOX_DISABLED = "checkDisabled";
mstrEditorImpl.prototype.CHECKBOX_PARTIALLY_SELECTED = "checkUndefined";
var currentModalEditor = [];


// events
mstrEditorImpl.prototype.onload = function() {
    //@class=mstrEditorImpl;@method=onload;
    try {
        this.initEditor();
   }
    catch(err) {
        microstrategy.errors.log(err);
        return false;
    }
}

mstrEditorImpl.prototype.onpostload = function() {
    //@class=mstrEditorImpl;@method=onpostload;
    try {
        mstrBoneImpl.prototype.onpostload.call(this);
        this.initResize();
        if (microstrategy.eventManager) {
            microstrategy.eventManager.notifyOrphanBones("onstatechange");
        }
    }
    catch(err) {
        microstrategy.errors.log(err);
        return false;
    }
}

mstrEditorImpl.prototype.onsubmit = function(e) {
    if (!e) e = window.event;

	 if(this.validateInputs()){
   	 	if (this.navigateOnSubmit) {
        	var oForm = this.elem.getElementsByTagName("form")[0];
	        if (oForm) {
    	        oForm.target = "";
        	}
    	}
    }else{
        return false;
    }
}

mstrEditorImpl.prototype.onunload = function() {
    //@class=mstrEditorImpl;@method=onunload;
    try {
    	//If we still have the elem property on the bone, we should call hide to complete the clean up. 
    	if (this.elem) {
    		this.hide();
    	}
    	
        mstrDialogImpl.prototype.onunload.call(this);
        this.hideCurtain();
    }
    catch(err) {
        microstrategy.errors.log(err);
        return false;
    }
}


mstrEditorImpl.prototype.onnotifydragend = function() {
    //@class=mstrEditorImpl;@method=onnotifydragend;
    try {
        if (this.mask && this.mask.toggle) this.mask.toggle(false);
    }
    catch(err) {
        microstrategy.errors.log(err);
        return false;
    }
}

mstrEditorImpl.prototype.initEditor = function() {
    //@class=mstrEditorImpl;@method=initEditor;
    try{
        this.initDialog();

        //If this is a "dialog":
        if (this.elem.getAttribute(mstrHTMLAttributes.ATTR_DIALOG) == 'true') {
            if (this.elem.getAttribute(mstrHTMLAttributes.ATTR_HIDDEN) != 'true') {
                this.show();
            } else {
                this.hideCurtain();
            }
        }

        this.initErrorMessage();
    }
    catch(err) {
        microstrategy.errors.log(err);
        return false;
    }
}

mstrEditorImpl.prototype.disableIFrame = function(button) {
    //@class=mstrEditorImpl;@method=disableIFrame;
    try {
        if (!button) return false;

        var oForm = findTargetTag(button, 'FORM');
        if (oForm) {
            if (oForm.target == "frameManager") {
                var oInputs = oForm.getElementsByTagName("INPUT");
                for (var j=0; j < oInputs.length; j++) {
                    if (oInputs[j].name == "iframe") {
                        oInputs[j].value = "false";
                        break;
                    }
                }
                oForm.target = "";
            }
        }

        return true;
    }
    catch(err) {
        microstrategy.errors.log(err);
        return false;
    }
}


mstrEditorImpl.prototype.show = function() {
    //@class=mstrEditorImpl;@method=show;
    //Usage: called as this.show();
    //Purpose: graphically, if the dialog doesn't already has a position, it centers it within the browser:
    if (this.elem) {
        var modalMode = this.elem.getAttribute(mstrHTMLAttributes.ATTR_MODAL) == 'true';

        var zIndex = this.computeZIndex();
        if (modalMode) this.showCurtain(zIndex);

        this.elem.style.display = "block";

        // Use current coordinates if available
        var x = parseInt(this.elem.style.left);
        var y = parseInt(this.elem.style.top);

        if ((isNaN(parseInt(x))) || (x <= 0) || (isNaN(parseInt(y))) || (y <= 0)) {
            this.elem.style.display = "block";
        }

        if ((isNaN(parseInt(x))) || (x <= 0)) x = ((getClientWidth() - getObjWidth(this.elem)) / 2 + getDocumentScrollLeft());
        if ((isNaN(parseInt(y))) || (y <= 0)) y = (((getClientHeight() - getObjHeight(this.elem)) / 2) + getDocumentScrollTop());

        //If the browser window is made very small we still want the user to be able to click on the title bar at all times
        x = Math.max(x, 0);
        y = Math.max(y, 0);

        this.elem.style.zIndex = zIndex + 1;
        this.moveTo(x, y);

        //if we have editors on top of this editor
        var currentPosition = this.getLayer(this.id);
        if(currentPosition + 1 < currentModalEditor.length) {
            for(var i = currentPosition + 1; i < currentModalEditor.length; i++) {
               if(getObj(currentModalEditor[i]) != null) {
                togglePulldowns(getObj(currentModalEditor[i]), false);
                enablePulldowns(getObj(currentModalEditor[i]), true);
            }
        }
        } else {
            enablePulldowns(this.elem, true);
        }


        if (!this.doSlide) displayObj(this.elem);
    }

    return;
}

mstrEditorImpl.prototype.slideOut = function() {
    //@class=mstrEditorImpl;@method=slideOut;
    try {
        if (!this.doSlide) return;
        this.doSlide = false;
        var o = this.elem;
        
        this.oHeight = getObjHeight(o);
        this.oWidth = getObjWidth(o);
        this.clipTop = this.oHeight - 1;
        this.clipLeft = this.oWidth - 1;
        this.oTop = getObjTop(o);
        this.oLeft = getObjLeft(o);
        this.top = this.oTop - this.oHeight;
        this.left = this.oLeft - this.oWidth;
        o.style.clip = "rect(" + this.clipTop + "px, " + this.oWidth + "px, " + this.oHeight + "px, " + this.clipLeft + "px)";
        o.style.top = this.top + "px";
        o.style.left = this.left + "px";
        displayObj(o);
        
        this.timer = window.setInterval("microstrategy.bone('" + this.id + "').slide();", 1);
    }
    catch(err) {
        microstrategy.errors.log(err);
        return false;
    }    
}

mstrEditorImpl.prototype.slide = function() {
    //@class=mstrEditorImpl;@method=slide;
    try {
        var inc = 40;
        var o = this.elem;
        if (this.clipTop < 1 && this.clipLeft  < 1) {
            window.clearInterval(this.timer);
            o.style.clip = "rect(auto, auto, auto, auto)";
            o.style.top = this.oTop + "px";
            o.style.left = this.oLeft + "px";
            return;
        }
        var h = Math.max(this.clipTop -= inc, 0);
        var w = Math.max(this.clipLeft -= inc, 0);
        
        if (this.top < this.oTop) {
            this.top = Math.min(this.oTop, this.top += inc);
            o.style.top = this.top + "px";
        }
        if (this.left < this.oLeft) {
            this.left = Math.min(this.oLeft, this.left += inc);
            o.style.left = this.left + "px";
        }
        o.style.clip = "rect(" + this.clipTop + "px, " + this.oWidth + "px, " + this.oHeight + "px, " + this.clipLeft + "px)";
    }
    catch(err) {
        microstrategy.errors.log(err);
        return false;
    }    
}


mstrEditorImpl.prototype.showCurtain = function(zindex) {
	//@class=mstrEditorImpl;@method=showCurtain;
    var name = this.id + "_bg";
    var elCurtain = document.getElementById(name);

    if (!elCurtain) {
    	elCurtain = document.createElement("div");
    	elCurtain.id = name;
    	elCurtain.className = 'mstrCurtain';
        document.body.appendChild(elCurtain);
    }

    if (elCurtain) {
    	elCurtain.style.zIndex = zindex;
    	elCurtain.style.height = mstr.utils.BoxModel.getBrowserWindowHeight(document)  + 'px';
    	elCurtain.style.width  = mstr.utils.BoxModel.getBrowserWindowWidth(document) + 'px';
    	elCurtain.style.left = getDocumentScrollLeft() + 'px';
    	elCurtain.style.top = getDocumentScrollTop() + 'px';
    	elCurtain.style.visibility = "visible";
        enablePulldowns(document.body, false);
    }
}

mstrEditorImpl.prototype.hideCurtain = function() {
	//@class=mstrEditorImpl;@method=hideCurtain;
	var elCurtain = document.getElementById(this.id + "_bg");
    if (elCurtain && elCurtain.style.visibility == 'visible') {
    	elCurtain.style.visibility = 'hidden';
    	//must shrink curtain size so it does not affect browser scrolling
    	elCurtain.style.height = '1px';
    	elCurtain.style.width  = '1px';
    	enablePulldowns(document.body, true);
    }
}

mstrEditorImpl.prototype.hide = function() {
    //@class=mstrEditorImpl;@method=hide;
    //Usage: called as this.hide().
    //Purpose: graphically, it sets style display property to 'none' in order to dissapear it in browser.
    try {
        //hide:
        this.elem.style.display = 'none';
        this.elem.setAttribute("hidden", "1");

        //Hide curtains displayed behind editor if it's modal.
        this.hideCurtain();

        this.removeLayer();

        togglePulldowns(this.elem, true);

        return true;
    }
    catch(err) {
        microstrategy.errors.log(err);
        return false;
    }
}

mstrEditorImpl.prototype.close = function() {
    //@class=mstrEditorImpl;@method=close;
    //Usage: called as this.close.
    //Purpose: to hide graphically current Editor and to append in UpdateManager query
    //         an event for closing this Editor to be processed by the PageEvent event handler
    //         Use with caution as this method doesn't unregiser the bone from the page.
    try {
        //hide editor.
        this.hide();

        if (this.id) {
            var updateManager = microstrategy.updateManager;

            if (updateManager) {
                var actionCollection = [];
                actionCollection.push(updateManager.createActionObject(this,
                                                    mstrUpdateManager.SHOW_BEAN,
                                                    microstrategy.servletName + "." + microstrategy.pageName,
                                                    ['5017','5018'],
                                                    ['false', this.getBeanName()], [] ));


                microstrategy.updateManager.add(actionCollection, true);
            }

        }

        return true;
    }
    catch(err) {
        microstrategy.errors.log(err);
        return false;
    }
}

mstrEditorImpl.prototype.closeEditor = function(submit, applyCookie) {
    //@class=mstrEditorImpl;@method=closeEditor;
    //Usage: called as this.closeEditor.
    //Purpose: to hide graphically current Editor and to append in UpdateManager query
    //         an event for closing this Editor to be processed by the PageEvent event handler,
    //         and to unregister the bone from the bones collection.
    try {
        //hide editor.
        this.close();
        
        //Do we have the beanName? Then it must be an editor bone. Save the cookie in the event that the user navigates away from the
        //page and we have unsent events in the update manager.
        var bn = this.beanName 
        if (bn && applyCookie) {
        	//By default all cookie values are based upon the name of the bean.
        	microstrategy.updateCookieSetting(bn, '0');
        }

        this.unregister();

        if (microstrategy.eventManager) {
            microstrategy.eventManager.notifyOrphanBones("onstatechange");
            if (!this.isDraggable) {
                microstrategy.eventManager.ondialogresize();
            }
        }


        if (microstrategy.updateManager) {

            if ( submit==true ) {
               microstrategy.updateManager.flushAndSubmitChanges();
            }  else if (submit != false && microstrategy.mstrwid!='') {
            	//submit is not defined, and the request is from portal.
            microstrategy.updateManager.flushAndSubmitChanges();
        } else {
            microstrategy.eventManager.notifyOrphanBones('oneditorclose', this.id);
        }

	}

        return true;

    }
    catch(err) {
        microstrategy.errors.log(err);
        return false;
    }
}

mstrEditorImpl.prototype.unregister = function() {
    //@class=mstrEditorImpl;@method=unregister;
    try {
        //delete dom contents
        if (this.elem) {
            this.elem.innerHTML = "";
        }
        microstrategy.unRegisterBone(this.id);
    }
    catch(err) {
        microstrategy.errors.log(err);
        return false;
    }
}

mstrEditorImpl.prototype.getBeanName = function() {
    //@class=mstrEditorImpl;@method=getBeanName;
    //Usage: called as this.getBeanName()
    //Purpose: returns the name of the corresponding ben associated with this bone.
    try {

        var sEditorName = "";
        if (this.beanName) {
            sEditorName = this.beanName;

        } else {

	        sEditorName = this.id;

        //If it includes '_', get the bean's name only:
        if (sEditorName.indexOf('_') > 0) sEditorName = sEditorName.substr(0, sEditorName.indexOf('_'));
        }

        return sEditorName;
    }
    catch(err) {
        microstrategy.errors.log(err);
        return false;
    }
}

mstrEditorImpl.prototype.getLayer = function() {
    var __result = -1;

    if (this.isLoaded) {
        for(var i = currentModalEditor.length - 1; i > -1; i--) {
            if(currentModalEditor[i] == this.elem.getAttribute("name")) {
                __result = i;
                break;
            }
        }
    }

    return __result;
}

mstrEditorImpl.prototype.removeLayer = function() {
    //@class=mstrEditorImpl;@method=removeLayer;
    try {
        //Remove this from currentModalEditor list:
        for(var i = 0; i < currentModalEditor.length; i++) {
            if(currentModalEditor[i] == this.elem.getAttribute("name")) {
                currentModalEditor.length = i;
                break;
            }
        }
    }
    catch(err) {
        microstrategy.errors.log(err);
        return false;
    }
}

mstrEditorImpl.prototype.addLayer = function() {
    //@class=mstrEditorImpl;@method=addLayer;
    try {
        var __result = currentModalEditor.length;
        currentModalEditor[__result] = this.elem.getAttribute("name");  
        return __result; 
    }
    catch(err) {
        microstrategy.errors.log(err);
        return false;
    }
}    
  
mstrEditorImpl.prototype.validateField= function(field, message, enforceValidation) {
    //@class=mstrEditorImpl;@method=validateInputs;
    //Usage: called as this.validateInputs(this).
    //Purpose: to validate all inputs in the editor.
    if(typeof(enforceValidation) == 'undefined') { enforceValidation = true;}
	
	return mstrEditorImpl.validateField(field, message, enforceValidation);
}   

mstrEditorImpl.validateField= function(field, message, enforceValidation) {
    try {
       
	    if(typeof(enforceValidation) == 'undefined') { enforceValidation = true;}
        if (field == null || !(field.type == "text" || field.type == "password")) {
            return message;
        }
        
        //Issue 384109: The validator picks up the incremental fetch input field and tries to validate it. Check if the 
        //input fields have a fld attribute.
        //Issue 386106: We also need to check the attribute filed id
        if (!field.getAttribute(mstrHTMLAttributes.ATTR_FLD) && !field.getAttribute(mstrHTMLAttributes.ATTR_FLDID)) {
        	return message;
        }
        
        //do not validate disabled input
        if (field.disabled) {
            return message;
        }
        
        var decimalSep = mstr.Settings.Locale.DECIMALSEP;
        var intRegExp  = /(^-?\d\d*$)/;
        var numRegExp = new RegExp("(^-?\\d\\d*\\" + decimalSep + "\\d*$)|(^-?\\d\\d*\\" + decimalSep + "?\\d*[eE](\\+|-)?\\d+$)|(^-?\\d\\d*$)|(^-?\\" + decimalSep + "\\d\\d*$)");

        var interimMessage = "";
        var value = field.value;
        var fieldId = field.getAttribute(mstrHTMLAttributes.ATTR_FLDID);
        var fieldName = null;
        if (typeof(fieldId) != 'undefined' && fieldId != null) {
            fieldName = microstrategy.descriptors.getDescriptor(fieldId);
        }
        if (fieldName == null) fieldName = field.getAttribute(mstrHTMLAttributes.ATTR_FLD);
        var zeroValid = field.getAttribute(mstrHTMLAttributes.ATTR_ZERO);
        var bCheck = true;
        var base = 10;
        //Dependency
        if (field.getAttribute(microstrategy.HTMLATTR_CMD_VALUE) != null || enforceValidation) { //validate only values that changed
            if (field.getAttribute(mstrHTMLAttributes.ATTR_DPN)) {
                var oDepRadio = getObj(field.getAttribute(mstrHTMLAttributes.ATTR_DPN));
                if (oDepRadio) {
                    bCheck = (oDepRadio.length) ? oDepRadio[field.getAttribute(mstrHTMLAttributes.ATTR_DPNND)].checked : oDepRadio.checked;
                }
            }
            //Data type validation
            if (bCheck) {
                // no limits have been set - just check it's an integer unless zero length is enabled.
                if (field.getAttribute(mstrHTMLAttributes.ATTR_DTY) == "1") { //Integer
                   if ((!zeroValid && value.length == 0) ||
                    (value.length > 0 && intRegExp.test(value) == false) ||
                    (value.length > 0 && (parseInt(value,base) != parseFloat(value)))) {
                    message += microstrategy.descriptors.getDescriptor("3037") + " " + fieldName + "<br />";  //Descriptor: Please enter an integer in the following field:
                    }
                } else if (field.getAttribute(mstrHTMLAttributes.ATTR_DTY) == "2") { //float
                    if ((!zeroValid && value.length == 0) || (value.length > 0 && !numRegExp.test(value))) {
                        message += microstrategy.descriptors.getDescriptor("3038")+ " " + fieldName + "<br />"; //Descriptor: Please enter a number in the following field:
                    }
                } else if (field.getAttribute(mstrHTMLAttributes.ATTR_DTY) == "201") { //date
                    if (value.length > 0 && !mstrEditorImpl.getTime(field)) {
                        message += microstrategy.descriptors.getDescriptor("7745")+ " " + fieldName + "<br />"; //Descriptor: Please enter a date in the following field:
                    }
                }
                else if (field.getAttribute(mstrHTMLAttributes.ATTR_DTY) && field.parentNode.style.visibility!='hidden' &&field.parentNode.style.display!="none") { //validate the values where inputType is given
	        		switch(field.getAttribute(mstrHTMLAttributes.ATTR_DTY)){
                        case mstrEditorImpl.INPUT_TYPE_PRINTER:      
                            var regExp1 = new RegExp("^[^$%:*?\"<>|/\\\\]*$");  //single printer name pattern     
                            var regExp2 = new RegExp("^((/|\\\\\\\\)[^$%:*?\"<>|/\\\\]+)((/|\\\\)[^$%:*?\"<>|/\\\\]+)*(/|\\\\){0,1}$"); //printer path pattern, including windows and unix
                            if(value.length<0 || (!regExp1.test(value) && !regExp2.test(value))){
                                message += microstrategy.descriptors.getDescriptor("5583").replace(/###/, "'" + fieldName + "'") + "<br />";
                            }
                            break;
    	    			case mstrEditorImpl.INPUT_TYPE_FOLDERPATH:
                            var regExpWin = new RegExp("^([a-zA-Z]:|\\\\\\\\[^:*?\"<>|/\\\\]+|[^:*?\"<>|/\\\\]*)(\\\\[^:*?\"<>|/\\\\]+)*(\\\\){0,1}$");//Windows sub-Folder path name pattern
                            var regExpUnix = new RegExp("^(/){0,1}([^:*?\"<>|/\\\\]+/)*([^:*?\"<>|/\\\\]+){0,1}$"); //Unix, Linux sub-Folder path name pattern
                            //TQMS 343499: add sub-folder pattern
							if(value.length<0 || ( !regExpWin.test(value) && !regExpUnix.test(value) )){
								message += microstrategy.descriptors.getDescriptor("5583").replace(/###/, "'" + fieldName + "'") + "<br />";
							}
        					break;
	        			case mstrEditorImpl.INPUT_TYPE_FILENAME:
    	    				var regExp  = new RegExp("^[^:*?\"<>|/\\\\]+$"); //single file name pattern
							if(value.length<=0 || !regExp.test(value)){
								message += microstrategy.descriptors.getDescriptor("5583").replace(/###/, "'" + fieldName + "':<br />");
								message += microstrategy.descriptors.getDescriptor("5808").replace(/##/, "<b>:*?\"<>|/\\</b> ") + "<br />";  // "## are not allowed in a file name.";
							}
        					break;
                        case mstrEditorImpl.INPUT_TYPE_EMAILADDR:
                        	//TQMS #422994, allow & included in the email address
                            var regExp  = new RegExp("^([&a-zA-Z0-9_.-])+@(([&a-zA-Z0-9-])+[.])+([a-zA-Z0-9]{2,4})+$");  //the regular expression may need to be improved in the future
                            if(value.length<=0 || !regExp.test(value)){
                                message += microstrategy.descriptors.getDescriptor("5583").replace(/###/, "'" + fieldName + "'") + "<br />";
                            }
                            break;
        			}
                }
                //Regex Validation
                if(field.getAttribute(mstrHTMLAttributes.ATTR_REGEX)){
                    var regexValidation = new RegExp(field.getAttribute(mstrHTMLAttributes.ATTR_REGEX));
                    if(regexValidation.test(value)){
                        message += field.getAttribute(mstrHTMLAttributes.ATTR_REGEX_MSG);
                    }
                }
                //Min and Max validation
                var minValue = null,
                    maxValue = null,
                	minmaxError = false;
                if (field.getAttribute(mstrHTMLAttributes.ATTR_MIN) != null && field.getAttribute(mstrHTMLAttributes.ATTR_MIN).length > 0) {
                    minValue = parseFloat(eval(field.getAttribute(mstrHTMLAttributes.ATTR_MIN)));
                    if (parseFloat(mstr.utils.LocaleParser.convertToBrowserNumber(value)) < minValue) {
                        if ((field.getAttribute(mstrHTMLAttributes.ATTR_ERR) != null) && (field.getAttribute(mstrHTMLAttributes.ATTR_ERR).length > 0)) {
                            message += field.getAttribute(mstrHTMLAttributes.ATTR_ERR) + "<br />";
                        } else {
                        	minmaxError = true;
                        }
                    }
                }
                if (field.getAttribute(mstrHTMLAttributes.ATTR_MAX) != null && field.getAttribute(mstrHTMLAttributes.ATTR_MAX).length > 0) {
                    maxValue = parseFloat(eval(field.getAttribute(mstrHTMLAttributes.ATTR_MAX)));
                    if (parseFloat(mstr.utils.LocaleParser.convertToBrowserNumber(value)) > maxValue) {
                        if ((field.getAttribute(mstrHTMLAttributes.ATTR_ERR) != null) && (field.getAttribute(mstrHTMLAttributes.ATTR_ERR).length > 0)) {
                            message += field.getAttribute(mstrHTMLAttributes.ATTR_ERR) + "<br />";
                        } else {
                        	minmaxError = true;
                        }
                    }
                }
                
                if (minmaxError) {
                	if (minValue !== null && maxValue !== null) {
	                    message += ((microstrategy.descriptors.getDescriptor("6117").replace(/####/, maxValue)).replace(/###/, minValue)).replace(/##/, fieldName) + "<br />";  //Descriptor: Please enter a number between ### and #### in the following field: ##
	                } else if (minValue !== null) {
	                    message += (microstrategy.descriptors.getDescriptor("3039").replace(/###/, minValue)).replace(/##/, fieldName) + "<br />";  //Descriptor: Please enter a number greater than ### in the following field: ##
	                } else if (maxValue !== null) {
	                    message += (microstrategy.descriptors.getDescriptor("3041").replace(/###/, maxValue)).replace(/##/, fieldName) + "<br />";  //Descriptor: Please enter a number less than ### in the following field: ##
	                }
	            }
                //Validation against other field - lessthan/greaterthan
                var ltInput = null;
                var acceptEqual;
                if (value.length > 0 && field.getAttribute(mstrHTMLAttributes.ATTR_LT) != null && field.getAttribute(mstrHTMLAttributes.ATTR_LT).length > 0) {  // length zero already tested
                    ltInput = getElementById(field.getAttribute(mstrHTMLAttributes.ATTR_LT));
                    acceptEqual = false;
                } else if (value.length > 0 && field.getAttribute(mstrHTMLAttributes.ATTR_LE) != null && field.getAttribute(mstrHTMLAttributes.ATTR_LE).length > 0) {
                    ltInput = getElementById(field.getAttribute(mstrHTMLAttributes.ATTR_LE));
                    acceptEqual = true;
                }
                
                if (ltInput != null && !ltInput.disabled) {
                    ltValue = ltInput.value;
                    if (ltValue != null && ltValue.length > 0) {
                    	var fieldValue = value;
                    	if (field.getAttribute(mstrHTMLAttributes.ATTR_DTY) == "201") {
                    		ltValue = mstrEditorImpl.getTime(ltInput) + "";
                    		fieldValue = mstrEditorImpl.getTime(field) + "";
                    		if (ltValue == 0) { 
                    			return message;
                    		}
                    	} 
                        if (parseFloat(mstr.utils.LocaleParser.convertToBrowserNumber(ltValue)) < parseFloat(mstr.utils.LocaleParser.convertToBrowserNumber(fieldValue))
                            || (!acceptEqual && parseFloat(mstr.utils.LocaleParser.convertToBrowserNumber(ltValue)) == parseFloat(mstr.utils.LocaleParser.convertToBrowserNumber(fieldValue)))) {
                            if ((field.getAttribute(mstrHTMLAttributes.ATTR_ERR) != null) && (field.getAttribute(mstrHTMLAttributes.ATTR_ERR).length > 0)) {
                                message += field.getAttribute(mstrHTMLAttributes.ATTR_ERR) + "<br />";
                            } else {
                                message += (microstrategy.descriptors.getDescriptor(field.getAttribute(mstrHTMLAttributes.ATTR_DTY) == "201"? "7747" : "3041").replace(/###/, ltInput.value)).replace(/##/, fieldName) + "<br />";   //Descriptor: Please enter a number/date less than ### in the following field: ##
                            }
                        }
                    }
                }
                
                var gtInput = null;
                if (value.length > 0 && field.getAttribute(mstrHTMLAttributes.ATTR_GT) != null && field.getAttribute(mstrHTMLAttributes.ATTR_GT).length > 0) {
                    gtInput = getElementById(field.getAttribute(mstrHTMLAttributes.ATTR_GT));
                    acceptEqual = false;
                } else if (value.length > 0 && field.getAttribute(mstrHTMLAttributes.ATTR_GE) != null && field.getAttribute(mstrHTMLAttributes.ATTR_GE).length > 0) {
                    gtInput = getElementById(field.getAttribute(mstrHTMLAttributes.ATTR_GE));
                    acceptEqual = true;
                }

                if (gtInput != null && !gtInput.disabled) {
                    gtValue = gtInput.value;
                    if (gtValue && gtValue.length > 0) {
                        var fieldValue = value;
                    	if (field.getAttribute(mstrHTMLAttributes.ATTR_DTY) == "201") {
                    		gtValue = mstrEditorImpl.getTime(gtInput) + "";
                    		fieldValue = mstrEditorImpl.getTime(field) + "";
                    		if (gtValue == 0) { 
                    			return message;
                    		}
                    	} 
                        if (parseFloat(mstr.utils.LocaleParser.convertToBrowserNumber(fieldValue)) < parseFloat(mstr.utils.LocaleParser.convertToBrowserNumber(gtValue))
                            || (!acceptEqual && parseFloat(mstr.utils.LocaleParser.convertToBrowserNumber(gtValue)) == parseFloat(mstr.utils.LocaleParser.convertToBrowserNumber(fieldValue)))) {
                            if ((field.getAttribute(mstrHTMLAttributes.ATTR_ERR) != null) && (field.getAttribute(mstrHTMLAttributes.ATTR_ERR).length > 0)) {
                                message += field.getAttribute(mstrHTMLAttributes.ATTR_ERR) + "<br />";
                            } else {
                                message += (microstrategy.descriptors.getDescriptor(field.getAttribute(mstrHTMLAttributes.ATTR_DTY) == "201"? "7746" : "3039").replace(/###/, gtInput.value)).replace(/##/, fieldName) + "<br />";   //Descriptor: Please enter a number/date greater than ### in the following field: ##
                            }
                        }
                    }
                }
                
                if (field.getAttribute(mstrHTMLAttributes.ATTR_NOZEROSTR) != null && trim(value).length == 0) {
                	message += microstrategy.descriptors.getDescriptor("3878") + " " + fieldName + "<br />";        //Descriptor: Please enter a non-empty string in the following field:
                }
            }
        }
        return message;
    }
    catch(err) {
        microstrategy.errors.log(err);
        return message;
    }
}

mstrEditorImpl.getTime = function (field){
    var format = field.getAttribute(mstrHTMLAttributes.ATTR_DF);
    
    var y = getDateFromFormat(field.value, format, DATE_YEAR);
    var m = getDateFromFormat(field.value, format, DATE_MONTH) - 1;
    var d = getDateFromFormat(field.value, format, DATE_DAY);
    if (y > 0 && m >= 0 && d > 0) {
        return (new Date(y, m, d)).getTime();
    } else {
        return 0;
    }
}


//Static function to be used for editing subscription 
mstrEditorImpl.validateInputs = function(obj, enforceValidation){
	try {
        var errorMessage = "";
        var deltaMessage = "";
        
        if (obj) {
	        var inputs = obj.getElementsByTagName("INPUT");
	        var pageRange = [];
	        
	        for (var i = 0; i < inputs.length; i++) {
	        	// current function is a static function. When it is called as static way, 'this' is mstrEditorImpl
	        	// when it is called from instance function mstrEditorImpl.prototype.validateInputs,
	        	// an 'this' will be passed in, and it will be an instance of mstrEditorImpl,
	        	// then it will keep any ovrriding of instance function vailidateField() working
	        	
	            //TQMS 306331: need to check relationship dependency between rangeStart and rangeEnd
	            deltaMessage = this.validateField(inputs[i], "", enforceValidation);
	            if( deltaMessage.length == 0 && !inputs[i].disabled){
		            if( inputs[i].name == "rangeStart" || inputs[i].name == "rangeEnd" ){
		                pageRange.push( inputs[i] );
		            }
	            }
	            else {
		            errorMessage += deltaMessage;
	            }
	        }
	        
	        if( pageRange.length == 2 ){ //need to check relationship dependency between rangeStart and rangeEnd
	            var v0 = parseInt( pageRange[0].value );
	            var v1 = parseInt( pageRange[1].value );
                if( (pageRange[0].name == "rangeStart"  && v0 > v1) || (pageRange[0].name == "rangeEnd"  && v0 < v1)){
                    errorMessage += (microstrategy.descriptors.getDescriptor("5784").replace(/###/, microstrategy.descriptors.getDescriptor("6141"))).replace(/##/, microstrategy.descriptors.getDescriptor("6140")) + "<br />"; //Descriptor: A number in field: ### should be greater than or equal to the number in field: ##
                }
	        }
	        
	        if (errorMessage != null && errorMessage.length > 0) {
	            showMessage( {contents:errorMessage, elements:microstrategy.OK_BUTTON, type:mstrMsgBoxImpl.MSG_ERROR});
	            return false;
	        }
        }
        return true;
    }
    catch(err) {
        microstrategy.errors.log(err);
        return false;
    }
}

mstrEditorImpl.prototype.validateSingleInput = function(oInput){
    //@class=mstrEditorImpl;@method=validateSingleInput;
    //Usage: called as this.validateSingleInput(oInput).
    //Purpose: to validate the requested input field.
    try {
        var errorMessage = mstrEditorImpl.validateField(oInput, "");
        if (errorMessage != null && errorMessage.length > 0) {
            showMessage( {contents:errorMessage, elements:microstrategy.OK_BUTTON, type:mstrMsgBoxImpl.MSG_ERROR});
            return false;
        }
    }
    catch(err) {
        microstrategy.errors.log(err);
    }
    return true;
}

mstrEditorImpl.prototype.validateInputs = function() {
    //@class=mstrEditorImpl;@method=validateInputs;
    //Usage: called as this.validateInputs(this).
    //Purpose: to validate all inputs in the editor.
    try {
       return mstrEditorImpl.validateInputs.call(this, this.elem, false);
    } catch(err) {
       microstrategy.errors.log(err);
    }
}

mstrEditorImpl.prototype.getCheckboxesState = function(arrayCheckboxes) {
    //@class=mstrEditorImpl;@method=getCheckboxesState;
    // Usage: Determine if none selected, few selected or all selected.
    try {
        var result = null;
        if (arrayCheckboxes) {
            for (var i=0; i<arrayCheckboxes.length; i++) {
                var chkbox = arrayCheckboxes[i];
                if (chkbox.checked) {
                    switch (result) {
                    case this.CHECKBOX_PARTIALLY_SELECTED:
                    case this.CHECKBOX_UNSELECTED:
                        result = this.CHECKBOX_PARTIALLY_SELECTED;
                        break;
                    case this.CHECKBOX_SELECTED:
                    default:  // null
                        result = this.CHECKBOX_SELECTED;
                        break;
                    }
                } else {
                    switch (result) {
                    case this.CHECKBOX_PARTIALLY_SELECTED:
                    case this.CHECKBOX_SELECTED:
                        result = this.CHECKBOX_PARTIALLY_SELECTED;
                        break;
                    case this.CHECKBOX_UNSELECTED:
                        result = this.CHECKBOX_UNSELECTED;
                        break;
                    default:  // null
                        result = this.CHECKBOX_UNSELECTED;
                        break;
                    }
                }
                if (result == this.CHECKBOX_PARTIALLY_SELECTED) break;
            }
        }
        return result;
    }
    catch(err) {
        microstrategy.errors.log(err);
        return this.CHECKBOX_UNSELECTED;
    }
}

mstrEditorImpl.prototype.adjustCheckboxes = function(arrayCheckboxes, bChecked) {
    //@class=mstrEditorImpl;@method=adjustCheckboxes;
    // Usage: Set all the checkboxes on the array according to the checked value.
    try {
        if (arrayCheckboxes) {
            for (var i=0; i<arrayCheckboxes.length; i++) {
                var chkbox = arrayCheckboxes[i];
                chkbox.checked = bChecked;
            }
        }
    }
    catch(err) {
        microstrategy.errors.log(err);
        return false;
    }
}

mstrEditorImpl.prototype.updateChildrenCheckboxes = function(parentCheckbox, arrayCheckboxes) {
    //@class=mstrEditorImpl;@method=updateChildrenCheckboxes;
    // Usage: When the user clicks on a check box that has children checkboxes that need to be checked/unchecked accordingly.
    try {
        if (parentCheckbox && arrayCheckboxes) {
            // uncheck all children if unchecking
            // check all children if checking
            this.adjustCheckboxes(arrayCheckboxes, parentCheckbox.checked);
        }
    }
    catch(err) {
        microstrategy.errors.log(err);
        return false;
    }
}

mstrEditorImpl.prototype.updateParentCheckboxImage = function(parentCheckbox, arrayCheckboxes) {
    //@class=mstrEditorImpl;@method=updateParentCheckbox;
    // Usage: When the user clicks on a check box that has a 'parent' checkbox, see if the parent needs to be checked/unchecked accordingly.
    try {
        if (parentCheckbox && parentCheckbox.className != this.CHECKBOX_DISABLED && arrayCheckboxes) {
            parentCheckbox.className = this.getCheckboxesState(arrayCheckboxes);
        }
    }
    catch(err) {
        microstrategy.errors.log(err);
        return false;
    }
}

mstrEditorImpl.prototype.computeZIndex = function() {
    //@class=mstrEditorImpl;@method=computeZIndex;
        var currentPosition = this.getLayer(this.id);
        var maxZIndex = microstrategy.getMaxZIndex();

        if (currentPosition == -1) {
            currentPosition = this.addLayer();
        }

        // Add 100 to make sure it's on top of everything.
        var zIndex = (1 + currentPosition) * 2 + 3 + maxZIndex + 100;
        return zIndex;
}

mstrEditorImpl.prototype.customJS = function(jsCode) {
    //@class=mstrEditorImpl;@method=customJS;
    //Usage: used for customizations so any JS can be used on the "okJS", "applyJS" and "cancelJS" formal parameters
    //Purpose: to execute any javascript
    try {
		eval(jsCode)
    }
    catch(err) {
        microstrategy.errors.log(err);
        return false;
    }
}

/**
 * @class The base class for all editor bones. 
 * @param {String} id The ID of the HTMLElement that visually represents this bone.
 * @extends mstrDialogImpl
 */
function mstrEditorImpl(id) {
    this.inherits = mstrDialogImpl;
    this.inherits(id);
    delete this.inherits;

    return this;
}

