// %fv: uluv.js-110 % %dc: Tue Aug 04 13:30:22 2009 %

/******************************************************************************
COPYRIGHT
    (C) 2008 Compuware Corporation.  All rights reserved.
    Unpublished - rights reserved under the Copyright Laws of the United States.

    U.S. GOVERNMENT RIGHTS-Use, duplication, or disclosure by the
    U.S. Government is subject to restrictions as set forth in
    Compuware Corporation license agreement and as
    provided in DFARS 227.7202-1(a) and 227.7202-3(a) (1995),
    DFARS 252.227-7013(c)(1)(ii)(OCT 1988), FAR 12.212(a) (1995),
    FAR 52.227-19, or FAR 52.227-14 (ALT III), as applicable.
    Compuware Corporation

    This product contains confidential information and trade
    secrets of Compuware Corporation.  Use disclosure, or
    reproduction is prohibited
    without the prior express written permission of Compuware Corporation.
******************************************************************************/

/*******************************************************************************
date   refnum    version who description
080411 c26508    9.ajax  tsk mashup enablement
080508 c26571    9.ajax  mzu add more API function for unit test
080509 c26483    9.ajax  mzu change the widget style property handling
080611 c26693    9.ajax  mzu Reduce using of getElementById
090205 c27248    9.ajax  jdk acceskeys do not work & labels etc show the %sign
090227 c27325    9401c1  fd Introduce occurrence pool and occurrence map. See entityadmin.
090401 c27358    9401c1  fd  RIA: Use field IDs rather than names in the JSON stream.
090424 c27369    9401c1  mzu RIA: Extends the id with DSP component name.
090528 c27361    9401c1  mzu RIA: Enhance for DSP mashup.
090724 c27513    9401c1  jdk RIA: If instname.length != compname.lenght...crash.Use instname for key.
* date   refnum    version who description
*******************************************************************************/

/*global UNIFACE document */

UNIFACE.assert = function(condition, message) {
    if (!condition) {
        UNIFACE.throwException("INTERNAL ERROR: " + message);
    }
};
///////////////////////////////////////////////////////////////////////////////
// UNIFACE.luv.constants
///////////////////////////////////////////////////////////////////////////////

UNIFACE.namespace("luv.constants").extend(
function() {
return {
    BROWSER_TYPE : (document.all ? "ie" : "ff"), //UNIFACE.luv.constants.BROWSER_TYPE
    
    UENTITY_PREFIX: "uent:", //UNIFACE.luv.constants.UENTITY_PREFIX
    UFIELD_PREFIX : "ufld:", //UNIFACE.luv.constants.UFIELD_PREFIX
    ULABEL_PREFIX : "ulbl:", //UNIFACE.luv.constants.ULABEL_PREFIX
    
    EMPTY_OCC_ID : "---empty",  // UNIFACE id for the empty occurrence.
    
    ONETIME_PROPS : 
    {
        "uniface": 
        {
            "errormsg" : true,
            "subclass" : true
        }
    },
    
    UID_PREFIXES : {
    	"uent:" : "",
    	"ufld:" : "",
    	//"uf:ftitle:" : "",
    	"ulbl:" : "",
    	"uocc:" : "",
    	"uoce:" : "",
    	"uocs:" : ""
    },
    
    UOID_PREFIXES : {
    	"uocc:" : "",
    	"uoce:" : "",
    	"uocs:" : ""
    }

};
}());

///////////////////////////////////////////////////////////////////////////////
// UNIFACE.luv.util
///////////////////////////////////////////////////////////////////////////////

UNIFACE.namespace("luv.util").extend(
function() {
    var ULIST_SEPARATOR="\u001B",
        ULIST_SUBSEPARATOR="\u0015",
        TRIGGER_TYPES = {
            UPDATE   : true,
            FULLPAGE : true 
        };
    return {
        uListToArray : function(aUList) {
            return aUList.split(ULIST_SEPARATOR);
        },
        
        arrayToUList : function(aArray) {
            return aArray.join(ULIST_SEPARATOR);
        },
        
        // for Profiling
        getElementById : function (aId) {
            return document.getElementById(aId);
        },

        isValidRequestType : function(requestType) {
            return typeof(requestType) === "string" && TRIGGER_TYPES[requestType.toUpperCase()] === true;
        },
        
        duplicateObject : function(aObject) {
            var lObject;
            switch (typeof aObject) {
            case "array" :
                lObject = [];
                for (var i=0, l=aObject.length; i<l; i++) {
                    lObject[i] = UNIFACE.luv.util.duplicateObject(aObject[i]);
                }
                break;
            case "object" :
                lObject = {};
                for ( var aProp in aObject ) if ( aObject.hasOwnProperty(aProp) ) {
                    lObject[aProp] = UNIFACE.luv.util.duplicateObject(aObject[aProp]);
                }
                break;
            default:
                lObject = aObject;
            }
            return lObject;
        },
    
        // Removes the image references for valreps of the form "img!rep"
        normalizeValrep : function(valrep) {
            for (var i in valrep) if (valrep.hasOwnProperty(i) ) {
                var rep = valrep[i],
                    separatorIndex = rep.indexOf(ULIST_SUBSEPARATOR);
                if (separatorIndex >= 0) {
                    valrep[i] = rep.substr(separatorIndex+1);
                }
            }
            return valrep;
        }
    };
}());

///////////////////////////////////////////////////////////////////////////////
// UNIFACE.luv.properties
///////////////////////////////////////////////////////////////////////////////

UNIFACE.luv.properties = function() {
    this.preStyle = {};
    this.html = {};
    this.trigger = {};
    this.uniface = {};
};
    
UNIFACE.luv.properties.UHTML_DOM_MAP = {
    "html:accesskey" : "accessKey",
    "html:class"     : "className",
    "html:disabled"  : "disabled",
    "html:multiple"  : "multiple",
    "html:readonly"  : "readOnly",
    "html:size"      : "size",
    "html:tabindex"  : "tabIndex",
    "html:title"     : "title",
    "html:rows"      : "rows",
    "html:cols"      : "cols"
};

UNIFACE.luv.properties.UDOM_BOOL_PROPS = {        // dom property with bool value type
    "disabled"  : "disabled",
    "multiple"  : "multiple",
    "readOnly"  : "readOnly"
};
    
UNIFACE.luv.properties.USTYLE_DOM_MAP = { // UNIFACE style-related logic property to css style property
    backcolor : "backgroundColor",
    forecolor : "color",
    //fontname  : "fontFamily",
    //fontsize  : "fontSize",
    //size      : "width",
        
    "style:background"           : "background",
    "style:background-attachment": "backgroundAttachment",
    "style:background-color"     : "backgroundColor",
    "style:background-image"     : "backgroundImage",
    "style:background-repeat"    : "backgroundRepeat",
    "style:border"               : "border",
    "style:border-bottom"        : "borderBottom",
    "style:border-bottom-color"  : "borderBottomColor",
    "style:border-bottom-style"  : "borderBottomStyle",
    "style:border-bottom-width"  : "borderBottomWidth",
    "style:border-collapse"      : "borderCollapse",
    "style:border-color"         : "borderColor",
    "style:border-left"          : "borderLeft",
    "style:border-left-color"    : "borderLeftColor",
    "style:border-left-style"    : "borderLeftStyle",
    "style:border-left-width"    : "borderLeftWidth",
    "style:border-right"         : "borderRight",
    "style:border-right-color"   : "borderRightColor",
    "style:border-right-style"   : "borderRightStyle",
    "style:border-right-width"   : "borderRightWidth",
    "style:border-style"         : "borderStyle",
    "style:border-top"           : "borderTop",
    "style:border-top-color"     : "borderTopColor",
    "style:border-top-style"     : "borderTopStyle",
    "style:border-top-width"     : "borderTopWidth",
    "style:border-width"         : "borderWidth",
    "style:bottom"               : "bottom",
    "style:clear"                : "clear",
    "style:color"                : "color",
    //"style:csstext"              : "cssText",
    "style:cursor"               : "cursor",
    "style:direction"            : "direction",
    "style:display"              : "display",
    "style:font"                 : "font",
    "style:font-family"          : "fontFamily",
    "style:font-size"            : "fontSize",
    "style:font-style"           : "fontStyle",
    "style:font-variant"         : "fontVariant",
    "style:font-weight"          : "fontWeight",
    "style:height"               : "height",
    "style:left"                 : "left",
    "style:letter-spacing"       : "letterSpacing",
    "style:line-height"          : "lineHeight",
    "style:list-style-image"     : "listStyleImage",
    "style:list-style-position"  : "listStylePosition",
    "style:list-style-type"      : "listStyleType",
    "style:margin"               : "margin",
    "style:margin-bottom"        : "marginBottom",
    "style:margin-left"          : "marginLeft",
    "style:margin-right"         : "marginRight",
    "style:margin-top"           : "marginTop",
    "style:min-height"           : "minHeight",
    "style:overflow"             : "overflow",
    //"style:overflow-x"           : "overflowX",
    //"style:overflow-y"           : "overflowY",
    "style:padding"              : "padding",
    "style:padding-bottom"       : "paddingBottom",
    "style:padding-left"         : "paddingLeft",
    "style:padding-right"        : "paddingRight",
    "style:padding-top"          : "paddingTop",
    //"style:page-break-after"     : "pageBreakAfter",
    //"style:page-break-before"    : "pageBreakBefore",
    "style:position"             : "position",
    "style:right"                : "right",
    "style:table-layout"         : "tableLayout",
    "style:text-align"           : "textAlign",
    "style:text-decoration"      : "textDecoration",
    "style:text-indent"          : "textIndent",
    "style:text-transform"       : "textTransform",
    "style:top"                  : "top",
    "style:unicode-bidi"         : "unicodeBidi",
    "style:vertical-align"       : "verticalAlign",
    "style:visibility"           : "visibility",
    "style:white-space"          : "whiteSpace",
    "style:width"                : "width",
    "style:word-spacing"         : "wordSpacing",
    "style:z-index"              : "zIndex"
};
    
UNIFACE.luv.properties.PROPERTY_NOT = "!"; // Constant
    
UNIFACE.luv.properties.getStyleProperty = function(propName) {
    return UNIFACE.luv.properties.USTYLE_DOM_MAP[propName];
};

