﻿/* Build namespace */
if (NMR == undefined) var NMR = {};
if (NMR.Common == undefined) NMR.Common = {};
if (NMR.Common.Web == undefined) NMR.Common.Web = {};
if (NMR.Common.Web.GenericControls == undefined) NMR.Common.Web.GenericControls = {};

/* Global functions */

/* Dummy comment format
<summary>
    <example>
        <code>
        </code>
    </example>
</summary>
<param name="myParam"></param>
<returns></returns>
<remarks></remarks>
*/

/*
<summary>
Static method that provides infinite extensibility to derive one prototype from another. This
method should be called *after* the new sub-class has prototyped it's methods and properties.
    <example>
        <code>
            MyDerviedClass.prototype = {
                firstProp: null,
                secondProp: function(testarg) {alert(testarg);}
            }
            MyDerviedClass.prototype = prototypeExtend(MyBaseClass.prototype, MyDerivedClass.prototype);
        </code>
    </example>
</summary>
<param name='superClassProto'>The prototype of the object you wish to derive from.</param>
<param name='subClassProto'>The prototype of the object which you wish to derive into.</param>
<returns>A copy of the prototype incorporating both the SuperClass and SubClass</returns>
<remarks>This function will *not* replace methods with the same name in the derived class. This ensures that 
any override to a derived method is persisted in the derived class.</remarks>
*/
function prototypeExtend(superClassProto, subClassProto)
{
    for (var prop in superClassProto)
    {
        if(subClassProto[prop] == undefined)
        {
            subClassProto[prop] = superClassProto[prop];
        }
    }
    return subClassProto;
}

/*
<summary>
A simple function mapping to the text-return methods inside an element, across all browser platforms.
</summary>
<param name="el">The element which is to have it's text content (if any) returned.</param>
<returns>String of any text-content inside the node</returns>
*/
function getTextAllBrowsers(el)
{
    return((document.all)?el.innerText:el.textContent);    
}

/*
<summary>
An override for the Microsoft WebForm_CallbackComplete() method. See BaseFilterPageCodeBehind.vb for example implementation.
Resolves two issues with incorrect scoping of variables, and the execution of the callback method before cleanup has occured.
Credit to: Badri Narayanan (http://social.msdn.microsoft.com/Forums/en-US/netfxjscript/thread/6c4db554-539a-4b5e-9c0c-e1c41eed4fbb/)
</summary>
*/
function WebForm_CallbackComplete_SyncFixed() 
{
    // SyncFix: the original version uses "i" as global thereby resulting in javascript errors when "i" is used elsewhere in consuming pages
    for (var i = 0; i < __pendingCallbacks.length; i++) 
    {
        callbackObject = __pendingCallbacks[i];
        if (callbackObject && callbackObject.xmlRequest && (callbackObject.xmlRequest.readyState == 4)) 
        {
            // the callback should be executed after releasing all resources
            // associated with this request.
            // Originally if the callback gets executed here and the callback
            // routine makes another ASP.NET ajax request then the pending slots and
            // pending callbacks array gets messed up since the slot is not released
            // before the next ASP.NET request comes.
            // FIX: This statement has been moved below
            // WebForm_ExecuteCallback(callbackObject);
            if (!__pendingCallbacks[i].async) 
            {
                __synchronousCallBackIndex = -1;
            }
            __pendingCallbacks[i] = null;
            var callbackFrameID = "__CALLBACKFRAME" + i;
            var xmlRequestFrame = document.getElementById(callbackFrameID);
            if (xmlRequestFrame) 
            {
                xmlRequestFrame.parentNode.removeChild(xmlRequestFrame);
            }
            // SyncFix: the following statement has been moved down from above;
            WebForm_ExecuteCallback(callbackObject);
        }
    }
}

/*
<summary>
Custom implemention of the ECMA-262 standard forEach enumerator into non-compliant browsers.
See: http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:forEach
</summary>
*/
function implementCompatibleForEach()
{   
    if (!Array.prototype.forEach)
    {
        Array.prototype.forEach = function(fun)
        {
            var len = this.length;
            if (typeof fun != "function")
              throw new TypeError();

            var thisp = arguments[1];
            for (var i = 0; i < len; i++)
            {
              if (i in this)
                fun.call(thisp, this[i], i, this);
            }
        };
    }
}
implementCompatibleForEach();