UNIFACE.luv.properties.normalizeProps = function(props) {
    if ( props instanceof UNIFACE.luv.properties ) {
        return props;
    }
        
    var l_props = new UNIFACE.luv.properties();
    if ( typeof props !== "object" ) {
        return l_props;
    }
    var l_prop, l_lowercaseProp, l_normProp;
    
    for ( l_prop in props ) if (props.hasOwnProperty(l_prop))
    {
        l_lowercaseProp = l_prop.toLowerCase(); // normalize to lowercase
        if ( l_lowercaseProp.substring(0,1) !== UNIFACE.luv.properties.PROPERTY_NOT ) {
            l_normProp = UNIFACE.luv.properties.getStyleProperty(l_lowercaseProp);
            var l_value = props[l_prop];
            if ( l_normProp != null ) { // pragma(allow-loose-compare)
                l_props.preStyle[l_normProp] = l_value;  // add to list
            } else if ((l_normProp = UNIFACE.luv.properties.UHTML_DOM_MAP[l_lowercaseProp]) != null) {  // html prop, pragma(allow-loose-compare)
                l_props.html[l_normProp] = l_value;
            } else { // normal (uniface) prop
                l_props.uniface[l_lowercaseProp] = l_value;
            }
        }
    }
    l_props.styling();
    return l_props;
};

UNIFACE.luv.properties.supportedHTMLprops = {};
( function() {
    var prop;
    for (prop in UNIFACE.luv.properties.UHTML_DOM_MAP) if (UNIFACE.luv.properties.UHTML_DOM_MAP.hasOwnProperty(prop)){
        UNIFACE.luv.properties.supportedHTMLprops[UNIFACE.luv.properties.UHTML_DOM_MAP[prop]] = true;
    }
}());

// Function that determines whether or not a property was
// defined in the source document.
// This is needed because IE (7 and earlier at least) behaves
// rather peculiarly in this respect.  It has defaults for non-defined
// properties that are indistinguishable from explicitly defined properties.
UNIFACE.luv.properties.isAttributeDefined = function(node, attrName) {
    var attrValue = node.getAttribute(attrName);
    if (attrValue === "") {
        // Here we assume that the string value was not defined
        // in the source document.  Note that we therefore consider
        // explicitly defined values of "" to be the same as undefined.
        // --- If we want this behavior to be specific for IE
        // --- (rather than generic for all browsers)
        // --- this piece of code needs to move to the end of this
        // --- function (right before the last return statement).
        return false;
    }
    if (UNIFACE.luv.constants.BROWSER_TYPE !== "ie") {
        return node.hasAttribute(attrName);
    }
    return attrValue != null && attrValue === node.getAttribute(attrName, 2); // pragma(allow-loose-compare)
};


UNIFACE.luv.properties.getPropsFromDOMNode = function(domNode) {
    // There must be a domNode to get properties from.
    if ( !domNode ) {
        return;
    }
    
    var props = new UNIFACE.luv.properties();
    // Get the style properties from the domNode.
    if ( domNode.style && domNode.style.cssText !== "") {
        props.initByStyle(domNode.style);
    }
    // for supporting old size property
    if ( false && domNode.size > 0 && !isNaN(domNode.size) ) { // pragma(allow-loose-compare)
        props.preStyle = "width: " + domNode.size + "em";
    }
    // Get the U_display property.
    if ( domNode.U_display != null ) { // pragma(allow-loose-compare)
        props.preStyle.display = domNode.U_display;
    }
    
    // Get the other properties, assuming they are HTML properties.
    var attrs = domNode.attributes,
        attr,
        i;
    for (i = attrs.length - 1; i >= 0; i = i-1) {
        attr = attrs[i];
        var attrName = attr.nodeName;
        if (attrName === "tabindex") {
            attrName = "tabIndex";
        }
        if (UNIFACE.luv.properties.supportedHTMLprops[attrName] && UNIFACE.luv.properties.isAttributeDefined(domNode, attrName)) {
            props.html[attrName] = attr.nodeValue;
        }
    }
    //props.styling();
    return props;
};
    
UNIFACE.luv.properties.prototype.initByStyle = function(aStyle) {
        
    function getPList(aStyle) {
        var vPnvList = aStyle.cssText.split(/; +/),
            vPnList = [];
        for (var i=0, l=vPnvList.length; i<l; i++) {
            vPnList.push(vPnvList[i].split(":")[0].toLowerCase());
        }
        return vPnList;
    }
    var vPnList = getPList(aStyle);
    this.preStyle = {};
    for (var i=0, l=vPnList.length; i<l; i++) {
        var vProp = UNIFACE.luv.properties.getStyleProperty("style:" + vPnList[i]);
        if (vProp) {
            this.preStyle[vProp] = aStyle[vProp];
        }
    }
};
    
UNIFACE.luv.properties.prototype.overlayWith = function(otherProps) {
    var l_props = this,
        l_prop, l_lowercaseProp, l_normProp, l_value;
        
    // Adding newdata to list, or deleting prop if it starts with '!';
        
    // reset all first
    if ( otherProps && otherProps.hasOwnProperty(UNIFACE.luv.properties.PROPERTY_NOT) ) {
        l_props = new UNIFACE.luv.properties(); // reset all
    }
    
    for ( l_prop in otherProps) if (otherProps.hasOwnProperty(l_prop))
    {
        l_lowercaseProp = l_prop.toLowerCase(); // normalize to lowercase
        if ( l_prop.substring(0,1) !== UNIFACE.luv.properties.PROPERTY_NOT ) {
            l_normProp = UNIFACE.luv.properties.getStyleProperty(l_lowercaseProp);
            l_value = otherProps[l_prop];
            if ( l_normProp != null ) { // style-related prop.   pragma(allow-loose-compare)
                if ( l_lowercaseProp === "size" ) {
                    if ( l_value != null && !isNaN(l_value) && l_value !== "NaN" )  // pragma(allow-loose-compare)
                    {
                        l_props.preStyle[l_normProp] = l_value + "em";  // add to list
                    }
                } else {
                    l_props.preStyle[l_normProp] = l_value;  // add to list
                }
                
            } else if ((l_normProp = UNIFACE.luv.properties.UHTML_DOM_MAP[l_lowercaseProp]) != null) {  // html prop, pragma(allow-loose-compare)
                l_props.html[l_normProp] = l_value;
            } else { // normal (uniface) prop
                l_props.uniface[l_lowercaseProp] = l_value;  
            }
        } else if ( l_prop.length > 1 ) {
            l_lowercaseProp = l_lowercaseProp.substring(1);
            l_normProp = UNIFACE.luv.properties.getStyleProperty(l_lowercaseProp);
            if ( l_normProp != null ) { // pragma(allow-loose-compare)
                if ( l_props.preStyle.hasOwnProperty(l_normProp) ) {
                    delete l_props.preStyle[l_normProp]; // remove from preStyle list
                }
            } else if ((l_normProp = UNIFACE.luv.properties.UHTML_DOM_MAP[l_lowercaseProp]) != null) {  // html prop, pragma(allow-loose-compare)
                if ( l_props.html.hasOwnProperty(l_normProp) ) {
                    delete l_props.html[l_normProp]; // remove from html list
                }
            } else {
                if ( l_props.uniface.hasOwnProperty(l_lowercaseProp) ) {
                    delete l_props.uniface[l_lowercaseProp]; // remove from list
                }
            }
        }
    }
    return l_props;
};

UNIFACE.luv.properties.prototype.mergeWith = function(otherProps) {
    // We copy all string properties, as well as the property called "triggers".
    // The latter is not a string but rather an object, listing all supported triggers.    
    if ( otherProps == null ) { // pragma(allow-loose-compare)
    	return;
    }
    var vProp;  
    for (vProp in otherProps) if (otherProps.hasOwnProperty(vProp) && typeof otherProps[vProp] === "string" ) 
    {
        this[vProp] = otherProps[vProp];
    }
    
    //theStyle.cssText = "";
    for (vProp in otherProps.preStyle) if (otherProps.preStyle.hasOwnProperty(vProp )) 
    {
        this.preStyle[vProp] = otherProps.preStyle[vProp];
    }
    
    for (vProp in otherProps.html) if (otherProps.html.hasOwnProperty(vProp )) 
    {
        this.html[vProp] = otherProps.html[vProp];
    }
    
    for (vProp in otherProps.trigger) if (otherProps.trigger.hasOwnProperty(vProp )) 
    {
        this.trigger[vProp] = otherProps.trigger[vProp];
    }
    
    for (vProp in otherProps.uniface) if (otherProps.uniface.hasOwnProperty(vProp )) 
    {
        this.uniface[vProp] = otherProps.uniface[vProp];
    }
};            
    
(function(){
    var theStyle = null;
    
    function initStyle() {
        var tempDivNode = document.createElement("div");
        tempDivNode.id = "UNIFACE.styleHelper";
        var tempNode = document.createElement("span");
        tempNode.innerHTML = "UNIFACE style helper";
        theStyle = tempNode.style;
        
        tempDivNode.style.display = "none";
        document.body.appendChild(tempDivNode);
        tempDivNode.appendChild(tempNode);
    }
    
    UNIFACE.luv.properties.prototype.styling = function() {
        if ( !theStyle ) {
            initStyle();
        }
        theStyle.cssText = "";
        var vProp;
        for (vProp in this.preStyle) if ( this.preStyle.hasOwnProperty(vProp) ) {
            try {
                theStyle[vProp] = this.preStyle[vProp];
            } catch (e) {  // could happen for ie6
                //ignore
            }
        }
        this.initByStyle(theStyle);
    };
})();

/**
 * Applies the style and HTML properties in this properties object
 * to a DOM node.
 * @param node DOM node to which to apply this properties object.
 */
UNIFACE.luv.properties.prototype.applyToDOMNode = function(node) {
    var p;
    // The style properties:
    var style = node.style;
    style.cssText = "";    // First reset.
    for (p in this.preStyle) if (this.preStyle.hasOwnProperty(p)) {
        style[p] = this.preStyle[p];
    }
    // The HTML properties:
    for (p in this.html) if (this.html.hasOwnProperty(p)) {
        node[p] = this.html[p];
    }
};