/*
<summary>
Calls the base method for the calling object method. Equivilent to a VB.NET myBase.Method(arguments) call.
</summary>
<param name="obj">The calling object</param>
<param name="baseMethod">The prototype or instance method to invoke</param>
<param name="args">The arguments passed in from the calling object</param>
<remarks>
If calling an instance method (a method created on a specific object instance, not common to any other
object derived from the same prototype), omit the prototype keyword in the baseMethod parameter: 
    <example>
        <code>
            ...
            // Call a base method on the prototype from which the object was derived
            myBase(this, MyBase.prototype.MyBaseMethod, arguments);
            
            // Call a base method on an object (should be one from which the current object derives, but can be any method)              
            myBase(this, AnObject.AnObjectMethod, arguments);
            ...
        </code>
    </example>
</remarks> 
*/
function myBase(obj, baseMethod, args)
{
    baseMethod.apply(obj, args);
}


/* Global Prototypes */

/*
<summary>
The binding stack is responsible for resolving child control objects to a particular parent once a page has loaded.
In a nutshell, when the page is initially parsed any properties in a parent object that may reference child objects
(for instance Scheduled Reports Administration JS object implements Generic Popup as the ManagementRecipient popup)
cannot be resolved until the page has fully loaded, and all referenced objects have been created. In order to resolve 
this limitation, the bindingStack prototype (implemented as .bindingStack property in most controls JS object) has 
been introduced. Child bindings are created using their string names, and then evaluated for resolution when the page 
has fully loaded.

    <example>
        Binds an instance of the 'NMR.Common.Web.GenericControls.GenericPopup' prototype to a property ('ManPopUp') 
        in the 'ScheduledReportAdministration' object.
        <code>
            // this = typeof NMR.Common.ScheduledReports.ScheduledReportAdministration
            // sr1_a3ASDsc = typeof NMR.Common.Web.GenericControls.GenericPopup
            this.bindingStack = new NMR.Common.BindingStack();
            this.bindingStack.addControlBinding('sr1_a3ASDsc','ManPopUp');
        </code>
    </example>
    
    <example>
        Binds the event listener in the parent object that ensures pending binds are processed once the page has fully loaded.
        <code>
            // me = typeof NMR.Common.ScheduledReports.ScheduledReportAdministration
            // - for Firefox
            window.addEventListener("load", function(){me.bindingStack.resolveBindings(me);}, false);
        </code>
    </example>
    
It is important to note that binding should be done in the parent objects constructor/create method, as this is called
prior to the page loading.
</summary>
*/
if(NMR.Common.BindingStack == undefined) NMR.Common.BindingStack = function()
{
    // Private variables 
    this.pendingBinds = new Array();                    // Holds an array of objects describing pending Binds

    // Fire constructor!
    this.create.apply(this, arguments);
}
NMR.Common.BindingStack.prototype = {

    create: function(){},
    
    /*
    <summary>
    </summary>
    <param name="controlId">The name of the child control's object instance as a string E.g. 'mancp_sA2352'</param>
    <param name="targetProp">The name of the target property to bind the resolved controlId to - as string. E.g. 'manageRecipientsPopup'</param>
    */
    addControlBinding: function(controlId, targetProp)
    {
        this.pendingBinds.push({targetControlId:controlId, targetProperty:targetProp});
    }, 
    
    /* 
    <summary>
    Removes a pending control bind from the stack. Note that once the binds have been processed, the 
    pendingBinds() array will be empty.
    </summary>
    <param name="controlId">The target control object identifer (as a string) which is to be bound.</held>
    */ 
    removeControlBinding: function(controlId)
    {
        for(var x=(this.pendingBinds.length-1);x>-1;x--)
        {
            if(this.pendingBinds.targetControlId == controlId)
            {
                this.pendingBinds.splice(x, 1);
                break;
            }
        }
    },
    
    /* 
    <summary>
    Resolves the pending binds when the page is fully loaded. Should be executed in the 'onload' event
    in the parent page, typically by attaching an eventlistener via the implementing object.
    </summary>
    <param name="context">The object on which the targetProperty is held.</param>
    <remarks>
    Either a DOM element, or a script object can be bound. The initial codeblock will attempt
    to bind .targetControlId as an element in the DOM, failing that an attempt will be made to bind
    a global JS object matching the same name. If both attempts fail, the resulting error will be fatal.
    </remarks>
    */ 
    resolveBindings: function(context)
    {
        for(var x=(this.pendingBinds.length-1);x>-1;x--)
        {
            if(document.getElementById(this.pendingBinds[x].targetControlId))
            {
                context[this.pendingBinds[x].targetProperty] = document.getElementById(this.pendingBinds[x].targetControlId);
            }
            else if(eval(this.pendingBinds[x].targetControlId))
            {   
                context[this.pendingBinds[x].targetProperty] = eval(this.pendingBinds[x].targetControlId);
            }
            this.pendingBinds.splice(x, 1);
        }
    }
};