///////////////////////////////////////////////////////////////////////////////
// UNIFACE.luv.field
///////////////////////////////////////////////////////////////////////////////

    
UNIFACE.luv.field = function( a_id, a_occ, a_fldName, a_fldDef) {
    if (a_fldDef && a_fldDef.valrep) {
        a_fldDef.valrep = UNIFACE.luv.util.normalizeValrep(a_fldDef.valrep);
    }
    this.fieldId = a_id;
    this.occ = a_occ;
    this.definition = a_fldDef;
    
    this.valueExt = "";
    this.data = null;
    this.valrep = null;
    this.widget = null;

    if (a_fldDef.widget )
    {
        this.widget = UNIFACE.createWidget(a_fldDef.widget, this.fieldId);
        this.widget.callBack = this.createCallBack();
    }
    
    this.plainFieldName = a_fldName;
};

UNIFACE.luv.field.prototype.checkedValue = function(aVal)
{
    if (this.widget)
    {
        if (aVal === undefined)
        {
            aVal = this.widget.getValue();
        }
        if (aVal == null) { // pragma(allow-loose-compare)
            aVal = "";
        }

        var originalValue, props;
        if (this.data) {
            // Check the 'original' value as interpreted by the widget versus the 'new' value 
            originalValue = this.data.value;
            props = this.data.normalizedProps;
        } else {
            originalValue = "";
            props = {};
        }

        var lSyntax = this.definition.syntax;
        if (!lSyntax) {
            lSyntax = {};
        }

        // Check if the field's widget approves of the value.
        if (typeof this.widget.validate === "function") {
            var errorMsg = this.widget.validate();
            if (errorMsg) {
                return {
                    "originalValue"     : originalValue,
                    "fieldValue"        : originalValue,
                    "newValue"          : originalValue,
                    "normalizedValue"   : originalValue,
                    "syntax"            : lSyntax,
                    "valrep"            : this.valrep,
                    "fieldName"         : this.plainFieldName,
                    "error"             : errorMsg
                };
            }
        }

        if ( props.html ) {
            if ( props.html.disabled === "true" ) {
                lSyntax.DIM = true;
            } else if ( props.html.disabled === "false" && lSyntax.DIM !== undefined ) {
                delete lSyntax.DIM;
            }
            if ( props.html.readOnly === "true" ) {
                lSyntax.NED = true;
            } else if ( props.html.readOnly === "false" && lSyntax.NED !== undefined ) {
                delete lSyntax.NED;
            }
        }
   
        return UNIFACE.syn.checkField(lSyntax, aVal, originalValue, this.valrep, this.plainFieldName );
    }
    else
    {
        if (this.data) {
            return { normalizedValue : this.data.value };
        }
        else
        {
            return { normalizedValue : "" };
        }
    }
};

UNIFACE.luv.field.prototype.setProperties = function(a_fldDef, a_fldData) {
    var lData = a_fldDef;
    this.mergedProperties = new UNIFACE.luv.properties();
    this.mergedProperties.mergeWith(a_fldDef.declaredProps );

    if (a_fldData)
    {
        lData = a_fldData;
        if (lData.valrep) {
            lData.valrep = UNIFACE.luv.util.normalizeValrep(lData.valrep);
        }
            
        if (lData.normalizedProps === undefined)
        {
            lData.normalizedProps = UNIFACE.luv.properties.normalizeProps(lData.properties);
        }
        this.mergedProperties.mergeWith(lData.normalizedProps);        
        this.unBlockedStyle = undefined;
        if (a_fldData.block) 
    {
        this.showBlock();            
        }    
    }
    
    // Set field value, valrep, and syntax
    this.data = lData;
    if (lData.valrep )
    {
        this.valrep = lData.valrep;    
        this.widget.setValrep(lData.valrep);
    }
    else if ( this.definition.valrep )
    {
        this.valrep = this.definition.valrep;
        this.widget.setValrep(this.definition.valrep);
    }
        
    if (this.definition.syntax !== undefined && this.definition.syntax !== null)
    {
        this.widget.setSyntax(this.definition.syntax);
    }
    if (lData.value !== undefined && lData.value !== null)
    {
        if ( this.definition.declaredProps && 
            this.definition.declaredProps.uniface["func:getdatavalue"] && 
            UNIFACE.luv.dynamicFunctions && 
            UNIFACE.luv.dynamicFunctions[this.definition.declaredProps.uniface["func:getdatavalue"]] ) {
            this.valueExt = UNIFACE.luv.dynamicFunctions[this.definition.declaredProps.uniface["func:getdatavalue"]](this, lData);
        } else {
            this.valueExt = UNIFACE.syn.int2ext(this.definition.syntax, lData.value );
        }
        this.widget.setValue(this.valueExt);
    }
    if (lData.resource !== undefined && lData.resource !== null)
    {
        this.widget.setResource(lData.resource);
    }
};
       
UNIFACE.luv.field.prototype.showError = function(a_message)
{
    if (this.widget && typeof this.widget.showError === "function")
    {
        this.widget.showError(a_message);
    }
    else
    {            
        UNIFACE.extension.errorWidget.show(this.widget.getDomNode(), a_message);
    }
};
    
UNIFACE.luv.field.prototype.unrealize = function()
{
    if (this.widget)
    {
        this.widget.unrender();
    }
};
    
UNIFACE.luv.field.prototype.isModified = function()
{
    if (this.widget) {
        return this.widget.getValue() !== this.widgetValue;
    }
    return false;
};
        
UNIFACE.luv.field.prototype.createCallBack = function()
{
    var field = this;  // Create closure
    return {
        checkValue : function(aVal) {
            if (field.modValue === aVal) {
                // The field is not modified, so no need to check its value.
                return { newValue : aVal };
            }
            var checkedValue = field.checkedValue(aVal);
            if (!checkedValue.error) {
                // The field was successfully checked.
                // Update the 'modValue', so that next time this checkValue() function
                // will use *that* in the modification test a few lines above.
                field.modValue = checkedValue.normalizedValue;
            }
            return checkedValue;
        },
        getProperties : function() {
            return field.mergedProperties;
        },
        getSyntax : function() {
            return field.definition.syntax; // TODO: MERGE syntax
        },
        bindEvent : function(a_triggerName, a_post) {
            if (!field.definition.triggers || !field.definition.triggers[a_triggerName]) {
                return null;
            }
            return function(a_ev)
            {
                if (a_post)
                {
                    UNIFACE.dl.postTrigger(field, a_triggerName, true);
                    UNIFACE.dl.commands.run();
                }
                else
            {
                UNIFACE.dl.callTrigger(field, a_triggerName, a_ev);
                }
            };
        },
        getValue : function() {
            return field.valueExt;
        },
        getValrep : function() {
            return field.valrep;
        },
        getId : function() {
            return field.fieldId;
        }
    };            
};


UNIFACE.luv.realizeField = function(a_occ, a_fldName, a_fldDef, a_fldData) {
    function addTriggersToProps()
    {
        a_fldDef.declaredProps.trigger = {};
        if (a_fldDef.triggers!==undefined)
        {
            var i;
            for (i in a_fldDef.triggers) if (a_fldDef.triggers.hasOwnProperty(i))
            {
                var l_triggerType = "UPDATE";
                if (a_fldDef.triggers[i].requesttype !== undefined)
                {
                    l_triggerType =  a_fldDef.triggers[i].requesttype.toUpperCase();
                }            
                a_fldDef.declaredProps.trigger[i] = l_triggerType;
            } 
        }
    }

    var l_field = a_occ.getChild(a_fldName);
    if (!l_field) {
        // Look up the placeholder in the nodemap.
        var containingOcc;
        var l_instance = a_occ.instance;
        var vName = UNIFACE.luv.constants.UFIELD_PREFIX + a_fldDef.nm;
        var l_el = l_instance.getElementById(vName);

        if (l_el) {
            // Found the field node's placeholder in the nodemap.
            // Now find the occurrence that contains it.
            // Generally that is a_occ, but not necessarily.
            var occ = a_occ;
            while (containingOcc === undefined && occ.firstNode && occ.lastNode) {
                if (occ.containsNode(l_el)) {
                    containingOcc = occ;
                    break;
                }
                if (!occ.entity || !occ.entity.occ) {
                    break;
                }
                occ = occ.entity.occ;
            }
            //var vSuffix = (containingOcc !== undefined ? containingOcc.postfix : ".0");
            var vSuffix = (containingOcc !== undefined ? containingOcc.postfix : a_occ.postfix);
            l_instance.addNode(vName, null);
            l_el.id = vName + "." + l_instance.instanceName + vSuffix;
            l_instance.addNode(vName + vSuffix, l_el);
        }
        if (l_el) {
            l_field =  new UNIFACE.luv.field( l_el.id, a_occ,  a_fldName, a_fldDef);
            l_field.instance = l_instance;
            if (a_occ == containingOcc) {
                // A proper child of the occurrence.
                a_occ.children[a_fldName] = l_field;
            } else {
                // A foster child for a_occ's entity.
                a_occ.entity.fosterChildren[a_fldName] = l_field;
            }
            if (l_field.widget) {
                // Get declarative properties
                if (!a_fldDef.declaredProps) {
                    // Get the widget default properties
                    a_fldDef.declaredProps = UNIFACE.luv.properties.normalizeProps(a_fldDef.properties);
                    // Merge with the properties from the field's DOM node.
                    a_fldDef.declaredProps.mergeWith(UNIFACE.luv.properties.normalizeProps(UNIFACE.luv.properties.getPropsFromDOMNode(l_el)));
                    addTriggersToProps(a_fldDef.declaredProps, a_fldDef.triggers);
                }
                l_field.setProperties(a_fldDef, a_fldData);
                l_field.widget.render(l_el);
                // Map the widget events to triggers.
                l_field.widget.mapEvents();
            } else {
                l_field = null;
            }
        } else {
            l_field = null;
        }
    } else {
        l_field.setProperties(a_fldDef, a_fldData);
    }
    if (l_field) {
        l_field.postRealize();
    }
    return l_field;
};
    
UNIFACE.luv.field.prototype.postRealize = function() {
    this.widget.setProperties();
    if (this.mergedProperties.uniface && this.mergedProperties.uniface.errormsg)
    {
        this.showError(this.mergedProperties.uniface.errormsg);         
    }

    // Give the widget a chance to 'mangle' the value during 'render'
    // This mangled value is used later to compare against a 'recent' value as presented by the widget.
    this.modValue = this.widgetValue = this.widget.getValue();
};

/**
 * Gets the currency for this field, expressed as an array whose elements each
 * specify an entity name and occurrence id.  The first array element identifies
 * the outermost occurrence; subsequent elements "zoom in" on the field.
 * @return The currency for this field.
 */
UNIFACE.luv.field.prototype.getCurrency = function() {
    var occ,
        occs = [];
    for (occ = this.occ; occ && occ.entity && occ.entity !== occ.entity.instance; occ = occ.entity.occ) {
            occs.unshift(occ);
    }
    return occs;
};

UNIFACE.luv.field.prototype.showBlock = function()
{
    this.unBlockedStyle = { html: { disabled : this.mergedProperties.html.disabled}, preStyle: { cursor : this.mergedProperties.preStyle.cursor } };
    this.mergedProperties.html.disabled = "true";
    this.mergedProperties.preStyle.cursor = "progress";
    if (this.widget)
    {   
        this.widget.setProperties();
    }
};

UNIFACE.luv.field.prototype.showUnblock = function()
{
    if (this.unBlockedStyle !== undefined)
{
        this.mergedProperties.html.disabled = this.unBlockedStyle.html.disabled;
        this.mergedProperties.preStyle.cursor = this.unBlockedStyle.preStyle.cursor;
    this.unBlockedStyle = undefined;
    if (this.widget)
    {   
        this.widget.setProperties();
        }
    }
};


    
UNIFACE.luv.overlayFieldProperties = function(a_fieldDef, a_newData, a_oldData) // field
{
    if (!a_newData) {
        return;
    }
    
    if ( typeof a_newData.properties !== "object" ) { 
        a_newData.properties = {};
    }
    
    if (!a_oldData) {
        a_oldData = {};
    }
                    
    if ( a_oldData.normalizedProps === undefined)
    {
        a_oldData.normalizedProps =  UNIFACE.luv.properties.normalizeProps(a_oldData.properties);
    }
    
    var l_onetime;
    for (l_onetime in UNIFACE.luv.constants.ONETIME_PROPS)
    {
        if (a_oldData.normalizedProps[l_onetime] !== undefined)
        {
            var l_prp;
            for (l_prp in UNIFACE.luv.constants.ONETIME_PROPS[l_onetime])
            {
                if (a_oldData.normalizedProps[l_onetime][l_prp] !== undefined)
                {                
                    delete a_oldData.normalizedProps[l_onetime][l_prp];
                }
            }
        }
    }
        
    // Overlay oldData's properties with newData's properties
    a_newData.normalizedProps = a_oldData.normalizedProps.overlayWith(a_newData.properties);
    
    if ( a_newData.valrep === undefined && a_oldData.valrep !== undefined ) {
        a_newData.valrep = a_oldData.valrep;
    }
};

///////////////////////////////////////////////////////////////////////////////
// UNIFACE.luv.label
///////////////////////////////////////////////////////////////////////////////

UNIFACE.luv.label = function(a_id, a_fldName, a_lblDef, a_occPostFix) {
    //var l_fldId = a_fldName + a_occPostFix;
    this.labelId = a_id;
    this.definition = a_lblDef;

    if (a_lblDef.widget)
    {
        this.widget = UNIFACE.createWidget(a_lblDef.widget, a_id, a_lblDef.properties);
        this.widget.callBack = this.createCallBack();
    }
};
    
UNIFACE.luv.label.prototype.unrealize = function() {
    if (this.widget) {
        this.widget.unrender();
    }
};

UNIFACE.luv.label.prototype.createCallBack = function() {
    var _empty = function() {};
    var label = this; // Create closure
    return {
            checkedValue : _empty,
            getProperties : _empty,
            getSyntax : _empty,
            bindEvent : _empty,
            getValue : function() {
                return label.definition.value;
            },
            getValrep : _empty,
            getId : function() {
                return label.labelId;
            }
    };
};
    
UNIFACE.luv.realizeLabel =  function(a_occ, a_fldName, a_lblDef) {
    var l_lblName = UNIFACE.luv.constants.ULABEL_PREFIX + a_fldName;
    var l_label = null;
	var l_instance = a_occ.instance;
        
    l_label = a_occ.children[l_lblName];
    if (!l_label) {
        // Get the default label widget (without occurrence postfix).
        var l_el = a_occ.instance.getElementById(l_lblName);
        if (l_el) {
            // Assign the id (including occurrence postfix) to the label widget.
            
            l_instance.addNode(l_lblName, null);
            l_el.id = l_lblName + "." + l_instance.instanceName + a_occ.postfix ;
            l_instance.addNode(l_lblName + a_occ.postfix, l_el);
            
            // Create the actual label.
            l_label = new UNIFACE.luv.label(l_el.id, a_fldName, a_lblDef, a_occ.postfix);
            // Administrate it as a child of a_occ.
            a_occ.children[l_lblName] = l_label;
            // Finally render the label.
            if (l_label.widget) {
                //Support for the accesskey depends on the widget implementation
                l_label.widget.setValue(a_lblDef.value);
                l_label.widget.render(l_el);
            }
        }
    }
};
    
///////////////////////////////////////////////////////////////////////////////
// UNIFACE.luv.occurrence
///////////////////////////////////////////////////////////////////////////////
        
UNIFACE.luv.occurrence = function(a_entity, a_occDef, postfix) {
    if (a_entity.instance === a_entity) {
        this.entity = null;
        this.postfix = "";
    } else {
        this.entity = a_entity;
        this.postfix = postfix;
    }
    this.instance = a_entity.instance;
    this.occID = null;
    this.status = null;
    this.children = {};
    this.occDef = a_occDef;
    this.firstNode = null;
    this.lastNode = null;
    this.realized = false;
    //this.postfix = postfix;
};

/**
 * Gets a named child (either a proper child or a fosterChild)
 * of this occurrence.
 * @param childName Name of the child
 * @return The child.
 */
UNIFACE.luv.occurrence.prototype.getChild = function(childName) {
    var child = this.children[childName];
    // If there is no proper child and this is the first occurrence then
    // the field might be a foster child.
    if (!child && this.entity && this.entity.fosterChildren && this === this.entity.occs[0]) {
        child = this.entity.fosterChildren[childName];
    }
    if (!child) {
        child = null;
    }
    return child;
};

/**
 * Calculates the index of this occurrence in its entity's list of occurrences.
 * @return Index of this occurrence.
 */
UNIFACE.luv.occurrence.prototype.getIndex = function() {
    // Find the index of the occurrence in its entity's list of occurrences.
    var occs = this.entity.occs;
    for (var i = 0; i < occs.length; i++) {
        if (this === occs[i]) {
            return i;
        }
    }
    return -1;
};

/**
 * Inserts this occurrence after a given occurrence in the list
 * of its entity's occurrences.
 * This occurrence and the supplied preceding occurrence should belong
 * to the same entity.
 * The preceding occurrence may be null, in which case this occurrence
 * is inserted at the front of its entity's list of occurrences.
 * @param precedingOcc Occurrence after which to insert this one.
 */
UNIFACE.luv.occurrence.prototype.moveAfter = function(precedingOcc) {
    UNIFACE.assert(!precedingOcc || this.entity === precedingOcc.entity, "Moving an occurrence to a different entity!");
    UNIFACE.assert(this !== precedingOcc, "Moving an occurrence after itself!");
    var myIndex = this.getIndex();
    var requiredIndex;
    var insertionPointNode;
    if (precedingOcc) {
        requiredIndex = precedingOcc.getIndex() + 1;
        if (precedingOcc.lastNode) {
            insertionPointNode = precedingOcc.lastNode.nextSibling;
        }
    } else {
        requiredIndex = 0;
        insertionPointNode = this.entity.occs[0].firstNode;
    }
    if (myIndex !== requiredIndex) {
        // Move this occurrence from its current location to
        // the the required location in its entity's occurrence list.
        myIndex = this.getIndex();
        this.entity.occs.splice(myIndex, 1);
        this.entity.occs.splice(requiredIndex, 0, this);
        // Move the occurrence nodes as well.
        if (insertionPointNode) {
            var node = this.firstNode;
            var lastNode = this.lastNode;
            var parentNode = node.parentNode;
            while (node) {
                parentNode.insertBefore(node, insertionPointNode);
                if (node != lastNode) {
                node = node.nextSibling;
                } else {
                    node = null;
                }
            }
        } else {
            UNIFACE.assert(this.firstNode == null, "Moving an occurrence after one without nodes!"); //pragma(allow-loose-compare)
        }
    }
};

/**
 * Visits all non-text nodes that are associated with this occurrence
 * and calls the nodeAction on each of them.
 * @param nodeAction Action to apply to the nodes
 */
UNIFACE.luv.occurrence.prototype.visitNodes = function(nodeAction) {
    if (this.firstNode && this.lastNode && this.firstNode.parentNode && this.firstNode.parentNode ===  this.lastNode.parentNode) {
        var l_node =  this.firstNode;
        while (l_node !==  this.lastNode.nextSibling) {
            if (l_node.nodeType !== 3) {
                nodeAction(l_node);
            }
            l_node = l_node.nextSibling;
        }
    }
};

/**
 * Visits all of this occurrence's children (including fosterChildren
 * if it has them), and performs the childAction on each of them.
 * @param childAction Action to apply to the children
 */
UNIFACE.luv.occurrence.prototype.visitAllChildren = function(childAction) {
    this.visitOwnChildren(childAction);
    if (this.entity && this === this.entity.occs[0] && this.entity.fosterChildren) {
        var childName,
            fosterChildren = this.entity.fosterChildren;
        for (childName in fosterChildren) if (fosterChildren.hasOwnProperty(childName)) {
            childAction(fosterChildren[childName], childName);
        }
    }
};

/**
 * Visits this occurrence's own children (so, excluding any fosterChildren)
 * and performs the childAction on each of them.
 * @param childAction Action to apply to the children
 */
UNIFACE.luv.occurrence.prototype.visitOwnChildren = function(childAction) {
    var childName;
    for (childName in this.children) if (this.children.hasOwnProperty(childName)) {
        childAction(this.children[childName], childName);
    }
};

UNIFACE.luv.occurrence.prototype.makeVisible = function() {
    if (!this.realized) {
        var makeNodeVisible = function (n) {
                if (n.U_display !== undefined) {
                    n.style.display = n.U_display;
                    n.U_display = null;
                }
            };
        this.visitNodes(makeNodeVisible);
        this.realized = true;
    }
    // TODO?
    // At this point we could apply properties to the occurrence nodes,
    // for occurrence coloring.
};