/*
<summary>
Base64 encoder/decoder utilities. Adapted from http://www.webtoolkit.info/
</summary>
*/
if(NMR.Common.Utilities == undefined) NMR.Common.Utilities = {};
if(NMR.Common.Utilities.Base64 == undefined) NMR.Common.Utilities.Base64 = function()
{
    // Fire constructor!
    this.create.apply(this, arguments);
}
NMR.Common.Utilities.Base64.prototype = {

    /* Properties */ 
    keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",     // Base64 encode characters

    /*
    <summary>
    </summary>
    */
    create: function(){},

    /*
    <summary>
    Public method for encoding a string to Base64.
    </summary>
    <param name="input">The string to encode.</param>
    <returns>A Base64 encoded string</returns>
    */
    encode: function(input)
    {
        var output = "";
        var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
        var i = 0;
        
        input = this.utf8_encode(input);

        while (i < input.length) {

            chr1 = input.charCodeAt(i++);
            chr2 = input.charCodeAt(i++);
            chr3 = input.charCodeAt(i++);

            enc1 = chr1 >> 2;
            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
            enc4 = chr3 & 63;

            if (isNaN(chr2)) {
                enc3 = enc4 = 64;
            } else if (isNaN(chr3)) {
                enc4 = 64;
            }
            output = output +
            this.keyStr.charAt(enc1) + this.keyStr.charAt(enc2) +
            this.keyStr.charAt(enc3) + this.keyStr.charAt(enc4);
        }
        return(output);
    },

    /*
    <summary>
    Public method for decoding from Base64 to a string.
    </summary>
    <param name="input">The Base64 encoded string to decode</param>
    <returns>The original string as decoded from the Base64 param 'input'</returns>
    */
    decode: function(input) 
    {
        var output = "";
        var chr1, chr2, chr3;
        var enc1, enc2, enc3, enc4;
        var i = 0;

        input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

        while (i < input.length) {

            enc1 = this.keyStr.indexOf(input.charAt(i++));
            enc2 = this.keyStr.indexOf(input.charAt(i++));
            enc3 = this.keyStr.indexOf(input.charAt(i++));
            enc4 = this.keyStr.indexOf(input.charAt(i++));

            chr1 = (enc1 << 2) | (enc2 >> 4);
            chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
            chr3 = ((enc3 & 3) << 6) | enc4;

            output = output + String.fromCharCode(chr1);

            if (enc3 != 64) {
                output = output + String.fromCharCode(chr2);
            }
            if (enc4 != 64) {
                output = output + String.fromCharCode(chr3);
            }

        }
        output = this.utf8_decode(output);
        return(output);
    },
    
    /*
    <summary>
    Private internal UTF-8 encoding method
    </summary>
    <param name="string">The string to encode to UTF-8 format</param>
    <returns>A UTF-8 encoded text string</returns>
    */
    utf8_encode: function(string) 
    {
        string = string.replace(/\r\n/g,"\n");
        var utftext = "";
        for (var n = 0; n < string.length; n++) {
            var c = string.charCodeAt(n);
            if (c < 128) {
                utftext += String.fromCharCode(c);
            }
            else if((c > 127) && (c < 2048)) {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            }
            else {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }
        }
        return utftext;
    },
    
    /*
    <summary>
    Private internal UTF-8 decoding method
    </summary>
    <param name="utftext">The UTF-8 encoded string to decode</param>
    <returns>A UTF-8 decoded text string</returns>
    */
    utf8_decode: function (utftext) 
    {
        var string = "";
        var i = 0;
        var c = c1 = c2 = 0;
        while ( i < utftext.length ) {
            c = utftext.charCodeAt(i);
            if (c < 128) {
                string += String.fromCharCode(c);
                i++;
            }
            else if((c > 191) && (c < 224)) {
                c2 = utftext.charCodeAt(i+1);
                string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
                i += 2;
            }
            else {
                c2 = utftext.charCodeAt(i+1);
                c3 = utftext.charCodeAt(i+2);
                string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
                i += 3;
            }
        }
        return(string);
    }
};