UNIFACE.luv.occurrence.prototype.makeInvisible = function() {
    if (this.realized) {
        var makeNodeInvisible = function(n) {
                n.U_display = n.style.display;
                n.style.display = "none";
            };
        this.visitNodes(makeNodeInvisible);
        this.realized = false;
    }
};

/*
Recursively update the status (mod, est, ...) of a realized occurrence.
Not necessary for invisible occurrences (?) since their is no way to change their status (yet)
TODO: when an API is available, traverse all occurrences, not just realized ones. 
This is done before a request is fired to determine the proper input/output scopes
(i.e. properly resolve the $mod keyword in a scope definition)
*/
UNIFACE.luv.occurrence.prototype.UpdateStatus = function(a_occData)
{
    var mod = false,
        childrenMod = false;
    var childAction = function(child, childName) {
        if (child.UpdateStatus !== undefined) {
            childrenMod = child.UpdateStatus(a_occData[childName]) || childrenMod;
        } else if (child.isModified !== undefined) {
            mod = child.isModified()  || mod;
            var l_val = child.checkedValue();
            if (!l_val.error) {
                a_occData[childName].value = l_val.normalizedValue;
            }
        }
    };
    this.visitAllChildren(childAction);
       
    if ( a_occData.status != null) /* pragma(allow-loose-compare) */
    {
        switch (a_occData.status.toLowerCase())
        {
            case "est":
                a_occData.status = mod ? "mod" : "est"; //cpProp("status");
                break;

            case "empty":
                a_occData.status = (mod || childrenMod) ? "new" : "empty"; //cpProp("status");
                break;
         }
    }
    return a_occData.status === "mod";
};

/*
 No visualization for blocked occurrences yet.
*/
UNIFACE.luv.occurrence.prototype.showBlock = function()
{
};

/*
 No visualization for blocked occurrences yet.
*/
UNIFACE.luv.occurrence.prototype.showUnblock = function()
{
};


UNIFACE.luv.occurrence.prototype.unrealize = function() {
    if (this.realized) {
        this.visitOwnChildren(function(child) { child.unrealize(); } );
        this.makeInvisible();
    }
};
        
UNIFACE.luv.realizeOccurrence = function(a_entity, a_occData, precedingOcc, predefinedID) {
    var forceRealization = false;
    var occID = null;
    if (predefinedID !== undefined) {
        occID = predefinedID;
    } else if (a_occData && a_occData.id) {
        occID = a_occData.id;
    }
    var occ = a_entity.getOccByID(occID);
    if (occ && occ.entity === a_entity) {
        // Move occ to be after precedingOcc.
        occ.moveAfter(precedingOcc);
    } else {
        // Create a new occurrence.
        occ = a_entity.instance.getNewOccurrence(a_entity, occID, precedingOcc);
        // Make sure it gets realized.
        forceRealization = true;
    }
    // Realize the occurrence, if there is data for it.
    occ.data=a_occData;
    
    if (a_occData) {
        occ.realize(a_occData, forceRealization);
    }
        
    return occ;
};
        
UNIFACE.luv.occurrence.prototype.realize = function(a_occData, a_forceRealization) {
    // Realize all of the occurrence's contents.
    if (a_occData) {
        this.realizeContent(a_occData, a_forceRealization);
    }
    // Make the occurrence visible.
    this.makeVisible();
};

UNIFACE.luv.occurrence.prototype.realizeContent = function(a_occData, forceRealization) {
    // Realization is required if caller says so, or if the supplied
    // occurrence data is 'dirty', which is an indication that the
    // occurrence data needs to be re-realized.
    var realizeThisOccurrence = forceRealization || (a_occData && !!a_occData.dirty);
        
    // Update occ status for new data
    if (a_occData && a_occData.status != null) { // pragma(allow-loose-compare)
        this.status = a_occData.status;
    }

    // Loop through the content of this occurrence.    
    var occDef = this.occDef;
    var l_name;
    for (var l_childName in occDef) {
        if (typeof occDef[l_childName].type === "string") {
            var l_childDef = occDef[l_childName],
                l_childData = null;
            if (a_occData && a_occData[l_childName] !== undefined ) {
                l_childData = a_occData[l_childName];
            }
            if (l_childDef.type === "entity") {
                UNIFACE.luv.realizeEntity(this, l_childName, l_childDef, l_childData, forceRealization);
            } else if (realizeThisOccurrence) {
                if (l_childDef.type === "field") {
                    UNIFACE.luv.realizeField(this, l_childName, l_childDef, l_childData);
                    if (l_childDef.label) {
                        // Realize the label that is associated with the field.
                        l_name = occDef[l_childName].nm;
                        if (!l_name) {
                            l_name = l_childName;
                        }
                        UNIFACE.luv.realizeLabel(this, l_name, l_childDef.label);
                    }
                } else if (l_childDef.type === "label") {
                    // Realize an unassociated label.
                    l_name = occDef[l_childName].nm;
                    if (!l_name) {
                        l_name = l_childName;
                    }
                    UNIFACE.luv.realizeLabel(this, l_name, l_childDef);
                }
            }
        }
    }
    // Reset the 'dirty' flag, to make sure that next time
    // this occurrence is not realized unnecessarily. 
    a_occData.dirty = false;
};
        
/**
 * Removes this occurrence.
 * This occurrence is first unrealized and removed from the occurrence
 * administration.  Then is is moved to the occurrence pool, unless it
 * is the one and only occurrence of its containing entity.  In the
 * latter case it should remain where it is, for two reasons:
 *      - It needs to stay, because it indicates where new occurrences
 *        should be added.
 *      - Removing it might result in an invalid tree (like an HTML
 *        table without any rows).
 */
UNIFACE.luv.occurrence.prototype.remove = function() {
    var i,
        removeAction = function(child) {
           // We assume here that a childwith an "occs" property indicates an inner entity.
            // TODO: a better way of determining this?
            if (child.hasOwnProperty("occs")) {
                for (var j = child.occs.length - 1; j >= 0; --j) {
                    child.occs[j].remove();
                }
            }
        };
    // First remove all inner occurrences!
    this.visitOwnChildren(removeAction);
    // Take care that this occurrence is no longer shown in the page.
    this.unrealize();
    // Remove this occurrence.
    this.instance.removeOccurrence(this);
};

/**
 * Checks whether a given node is among the tree of nodes that make
 * up this occurrence.
 * @param node Node to check
 * @return <code>true</code> if and only if node is among the tree
 *      of nodes that make up this occurrence.
 */
UNIFACE.luv.occurrence.prototype.containsNode = function(node) {
    var myNodes = [];
    var myNodeCount = 0;
    for (var myNode = this.firstNode; myNode !== this.lastNode.nextSibling; myNode = myNode.nextSibling) {
        if (myNode.nodeType === 1) {
            myNodes[myNodeCount++] = myNode;
        }
    }
    // See if the node or any of its ancestors is among myNodes.
    while (node) {
        for (var i = 0; i < myNodeCount; i++) {
            if (node === myNodes[i]) {
                return true;
            }
        }
        // Go on, to check the node's parent node.
        node = node.parentNode;
    }
    return false;
};

UNIFACE.luv.overlayOccurrenceProperties = function(a_occDef, a_newData, a_oldData)  //occ
{
    var l_child;
    if (!a_newData) {
        return;
    }

    // If the data does not specify whether it is 'dirty', then assume it is.
    if (a_newData.dirty === undefined) {
        a_newData.dirty = true;
    }

    a_newData.dirty = true;
    for (l_child in a_occDef)
    {
        if (typeof a_occDef[l_child].type === "string")
        {
            var l_fldDef = a_occDef[l_child];
            
            var l_newData = a_newData[l_child];
            var l_oldData = (!a_oldData ? null : a_oldData[l_child]);
            
            if (l_newData !== undefined)
            {
                if (l_fldDef.type === "entity")
                {
                    UNIFACE.luv.overlayEntityProperties( l_fldDef, l_newData, l_oldData);
                }
                else if (l_fldDef.type === "field")
                {
                    UNIFACE.luv.overlayFieldProperties( l_fldDef, l_newData, l_oldData);
                }
            }
        }
    }
};

///////////////////////////////////////////////////////////////////////////////
// UNIFACE.luv.occurrenceContainer
///////////////////////////////////////////////////////////////////////////////

UNIFACE.luv.occurrenceContainer = function() {

    // The occurrence administration:
    var occMap = {};
    /**
     * Registers an occurrence.
     * @param occ Occurrence to be registered.
     */
    this.registerOcc = function(occ) {
        if (occ && occ.occID) {
            UNIFACE.assert(occ.entity === this, "Registering an occurrence with a container that is not its own!");
            occMap[occ.occID] = occ;
        }
    };
    /**
     * Unregisters an occurrence.
     * @param occ Occurrence to be unregistered.
     */
    this.unregisterOcc = function(occ) {
        if (occ) {
            UNIFACE.assert(occ.entity === this, "Unregistering an occurrence with a container that is not its own!");
            delete occMap[occ.occID];
        }
    };
    /**
     * Gets an occurrence given an occurrence ID.
     * @param occID ID of the wanted occurrence.
     * @return The wanted occurrence, or <code>null</code> if there was
     *      no occurrence registered with the specified ID.
     */
    this.getOccByID = function(occID) {
        return occMap[occID];
    };
};

///////////////////////////////////////////////////////////////////////////////
// UNIFACE.luv.entity
///////////////////////////////////////////////////////////////////////////////

UNIFACE.luv.entity = function(a_occ, a_entityName, a_entityDef)    {
    a_occ.children[a_entityName] = this;
    this.occ = a_occ;
    this.occs = [];
    this.name = a_entityName;
    this.instance = a_occ.instance;
    this.entDef = a_entityDef;
    this.placeHolders = null;
    this.parentNode = null;
    this.firstNode = null;
    this.lastNode = null;
    this.minOccurs = 0;
    this.maxOccurs = "unbounded";
    this.fosterChildren = {};
    this.postfix = (a_occ ? a_occ.postfix : "");
    
    if (a_entityDef.minOccurs !== undefined)
    {
        this.minOccurs = a_entityDef.minOccurs;
    }
    
    if (a_entityDef.maxOccurs !== undefined)
    {
        this.maxOccurs = a_entityDef.maxOccurs;
    }

    UNIFACE.luv.occurrenceContainer.call(this);
};

UNIFACE.luv.entity.prototype.findPlaceHolders = function(anOccSuffix)
{
    if (this.hasNoPlaceholders) {
        return;
    }
    if (!this.placeHolders)
    {
        var l_name = this.entDef.nm;
        var l_occStart = this.instance.getElementById("uocc:" + l_name);
        var l_occEnd = l_occStart;
        if (!l_occStart)
        {
            l_occStart = this.instance.getElementById("uocs:" + l_name);
            l_occEnd = this.instance.getElementById("uoce:" + l_name);
        }
        if (l_occStart && ! (l_occEnd && (l_occStart.parentNode === l_occEnd.parentNode)) )
        {
            l_occEnd = l_occStart;
        }
        if (l_occStart)
        {
        	if (false) { // 2009-04-23
				this.instance.addNode(l_occStart.id, null);
				l_occStart.id += anOccSuffix;
				this.instance.addNode(l_occStart.id, l_occStart);
				if ( l_occEnd !== l_occStart ) {
					this.instance.addNode(l_occEnd.id, null);
					l_occEnd.id += anOccSuffix;
					this.instance.addNode(l_occEnd.id, l_occEnd);
				}
        	}

            this.parentNode = l_occStart.parentNode;
            this.firstNode = l_occStart;
            
            this.lastNode = l_occEnd;
            var l_ph = l_occStart;
            this.placeHolders = [];
            while (l_ph !== l_occEnd.nextSibling)
            {
                var l_newNode = l_ph.cloneNode(true);
                if (l_newNode.nodeType !== 3) { // If not a text node...
                    l_newNode.U_display = l_newNode.style.display;
                    l_newNode.style.display = "none";
                }
                this.placeHolders.push(l_newNode );
                l_ph = l_ph.nextSibling;
            }
        } else {
            this.hasNoPlaceholders = true;
        }
    }
};

UNIFACE.luv.entity.prototype.calcLastNode = function(a_nextSibling) {
    if (a_nextSibling)
    {
        this.lastNode = a_nextSibling.previousSibling;
    }
    else if (this.parentNode)
    {
        this.lastNode = this.parentNode.lastChild;
    }
    else
    {
        this.lastNode = null;
    }
};

/*
Recursively update the status (mod, est, ...) of a realized entity.
Not necessary for invisible entity (?) since their is no way to change their status (yet)
TODO: when an API is available, traverse all occurrences, not just realized ones. 
This is done before a request is fired to determine the proper input/output scopes
(i.e. properly resolve the $mod keyword in a scope definition)
*/
UNIFACE.luv.entity.prototype.UpdateStatus = function(a_entData)
{
    var i;
    var l_mod = false;

    for (i = 0; (i< this.occs.length) && this.occs[i].realized; i++)
    {
        l_mod = this.occs[i].UpdateStatus(a_entData.occs[this.occs[i].dataIdx]) || l_mod;
    }
    return l_mod;
};


UNIFACE.luv.entity.prototype.unrealize = function() {
    for (var i =0; i < this.occs.length; i++) {
        this.occs[i].remove();
    }
};

UNIFACE.luv.realizeEntity = function(a_occ, a_entityName, a_entityDef, entityData)
    {
    var lEntity = a_occ.children[a_entityName];
    if (!lEntity) {
        // Create a new entity object.
        lEntity = new UNIFACE.luv.entity(a_occ, a_entityName, a_entityDef);
        // Get the default entity placeholder.
        var l_entityName = UNIFACE.luv.constants.UENTITY_PREFIX + a_entityDef.nm;
        var l_el = lEntity.instance.getElementById(l_entityName);
        if (l_el) {
            // Assign the entity ID to the element.
            lEntity.instance.addNode(l_entityName, null);
            l_el.id = l_entityName + "." + lEntity.instance.instanceName + a_occ.postfix;
            lEntity.instance.addNode(l_entityName + a_occ.postfix, l_el);
        }
    }           
    lEntity.realize(entityData);
};
                
UNIFACE.luv.entity.prototype.realize = function(a_entityData) {
    this.data = a_entityData;
    var l_occs = this.occs;
        
    var l_minOccurs = parseInt(this.minOccurs,10);
    if (isNaN(l_minOccurs) || !l_minOccurs) // defaults to 1, at least 1
    {
        l_minOccurs = 1;
    }
        
    var l_lastOcc = l_minOccurs;
        
    if (a_entityData && l_lastOcc < a_entityData.occs.length )
    {
        l_lastOcc = a_entityData.occs.length;
    }
        
    var l_maxOccurs = parseInt(this.maxOccurs,10);
    if (isNaN(l_maxOccurs) || !l_maxOccurs)
    {
        l_maxOccurs = l_lastOcc;
    }
                
                    
    if (a_entityData)
    {
        a_entityData.idMap = {};
    }

    // At this point this realized entity has a number of realized occurrences.
    // a_entityData contains data for some of those realized occurrences.
    // It also contains data for some new occurrences.
    // There may also be realized occurrences for which there is *no* data
    // in a_entityData.
    // 
    // First we'll remove, from the currently available realized occurrences,
    // the ones for which a_entityData contains no data.
    var j;
    // Get a map with available realized occurrences.
    var realizedOccs = {};
    for (j = 0; j < l_occs.length; j++) {
        if (l_occs[j].realized) {
            realizedOccs[l_occs[j].occID] = l_occs[j];
        }
    }
    // Get a map with the data for new occurrences.
    var newOccData = {};
    if (a_entityData) {
        for (j = 0; j < a_entityData.occs.length; j++) {
            var occData = a_entityData.occs[j];
            newOccData[occData.id] = occData;
        }
    }
    // Remove the realized occurrences for which there is no new data.
    // Also remove the ones whose data has status "del".
    // Also remove the ones that belong to a different entity (this
    // should not occur, ordinarily).
    for (var occID in realizedOccs) if (realizedOccs.hasOwnProperty(occID)) {
        if (newOccData[occID] === undefined ||
            newOccData[occID].status === "del" ||
            realizedOccs[occID].entity != this) {
            realizedOccs[occID].remove();
        }
    }
    
    // At this point the realized occurrences of this entity all have
    // some (new) data in a_entityData.  a_entityData may also contain
    // data for occurrences that have not been realized yet.

    // 1. Filled occurrences & empty occurrences
    var l_occIdx = 0;   // Index in the data source (includes deleted occurrences)
    var i = 0;          // Index in the list of visible occurrences
    var l_occData;      // Occurrence data source being handled inside the loop.
    var l_occ;          // Realized occurrence, inside the loop.
    var prevDataID;     // ID of the occurrence data that was handled most recently in the loop.
    var prevRealizedOcc = null; // Realized occurrence that was handled most recently in the loop.
    while (i < l_minOccurs || (i < l_maxOccurs && a_entityData && l_occIdx < l_lastOcc ) ) {
        // Do not show deleted occurrences
        if (!a_entityData || l_occIdx >= a_entityData.occs.length || a_entityData.occs[l_occIdx].status !== "del") {
            l_occData = null;
            if (a_entityData && l_occIdx < a_entityData.occs.length) {
                l_occData = a_entityData.occs[l_occIdx];
                if (typeof l_occData.status === "string" && l_occData.status === "empty") {
                    a_entityData.idMap[UNIFACE.luv.constants.EMPTY_OCC_ID] = l_occData;
                } else if (typeof l_occData.id === "string" && l_occData.id) {
                    a_entityData.idMap[l_occData.id] = l_occData;
                }
            }
            l_occ = UNIFACE.luv.realizeOccurrence(this, l_occData, prevRealizedOcc);
            if (l_occData) {
                l_occ.dataIdx = l_occIdx;   // Map this visible occurrence to the data source
            } else {
                l_occ.dataIdx = null;       // Empty occurrence (minOccurs), so there is no index in the data source....
            }
            i++;
            prevRealizedOcc = l_occ;
        }
        l_occIdx++;
    }
        
        // 2. Occurrences that need to be deleted
    while (i < l_occs.length) {
        l_occs[i].remove();
    }
};

UNIFACE.luv.overlayEntityProperties = function(a_entityDef, a_newData, a_oldData)  //entity
{
    if (!a_newData) {
        return;
    }
    var i =0;
    var l_idMap = ( !a_oldData || !a_oldData.idMap ? {} : a_oldData.idMap );
    var l_newOccs = a_newData.occs;
    if (typeof l_idMap === "object" && l_newOccs !== undefined && l_newOccs )
    {
        var l_lastOcc = a_newData.occs.length;

        for (i = 0; i<l_lastOcc; i++)
        {
            if (l_newOccs[i] !== undefined)
            { 
                var l_oldOcc;
                if (typeof l_newOccs[i].status === "string" && l_newOccs[i].status === "empty")
                {
                    l_oldOcc = l_idMap[UNIFACE.luv.constants.EMPTY_OCC_ID];
                }
                else
                {
                    l_oldOcc = l_idMap[l_newOccs[i].id];
                }
                UNIFACE.luv.overlayOccurrenceProperties(a_entityDef.occs, l_newOccs[i], l_oldOcc);
            }
        }
    }
};


///////////////////////////////////////////////////////////////////////////////
// UNIFACE.luv.entityadmin
///////////////////////////////////////////////////////////////////////////////
/**
 * UNIFACE.luv.entityadmin is a class for the administration of entities and
 * their occurrences.
 * The class is abstract, in the sense that subclasses need to define
 * functions getEntityAdminName() and getPseudoOccID().
 */
UNIFACE.luv.entityadmin = function() {

    // The entity handlers, for handling individual entities.    
    this.entityHandlers = {};
};

/**
 * Returns a name to be used in places where an entity name is required
 * but not available. The returned name should be distinguishable from
 * real entity names. 
 * @return A string denoting a pseudo-entity name.
 */
UNIFACE.luv.entityadmin.prototype.getEntityAdminName = function() {
    UNIFACE.throwException("Unimplemented abstract function getEntityAdminName() was called.");
};

/**
 * Returns an ID to be used in places where an occurrence ID is required
 * but not available. 
 * @return A string denoting a pseudo-entity's occurrence ID.
 */