/*
<summary>

Recommended Reading: http://www.jibbering.com/faq/faq_notes/closures.html

The CustomEvent model implemented for the control suite uses a hierarchical methodology for event handling. Each NMR.Common.CustomEvent
object contains an array of handlers, which are fired whenever that event is raised. Each event can be implemented in the same way as
built-in objects implement their events (e.g. onClick etc) - see NMR.Common.CustomEvent comments.

In order to provide inter-object communication, the need for another level of event management arises. To solve this
problem, the NMR.Common.CustomEvents prototype is introduced. This object holds references to a collection of events, that - depending
upon it's scope - allows any object to attach handlers to the events contained within the NMR.Common.CustomEvents object. 

In this implementation - two instances of the NMR.Common.CustomEvents prototype exist. One instance is declared globally (Broadcast level),  
permitting any object the ability to add/remove events or attach/remove handlers to existing events within the NMR.Common.CustomEvents object.

The second instance is declared as a property of the NMR.Common.Web.GenericControls.ScheduedReportBase prototype, and permits all 
controls derived from this type to communicate - E.g. if two instances of NMR.Common.Web.GenericControls.GenericControls exist on a page
and one contains the same data as another, the developer may wish to cause both to perform a callback if one of the control instances 
amends/deletes it's list of report schedules.

The following diagram should better illustrate the CustomEvent model:

               /--------|NMR.Common.CustomEvents|----------\
              /                 |                           \
  |NMR.Common.CustomEvent|  |NMR.Common.CustomEvent|   |NMR.Common.CustomEvent|
      /        |                |                       /         |         \
|Handler|   |Handler|       |Handler|              |Handler|   |Handler|   |Handler|

</summary>
*/