UNIFACE.luv.entityadmin.prototype.getPseudoOccID = function() {
    UNIFACE.throwException("Unimplemented abstract function getPseudoOccID() was called.");
};

/**
 * Adds entityhandlers for all entities occurring in a given
 * definition structure.
 * @param structure Entity definition structure (as in the 'webdefinitions'
 *          sense), generally nested.
 */
UNIFACE.luv.entityadmin.prototype.addEntityHandlers = function(structure) {
    for (var name in structure) {
        if (structure.hasOwnProperty(name)) {
            var item = structure[name];
            if (typeof item === "object" && item.type === "entity") {
                this.addEntityHandler(item, name);
            }
        }
    }
};

/**
 * Creates an entityhandler for a named entity.
 * @param name Name of the entity for which to create an entityhandler.
 * @param structure Entity structure (as in the 'webdefinitions' sense),
 *          generally nested.
 */
UNIFACE.luv.entityadmin.prototype.addEntityHandler = function(structure, name) {
    if (name === undefined) {
        name = this.getEntityAdminName();
    }
    this.entityHandlers[name] = new UNIFACE.luv.entityhandler(name, structure);
    this.addEntityHandlers(structure.occs);  // Recurse deeper into the structure
};

/**
 * Gets a new occurrence for a given entity object, either by reusing
 * an occurrence from the pool or by creating a new one.
 * @param entity The entity for which to get a new occurrence.
 * @param occID The id for the new occurrence.
 * @param precedingOcc The occurrence that is to precede the new one
 *          (null means that the new occurrence should be the first).
 * @return The new occurrence.
 */
UNIFACE.luv.entityadmin.prototype.getNewOccurrence = function(entity, occID, precedingOcc) {
    var occ = null;
    var entityName = entity.name;
    if (entityName === undefined) {
        entityName = this.getEntityAdminName();
    }
    var entityHandler = this.entityHandlers[entityName];
    if (entityHandler) {
        occ = entityHandler.getNewOccurrence(entity, occID, precedingOcc);
        // Register the occurrence in the occurrence administration.
        occ.entity.registerOcc(occ);
    }
    return occ;
};

/**
 * Removes a given occurrence for a given entity object, either by reusing
 * an occurrence from the pool or by creating a new one.
 * @param entity The entity for which to create a new occurrence.
 */
UNIFACE.luv.entityadmin.prototype.removeOccurrence = function(occ) {
    // Remove the occurrence from the occurrence administration.
    occ.entity.unregisterOcc(occ);
    // If the occurrence is not the only one in the list of
    // its entity's occurrences then remove it from that list
    // and move it to the occurrence pool.
    var occs = occ.entity.occs;
    if (occs.length > 1) {
        // Find the index of the occurrence in its entity's list of occurrences.
        var i = occ.getIndex();
        // Move the removed occurrence to the entity's occurrence pool.
        var entityHandler = this.entityHandlers[occ.entity.name];
        if (entityHandler) {
            entityHandler.moveToOccPool(occ);
        }
        // Remove the reference to the removed occurrence
        // from the entity's occurrence list.
        occs.splice(i,1);
    }
    // For debugging:
    occ.occID = "--Not-in-use--";
};

///////////////////////////////////////////////////////////////////////////////
// UNIFACE.luv.entityhandler
///////////////////////////////////////////////////////////////////////////////
/**
 * UNIFACE.luv.entityhandler is an entity-specific class for creating
 * occurrences, as well as removing them and keeping them for reuse.
 * @param name Name of the entity that the entityhandler will handle.
 * @param structure Structure of the entity.
 */
UNIFACE.luv.entityhandler = function(name, structure) {
    this.name = name;
    this.structure = structure;
    this.spareOccurrences = [];
    this.occCounter = 1;
};

/**
 * Moves an occurrence to this entityhandler's pool.
 * @param occ The occurrence to move to the pool.
 */
UNIFACE.luv.entityhandler.prototype.moveToOccPool = function(occ) {
    // An array of nodes to remember.
    var nodeArray = [];
    // Move all of the occurrence's nodes to the nodeArray,
    // starting with the firstNode up to and including the lastNode.
    var node = occ.firstNode;
    if (node) {
        var nextNode;
        var parentNode = node.parentNode;
        var endNode = occ.lastNode.nextSibling;
        while (node !== endNode) {
            nextNode = node.nextSibling;
            nodeArray.push(node);
            parentNode.removeChild(node);
            node = nextNode;
        }
    }
    // Store a spare-occurrence in the pool.
    var spareOcc = {
         "occ": occ,
         "nodes": nodeArray
    };
    this.spareOccurrences.push(spareOcc);
};

/**
 * Creates a new occurrence for a given entity object and adds it
 * to the end of the entity's occurrence array.
 * @param entity The entity object for which to create a new occurrence.
 * @param requestedIndex Index in the entity's occurrence list at which to
 *          create the new occurrence.
 * @return The new occurrence.
 */
UNIFACE.luv.entityhandler.prototype.createOcc = function(entity, requestedIndex) {
    var newOcc = new UNIFACE.luv.occurrence(entity, this.structure.occs, "." + this.occCounter++);
    this.insertOcc(entity, newOcc, requestedIndex);
    return newOcc;
};

/**
 * Inserts an occurrence in an entity's occurrence list at the requested index.
 * @param entity The entity object to whose occurrence list to insert an occurrence.
 * @param occ The occurrence to be inserted.
 * @param requestedIndex The index in the entity's occurrence list at which to
 *          insert the new occurrence.
 */
UNIFACE.luv.entityhandler.prototype.insertOcc = function(entity, occ, requestedIndex) {
    var occs = entity.occs;
    var occsCount = occs.length;
    UNIFACE.assert(!requestedIndex || requestedIndex <= occsCount, "Inserting an occurrence beyond the last index.");
    if (requestedIndex === occsCount) {
        occs[requestedIndex] = occ;
    } else {
        occs.splice(requestedIndex, 0, occ);
    }
};

/**
 * Gets a new occurrence for a given entity object, either by reusing
 * an occurrence from the pool or by creating a new one.
 * @param entity The entity for which to create a new occurrence.
 * @param occID The ID for the new occurrence.
 * @param precedingOcc The occurrence that is to precede the new one
 *          (null means that the new occurrence should be the first).
 */
UNIFACE.luv.entityhandler.prototype.getNewOccurrence = function(entity, occID, precedingOcc) {
    var occ = null;
    var isNewOcc = false;
    var i;
    if (!entity.placeHolders) {
        if (entity.hasNoPlaceholders === true) {
            // An earlier search for placeholders had no result.
            // Therefore it is clear that there is no occurrence repetition
            // for the entity, which means that the entity's single occurrence
            // should be reused.
            if (entity.occs.length > 0) {
                occ = entity.occs[0];
                // If the existing occurrence has a different occID
                // then that old occurrence should be unregistered.
                if (occ.occID !== occID) {
                    occ.entity.unregisterOcc(occ);
                }
            }
        } else {
            // No real occurrences exist yet for the entity.
            // Find the default occurrence placeholder(s); they will
            // be used as the placeholders for the first actual occurrence.
            occ = this.createOcc(entity, 0);

            if (typeof entity.findPlaceHolders === "function") {
                entity.findPlaceHolders(occ.postfix);
            }
            //occ = this.createOcc(entity, 0);
            isNewOcc = true;
            // PrecedingOcc should be null, here, because there are no occurrences yet.
            UNIFACE.assert(!precedingOcc, "Preceding occ is not null while creating the first occurrence!");
        }
    } else  if (entity.occs.length === 1 && !entity.occs[0].realized) {
        // If the entity has only one occurrence which is not realized,
        // then *that* occurrence can be used.
        // Simply return it.
        occ = entity.occs[0];
        // PrecedingOcc should be null, here, because there are no occurrences yet.
        UNIFACE.assert(!precedingOcc, "Preceding occ is not null while creating the first occurrence!");
    } else {
        var l_nextSibling;
        var l_index;
        if (!precedingOcc) {
            l_index = 0;
            // Make l_nextSibling the first node of the first occurrence.
            l_nextSibling = entity.occs[0].firstNode;
        } else {
            l_index = precedingOcc.getIndex() + 1;
            // Make l_nextSibling the node that follows the last node of the preceding occ.
            l_nextSibling = precedingOcc.lastNode.nextSibling;
        }
        var parentNode = entity.parentNode;
        // If there are spare occurrences then use one of those.
        if (this.spareOccurrences.length > 0) {
            var spare = this.spareOccurrences.pop();
            var nodeArray = spare.nodes;
            // Insert the occNodes before the next sibling.
            for (i = 0; i < nodeArray.length; i++) {
                parentNode.insertBefore(nodeArray[i], l_nextSibling);
            }
            occ = spare.occ;
            // Insert the occurrence at the expected location in the entity's occurrence list.
            this.insertOcc(entity, occ, l_index);
        } else {
            // There are no spare occurrences.
            // Clone the placeholders to make a new occurrence in the DOM.
            for (i = 0; i < entity.placeHolders.length; i++) {
                var l_node = entity.placeHolders[i].cloneNode(true);
                entity.instance.createNodeMap(l_node);
                if (i === 0) {
                    entity.firstNode = l_node;
                }
                entity.lastNode = l_node;
                if (l_node.nodeType !== 3) { // If not a text node...
                    l_node.U_display = entity.placeHolders[i].U_display;
                }
                parentNode.insertBefore(l_node, l_nextSibling);
            }
            // Also create a new occurrence object.
            occ = this.createOcc(entity, l_index);
            isNewOcc = true;
        }
    }
    if (occ !== null) {
        if (isNewOcc) {
            // This is a new occurrence.
            // Make sure the occurrence knows its first and last nodes.
            occ.firstNode = entity.firstNode;
            occ.lastNode = entity.lastNode;
            // Set the IDs of the first and last nodes.
            if (entity.firstNode) {
            	//occ.instance.addNode()
                occ.firstNode.id = occ.firstNode.id + occ.postfix;
            }
            if (entity.lastNode && entity.lastNode !== entity.firstNode) {
                occ.lastNode.id = occ.lastNode.id + occ.postfix;
            }
        }
        // Make sure the occurrence knows its entity.
        occ.entity = entity;
        // Set the occurrence id.
        occ.occID = occID;
    }
    return occ;
};

///////////////////////////////////////////////////////////////////////////////
// UNIFACE.luv.component
///////////////////////////////////////////////////////////////////////////////

UNIFACE.dspDefs = {};

UNIFACE.luv.getDspDef = function(aDspName)
{
    if (typeof UNIFACE.dspDefs[aDspName] !== "object")
    {
        UNIFACE.dspDefs[aDspName] = {
        	def : null,
        	layout : null
        };
    }
    return UNIFACE.dspDefs[aDspName];
};

UNIFACE.luv.getComponent = function(a_name, aDspName)
{
    if (typeof UNIFACE.components[a_name] !== "object")
    {
        UNIFACE.addComponent(new UNIFACE.luv.component( a_name, aDspName));
    }
    return UNIFACE.components[a_name];
};

UNIFACE.luv.component = function(a_name, aDspName)
{
    function _fire(listeners) {
        for ( var i = 0; i < listeners.length; i++ ) {
            listeners[i]();
        }
    }
     
    var onUpdateListeners = [];
    
    this.addOnUpdateListener = function(aListener) {
        onUpdateListeners.push(aListener);
    };

    this.fireOnUpdate = function() {
        _fire(onUpdateListeners);
    };

    UNIFACE.luv.entityadmin.apply(this, arguments);
	
	this.componentName = aDspName;

    // The following seemingly strangely named attributes allow the component to act
    // as if it were an entity (this one containing one occurrence).
    // The component's real entities are inner-entities of this single occurrence.
    this.instance = this;
    
    this.occs = [];
    this.postfix = "";
    
    var nodeMap = {};
    this.addNode = function(anId, aNode)
	{
		nodeMap[anId] = aNode;
	};
    this.getElementById = function(anId)
	{
		return nodeMap[anId];
	};
    
    this.instanceName = a_name;
    this.data = null;
    this.title = "";
    
    this.setLayout = function(a_layout, a_targetNode)
    {
        this.layout = a_layout;
        if (a_targetNode == "body")
        {
            this.targetNode = document.body;  
        }
        if (this.targetNode === undefined)
        {
            this.createTargetNode();
    		this.targetNode.innerHTML = a_layout;
        }
        this.createNodeMap(this.targetNode); 
        
        if (this.widget != null && this.widget.setLayout!=undefined) /* pragma(allow-loose-compare) */
        {
            this.widget.setLayout(this);
        }
        this.render();       
    };
    
    this.define = function(a_newStructure)
    {
        this.definition = a_newStructure;
        // Remember the component name.
        if (typeof this.definition.componentname === "string")
        {
            this.componentName = this.definition.componentname;
        }
        // Traverse the structure making sure everything's got a "nm" attribute.
        this.ensureNames(this.definition);
        // Add an entity handler for the pseudo-entity that this component is.
        this.addEntityHandler( { "type" : "entity", "occs" : this.definition} );
        // It may be the case that data was supplied to this component
        // before the data structure was defined (that is: the 'render' function
        // was called before the 'define' function).
        // In that case the render has not been able to do its job completely.
        // Therefore it is called here again (without arguments).
        this.render();
    };

    this.ensureNames = function(aStructure) {
        if (aStructure) {
            var c, child;
            for (c in aStructure) if (aStructure.hasOwnProperty(c)) {
                child = aStructure[c];
                if (child.componentName !== undefined || child.type === "entity" || child.type === "field") {
                    if (!child.nm) {
                        child.nm = c;
                    }
                    if (child.type === "entity") {
                        this.ensureNames(child.occs);
                    }
                }
            }
        }
    };        
    this.render = function(a_occData)
    {
        // Get the old data (could be null).
        var l_oldDat = this.data;
        // Replace the component's data with the new data. 
        if (a_occData) {
            this.data = a_occData;
            }
        if (this.data && this.definition && this.targetNode && (this.layout!==undefined)) {
            UNIFACE.luv.overlayOccurrenceProperties(this.definition, this.data, l_oldDat);
            // Realize the single occurrence of the 'pseudo-entity' that this component is.
            UNIFACE.luv.realizeOccurrence(this, this.data, null, this.getPseudoOccID());
            // Make the framework aware of the update.
            this.fireOnUpdate();
        }
    };
    
    var wNameMap;
    this.buildWidgetMap = function() 
    {
        var compName = this.componentName;
        var instName = this.instanceName;
        wNameMap = {};
        function getIdKey(aFieldId) {
            var i = aFieldId.lastIndexOf(instName);
            // remove "ufld:" prefix, and "." + instName
            return "id:" + aFieldId.substring(5, i-1) + aFieldId.substring(i+instName.length);
        }
        function getKey(aFieldId, occNr) {
            var i = aFieldId.lastIndexOf(instName);
            // remove "ufld:" prefix, and the trailing component name and suffixes,
            // and append the occNr.
            return aFieldId.substring(5, i) + occNr;
        }
        function buildByOccMap(aStructure, occNr) {
            var fieldName,
                occs,
                id,
                i,
                key;
            for (id in aStructure) if (aStructure.hasOwnProperty(id)) {
                occs = aStructure[id].occs;
                if (occs) { // entity
                    if (occNr !== "") {
                        occNr = occNr + ".";
                    }
                    buildByOccMap(aStructure[id].fosterChildren, occNr + "1");
                    for (i = 0; i < occs.length; i++) {
                        buildByOccMap(occs[i].children, occNr + "" + (i+1));
                    }
                } else { // field
                    fieldName = aStructure[id].definition.nm;
                    if (aStructure[id].fieldId !== undefined) {
                        key = getKey(aStructure[id].fieldId, occNr);
                        wNameMap[key] = aStructure[id];
                        key = getIdKey(aStructure[id].fieldId);
                        wNameMap[key] = aStructure[id];
                    }
                }
            }
        }
        if (this.occs && this.occs.length > 0) {
            buildByOccMap(this.occs[0].children, "");
        }
    };
    
    this.getWidgetById = function(a_id) {
        var field = wNameMap[a_id];
        if (field) {
            return field.widget;
        }
        return null;
    };
    
    this.getWidgetByFieldId = function(a_id) {
        var field = wNameMap["id:" + a_id];
        if (field) {
            return field.widget;
        }
        return null;
    };
    
    UNIFACE.luv.occurrenceContainer.call(this);
};

/**
 * UNIFACE.luv.component is a UNIFACE.luv.entityadmin for its entities.
 */
UNIFACE.luv.component.prototype = new UNIFACE.luv.entityadmin();

/**
 * Returns a pseudo-entity name for this component.  The component acts,
 * in a way, as an entity holding one occurrence.  The top-level entities
 * are considered as being inner-entities of that occurrence.
 * @return A pseudo-entity name.
 */
UNIFACE.luv.component.prototype.getEntityAdminName = function() {
    return "_component_" + this.instanceName;
    };

UNIFACE.luv.component.prototype.createTargetNode = function()
{
    this.targetNode = document.createElement("span");
    this.targetNode.className = "udsp_default";
    this.hideTargetNode();
};

UNIFACE.luv.component.prototype.showTargetNode = function(a_parent)
{
    if (this.targetNode.parentNode !== a_parent)
    {
        if (this.targetNode.parentNode)
        {
            this.targetNode.parentNode.removeChild(this.targetNode);
        }
        a_parent.appendChild(this.targetNode);
    }
};

UNIFACE.luv.component.prototype.hideTargetNode = function()
{
    if (UNIFACE.luv.parkingPlace === undefined)
    {
        UNIFACE.luv.parkingPlace = document.createElement("div");
        UNIFACE.luv.parkingPlace.style.display = "none";
    }
    if (this.targetNode)
    {
        if (this.targetNode.parentNode)
        {
            this.targetNode.parentNode.removeChild(this.targetNode);
        }
        UNIFACE.luv.parkingPlace.appendChild(this.targetNode);
    }
};

/**
 * Returns an ID to be used as the occurrence ID for the single occurrence
 * of the outermost pseudo-entity that this component actually is.
 * The name should be distinguishable from real occurrence IDs. 
 * @return A pseudo-entity occurrence ID.
 */
 UNIFACE.luv.component.prototype.getPseudoOccID = function() {
    return "-top-level-" + this.instanceName;
 };

/**
 * Returns the structure of this component's realized occurrences.
 * The outermost level is a single occurrence (of the pseudo-entity
 * that this component is).
 * @return The structure of this component's realized occurrences.
 */
UNIFACE.luv.component.prototype.getStructureMap = function() {
    return this.occs;  
};

UNIFACE.luv.component.prototype.setTitle = function(a_title)
{
    this.title =a_title;
    var l_el = UNIFACE.luv.util.getElementById("uf:ftitle:" + this.instanceName);
    if (!l_el)
    {
        l_el = UNIFACE.luv.util.getElementById("uf:ftitle" );
    }
    if (l_el)
    {
        l_el.innerHTML = "";
        this.element.appendChild(document.createTextNode(a_title));
    }
};


UNIFACE.luv.component.prototype.createNodeMap = function(aNode)
{
	var len0 = (typeof this.instanceName === "string") ? this.instanceName.length : 0;
	if ( len0 === 0) {
		return;
	}
	var suffix = "." + this.instanceName;
	len0++;
	
    function addSuffix(_aNode) {
	    if ( _aNode.id != null // pragma(allow-loose-compare)
	        && UNIFACE.luv.constants.UID_PREFIXES.hasOwnProperty(_aNode.id.substring(0,5).toLowerCase()) ) {
	        var l = _aNode.id.length;
	        if ( l < len0 || _aNode.id.substring(l-len0, l) !== suffix ) {
	        	this.addNode(_aNode.id, _aNode);
	            _aNode.id = _aNode.id + suffix;
	        } else {
	        	this.addNode(_aNode.id.substring(0, l-len0), _aNode);
	        }
	    }
    }
    
    for ( aNode = aNode.firstChild; aNode !== null; aNode = aNode.nextSibling)
    {
    	addSuffix.call(this, aNode);
        this.createNodeMap(aNode);
    }
};

UNIFACE.luv.component.prototype.mergeData = function( a_newData, a_outScope)
{
    if (this.data === null)
    {
        this.data = a_newData;
    }
    else
    {
        UNIFACE.scope.nodes.occurrence.merge( this.definition, this.data, a_newData, a_outScope[this.instanceName]);
    }
};