/*
<summary>
Provides the ability to attach custom events to a JavaScript object. The CustomEvent object attempts
to be browser agnostic, associating any number of handlers with a developer defined event. Any function/object
can attach a handler which will be called when the event is fired.     
    <example>
        To initialize an instance of the the event object against an existing prototype:
        <code>
            testObj = function()
            {   
                ...
                // Event initialisation (scopes the event for the object instance only)
                this.onLoaded = new CustomEvent();
                this.onDoSomethingFunky = new CustomEvent();
                ...
            }
            testObj.prototype = 
            {
                ...
                // Events - if CreateEvent() syntax is specified here, the event *instance* 
                // will exist across all objects that instance the prototype. E.g. :
                // onSomething: new CustomEvent(),
                onLoaded: null, 
                onDoSomethingFunky: null, 
                ...
            };       
        </code>
        
        To add an event handler to a prototyped CustomEvent object:
        <code>
            testObj.prototype = 
            {
                ...
                methodThatAddsEventHandlersForThetestObj: function()
                {   
                    // Assume 'me' has been defined as 'this'.
                    me.onLoaded.addHandler(function(){alert('handled once!');});
                    me.onLoaded.addHandler(function(){alert('handled twice!');});
                    me.onDoSomethingFunky.addHandler(function(){alert('handled!');});
                }
                ...
            }
        </code>
        
        To remove an event handler from a prototyped CustomEvent object:
        (NB: The function signature must be identical to that used in the 'addHandler' call).
        <code>
            testObj.prototype = 
            {
                ...
                methodThatRemovesEventHandlersForThetestObj: function()
                {
                    // Assume 'me' has been defined as 'this'.   
                    me.onLoaded.removeHandler(function(){alert('handled once!');});
                }
                ...
            }
        </code>
        
        To fire an event, and therefore invoke all handlers associated with that event:
        (NB: Any optional arguments will be passed to all handlers that exist for the event).
        <code>
            testObby = new testObj();
            testObby.onLoaded.raise([optional arguments]);
        </code> 
    </example>
</summary>
*/
if(NMR.Common.CustomEvent == undefined) NMR.Common.CustomEvent = function(eventName)
{
    // NB Scoping:
    // prop = private scope          <-- Notice no 'var' prefix
    // this.prop = instance scope    <-- Super important for correct object closure
    // prototype.prop = global scope (across all instances that derive from the prototype)

    // Private variables
    this.eventHandlers = new Array();
    
    // Fire constructor!
    this.create.apply(this, arguments);
}
NMR.Common.CustomEvent.prototype =
{
    // Constructor function
    create: function()
    {
        this.eventName = arguments[0];
    },
    
    eventName: null,

    removeHandler: function(evtHandler)
    {
        for(var i=0;i<this.eventHandlers.length;i++)
        {
            if(this.eventHandlers[i] == evtHandler)
            {
                this.eventHandlers.splice(i,1);
            }
        }  
    },

    addHandler: function(evtHandler) 
    {
        this.eventHandlers.push(evtHandler);
    },
    
    raise: function(sender, eventArgs)
    {
        for(var i=0;i<this.eventHandlers.length;i++)
        {
            this.eventHandlers[i].apply(this.eventHandlers[i], arguments);
        }
    }
};

/*
<summary>
Defines an event array. The event array permits multiple objects to attach handlers
to common events, therefore providing the ability for inter-object communication and
event recognition.
    <example>
        <code>
        
            var me = this;
            var myEvent = NMR.Common.Web.GenericControls.GlobalEvents.getCustomEvent("globaltest");
            if(!myEvent)
            {
                myEvent = new NMR.Common.CustomEvent("globaltest");
                NMR.Common.Web.GenericControls.GlobalEvents.addCustomEvent(myEvent);
            }
            myEvent.addHandler(function(sender, eventArgs){alert("global event fired handler for: " + me.clientObjectId);});
            
        </code>
    </example>
</summary>
*/
if(NMR.Common.CustomEvents == undefined) NMR.Common.CustomEvents = function()
{
    // Private variables
    this.listedEvents = new Array();
    
    // Fire constructor!
    this.create.apply(this, arguments);
}
NMR.Common.CustomEvents.prototype = {
    
    create: function(){},

    raiseCustomEvent: function(eventToRaise, sender, eventArgs)
    {
        // Declare a locally scoped class to use for comparision.
        // Equivilent to .NET class implementing IComparer(Of T).
        var predicate = new function(){
            this.eventName = null;
            this.sender = null;
            this.eventArgs = null;
            this.matchElement = function(arrayElement, currentIndex)
            {
                if(arrayElement.eventName == this.eventName)
                {
                    //##
                    try{arrayElement.raise.call(arrayElement, this.sender, this.eventArgs);}catch(e){}
                    return;
                }
            }
        }
        predicate.eventName = eventToRaise;
        predicate.eventArgs = eventArgs;
        predicate.sender = sender;
        this.listedEvents.forEach(predicate.matchElement, predicate);        
    },
    
    getCustomEvent: function(eventName)
    {
        for(var i=0;i<this.listedEvents.length;i++)
        {
            if(this.listedEvents[i].eventName == eventName)
            {
                return(this.listedEvents[i]);
            }
        }
    },
    
    addCustomEvent: function(eventObj)
    {
        if(eventObj.eventName == null) return(false);
        if(this.getCustomEvent(eventObj.eventName) == undefined){ this.listedEvents.push(eventObj); }
    },
    
    removeCustomEvent: function(eventName)
    {
        for(var i=0;i<this.listedEvents.length;i++)
        {
            if(this.listedEvents[i].eventName == eventName)
            {
                this.listedEvents.splice(i, 1);
                return;
            }   
        }
    }
};
// Stores Broadcast level event handlers for events to process globally across the document domain
if (NMR.Common.Web.GenericControls.GlobalEvents == undefined) NMR.Common.Web.GenericControls.GlobalEvents = new NMR.Common.CustomEvents();


/*
<summary>
A collection of registrations identifying any NMR.Common.Web.GenericControls that exist in the 
document domain.
</summary>
*/
if(NMR.Common.ControlRegistrations == undefined) NMR.Common.ControlRegistrations = function()
{
    // Private variables
    this.registeredControls = new Array();
    
    // Fire constructor!
    this.create.apply(this, arguments); 
}
NMR.Common.ControlRegistrations.prototype = {

    create: function(){},

    registerControl: function(friendlyId, instanceId, type)
    {
        var ctl = new NMR.Common.ControlRegistration(friendlyId, instanceId, type);
        return(this.registerControlFromObject(ctl));
    },
    
    registerControlFromObject: function(controlObject)
    {
        if(!controlObject){throw("no control object supplied");return(false);}
        if(this.locateControlByFriendlyId(controlObject.friendlyId)){throw("friendlyId is not unique");return(false);}
        if(this.locateControlByInstanceId(controlObject.instanceId)){throw("instanceId is not unique");return(false);} 
        this.registeredControls.push(controlObject);
    },
   
    unregisterControl: function(friendlyId, instanceId, type)
    {
        for(var x=0;x<this.registeredControls.length;x++)
        {
            if((this.registeredControls[x].friendlyId == friendlyId) && 
               (this.registeredControls[x].instanceId == instanceId) &&
               (this.registeredControls[x].type == type))
            {
                this.registeredControls.splice(x, 1);
            }
        }
    },
    
    locateControlByFriendlyId: function(friendlyId)
    {
        for(var x=0;x<this.registeredControls.length;x++)
        {
            if(this.registeredControls[x].friendlyId == friendlyId)
            {
                return(this.resolveControl(this.registeredControls[x]));
            }
        }
        return(null);
    },
    
    locateControlByInstanceId: function(instanceId)
    {
        for(var x=0;x<this.registeredControls.length;x++)
        {
            if(this.registeredControls[x].instanceId == instanceId)
            {
                return(this.resolveControl(this.registeredControls[x]));
            }
        }
        return(null);
    },
    
    locateControlsByType: function(type)
    {
        var ctls = new Array();
        for(var x=0;x<this.registeredControls.length;x++)
        {
            if(this.registeredControls[x].type == type)
            {
                ctls.push(this.resolveControl(this.registeredControls[x]));
            }
        }
        return((ctls.length == 0)?null:ctls);
    },
    
    resolveControl: function(controlObj)
    {
        if(controlObj.instanceId != null){controlObj.instanceObj = eval(controlObj.instanceId);}
        return((typeof controlObj.instanceObj == "object")?controlObj.instanceObj:null);
    }
};
// Stores Registrations for each generic control instance in the document domain
if (NMR.Common.Web.GenericControls.ControlRegistrations == undefined) NMR.Common.Web.GenericControls.ControlRegistrations = new NMR.Common.ControlRegistrations();

/*
<summary>
A control registration object. Represents an NMR.Common.Web.GenericControl present in
the document domain.
</summary>
*/
if(NMR.Common.ControlRegistration == undefined) NMR.Common.ControlRegistration = function()
{   
    // Fire constructor!
    this.create.apply(this, arguments); 
}
NMR.Common.ControlRegistration.prototype = {

    friendlyId: null,       // Friendly id to key the control against (as string)
    instanceId: null,       // The generated instance object instance of the control (as string)
    instanceObj: null,      // Reference to the generated object instance of the control
    type: null,             // Type of control 

    create: function(friendlyId, instanceId, type)
    {
        if(friendlyId != undefined){this.friendlyId = friendlyId;}
        if(instanceId != undefined){this.instanceId = instanceId;}
        if(type != undefined){this.type = type;}
    }
};