/// <reference name="MicrosoftAjax.debug.js" />

window.onload = function() {
    // Disable the Back Button and Back Space Key Press
    window.history.forward(1);

    // Ensure the page is enabled
    EnablePage();
}

// Validates that the entry has a length > 0.  Used by the CustomRequiredFieldValidator
function ValidateLength(sender, args) {
    // Check whether or not this entry has data
    var isValidEntry = args.Value.length > 0;
    if (isValidEntry == false)
    // Entry was not valid, enable the page so that text entry can resume
        EnablePage();

    args.IsValid = isValidEntry;
}

// Validates that the entry is numeric.  Used by the CustomNumericFieldValidator
function ValidateNumeric(sender, args) {
    // Define numeric RegEx
    //This is anchor regex 
    //  ^   # anchor at the start
    //  -?  # allow a negative for the first character
    //  \d* # allow any number of digits
    //  (\.\d+)?    # allow a period with at least one digit after it
    //  $   # anchor at the end
    var numericRegex = /^-?\d*(\.\d+)?$/;

    // Check text entry
    if (!args.Value.match(numericRegex)) {
        // Entry was not valid, enable the page so that text entry can resume
        EnablePage();
        args.IsValid = false;
    }
    else {
        args.IsValid = true;
    }
}

// Enables the page
function EnablePage() {
    // Get the Posting Div
    var postingDiv = document.getElementById('posting');
    // Reduce the size of the posting div
    postingDiv.style.height = '0px';
    postingDiv.style.width = '0px';
}

// Disables the page
function DisablePage() {
    // Get the Posting Div
    var postingDiv = document.getElementById('posting');
    // Increate the size of the posting div	
    postingDiv.style.height = '100%';
    postingDiv.style.width = '100%';
}

// Presents the user with a confirm message.  
function ConfirmDelete(message) {
    var answer = confirm(message);
    if (answer != 0) {
        DisablePage();
        return true;
    }
    else {
        return false;
    }
}

// Refreshes an image
function refreshImage(controlID, destination) {
    var image = document.getElementById(controlID);
    image.src = destination;
}

// Refreshes a Camera 
function RefreshCamera(controlID, destination, interval) {
    var time = new Date();
    setTimeout('refreshImage("' + controlID + '","' + destination + '?' + time + '");', interval * 1000);
}

//  Limits text entry depending on the maxlimit
function limitTextEntry(field, maxlimit) {
    if (field.value.length > maxlimit) {
        field.value = field.value.substring(0, maxlimit);
    }
}


// Parses and returns an array represending the Querystring   
function parseQuerystring() {
    var params = new Array();
    var querystring = location.search.substring(1);
    var pairs = querystring.split('&');

    for (var i in pairs) {
        var nameValuePair = pairs[i].split('=');
        params[nameValuePair[0]] = nameValuePair[1];
    }
    return params;
}



// r.a.d.ComboBox Methods 

// Enables the ComboBox
function OnClientItemsRequestedEventHandler(combobox) {
    combobox.Enabled = true;
}

// Clears and Disables the ComboBox
function OnClientItemsRequestingEventHandler(combobox) {
    combobox.Enabled = false;
    combobox.Items = [];
    document.getElementById(combobox.DropDownID).innerHTML = "";
}


// r.a.d.Window Methods

// This code is used to provide a reference to the radwindow "wrapper"
function GetRadWindow() {
    var radWindow = null;
    if (window.radWindow) {
        //Will work in Moz in all cases, including clasic dialog
        radWindow = window.radWindow;
    }
    else if (window.frameElement.radWindow) {
        //IE (and Moz az well)
        radWindow = window.frameElement.radWindow;
    }

    return radWindow;
}

function CloseOnReload() {
    GetRadWindow().close();
}

// Forces the parent page to PostBack to the Web Server
function ForceParentPagePostBack() {
    var window = GetRadWindow().BrowserWindow;
    window.__doPostBack('ForcedPostBack', '');
}

// Refreshes the parent page, equilavent to an F5
function RefreshParentPage() {
    GetRadWindow().BrowserWindow.location.reload();
}

// Opens a radWindow for a specific Lookup, indicated by the lookupID
function OpenSearchWindow(lookupID, height, width) {
    try {
        // Open the radWindow
        var radSearchWindow = window.radopen("Search.aspx?MyLookupID=" + lookupID, "rwLookup");

        // Size the radWindow
        radSearchWindow.setSize(width, height);

        // Move the radWindow to the upper left of the screen
        radSearchWindow.MoveTo(50, 50);
    }
    catch (error) {
        alert(error.message);
    }
}

function FocusOnRow(rowID) {
    var focusElement = $get(rowID);
    if (focusElement) {
        Telerik.Web.UI.Grid.ScrollIntoView(focusElement);
    }
}

//EditableGridManager -------------------------------------------------------------------------------
//Only one editableGridManager is ever created
var $egm = EditableGridManager = function(lookupIframeElemID, lookupURL) {
    this.lookupIframeElemID = lookupIframeElemID;
    this.lookupURL = lookupURL;

    this.grids = new Object();

    this.lookupManager = null;
    this.isLookupWindowLoadedDelegateSet = false;

    var ajaxSent = Function.createDelegate(this, this.AjaxSent);
    var egm = this;

    Sys.Net.XMLHttpExecutor.prototype.oldExecuteRequest = Sys.Net.XMLHttpExecutor.prototype.executeRequest;
    Sys.Net.XMLHttpExecutor.prototype.executeRequest = function() {
        egm.ajaxSentCompleted = false;
        this.waitForAjaxSentToComplete = function() {
            if (egm.ajaxSentCompleted) {
                _this._clearTimer();
                _this._responseAvailable = true;

                this._webRequest.completed(Sys.EventArgs.Empty);

                if (_this._xmlHttpRequest != null) {
                    _this._xmlHttpRequest.onreadystatechange = Function.emptyMethod;
                    _this._xmlHttpRequest = null;
                }
            }
            else {
                setTimeout(Function.createDelegate(this, this.waitForAjaxSentToComplete), 100);
            }
        }

        var _this = this;

        this._onReadyStateChange = function() {
            if (_this._xmlHttpRequest.readyState === 4) {
                _this.waitForAjaxSentToComplete();
            }
        }

        this.oldExecuteRequest();
        setTimeout(ajaxSent, 0);
    }

    Sys.WebForms.PageRequestManager.getInstance().add_pageLoading(Function.createDelegate(this, this.disposeTree));

    //The WebForm_InitCallback is not needed and so we override the method to speed up the process of updating especially in IE
    WebForm_InitCallback = function() { };
}

EditableGridManager.prototype = {
    LookupWindowLoaded: function() {
        if (this.lookupManager != null) {
            this.lookupManager.OnLookupLoaded();

            this.lookupManager = null;
        }
    },

    GetContainerElement: function(elem) {
        var containerElem = elem;

        while (containerElem != null) {
            if ("id" in containerElem && containerElem.id.endsWith("%Container")) {
                break;
            }
            else {
                containerElem = containerElem.parentNode;
            }
        }

        if (containerElem != null) {
            return new EditableGridManager.ContainerElement(containerElem);
        }
        else {
            return null;
        }
    },

    CreateLookupManager: function(elem) {
        var containerElem = this.GetContainerElement(elem);

        if (containerElem != null) {
            var rowPrefix = containerElem.GetRowPrefix();
            var columnName = containerElem.GetColumnName();
            var rowIndex = containerElem.GetRowIndex();

            var grid = this.GetGrid(containerElem.ID());

            if (grid.GetColumn(columnName).HasALookup()) {
                if (this.isLookupWindowLoadedDelegateSet == false) {
                    GetRadWindowManager().add_pageLoad(Function.createDelegate(this, this.LookupWindowLoaded));
                    this.isLookupWindowLoadedDelegateSet = true;
                }

                this.lookupManager = grid.CreateLookupManager(this.lookupIframeElemID, this.lookupURL, rowPrefix, columnName, rowIndex);
                this.lookupManager.OpenLookupWindow();
                grid.LoadValidationForARow(rowIndex);
            }
        }
    },

    GetGrid: function(elemID) {
        for (var gridID in this.grids) {
            if (elemID.indexOf(gridID) > -1) {
                return this.grids[gridID];
            }
        }

        return null;
    },

    AddGrid: function(gridClientID, pageSiteControlID, gridLayoutPosition) {
        var grid = new EditableGridManager.EditableGrid(gridClientID, pageSiteControlID, gridLayoutPosition);

        this.grids[gridClientID] = grid;

        return grid;
    },

    AjaxSent: function() {
        this.disposeObjectsDictionary = new Object();
        var elementIDs = Sys.WebForms.PageRequestManager.getInstance()._updatePanelClientIDs;

        for (var i = elementIDs.length - 1; i >= 0; i--) {
            var currentElementID = elementIDs[i];
            var elementArrayToAddDisposeObjectsTo = this.disposeObjectsDictionary[currentElementID] = new Array();

            var nodes = $get(currentElementID).getElementsByTagName('*');
            //We need to grab the length before executing otherwise performance suffers.
            var length = nodes.length;

            for (var j = 0; j < length; j++) {
                var node = nodes[j];
                if (node.nodeType === 1) {

                    if (node.dispose && typeof (node.dispose) === "function") {
                        Array.add(elementArrayToAddDisposeObjectsTo, node);
                    }
                    else if (node.control && typeof (node.control.dispose) === "function") {
                        Array.add(elementArrayToAddDisposeObjectsTo, node.control);
                    }

                    if (node._behaviors) {
                        var behaviorsLength = node._behaviors.length;
                        for (var k = behaviorsLength - 1; k >= 0; k--) {
                            Array.add(this.disposeObjects, node._behaviors[k]);
                        }
                    }
                }
            }
        }

        this.ajaxSentCompleted = true;
    },

    disposeTree: function(sender, args) {
        var elements = args.get_panelsUpdating();

        for (var i = 0; i < elements.length; i++) {
            var objectsToDispose = this.disposeObjectsDictionary[elements[i].id];
            this.disposeObjectsDictionary[elements[i].id] = null;

            var objectsToDisposeLength = objectsToDispose.length;
            for (var j = 0; j < objectsToDisposeLength; j++) {
                objectsToDispose[j].dispose();
            }

            elements[i].innerHTML = "";
        }
    }
}

//Static methods for EditableGridManager

//A lazy loader that returns the EditableGridManager singleton
EditableGridManager.getInstance = function() {
    if (EditableGridManager._instance == null) {
        //Replace method definitions with better definitions
        Telerik.Web.UI.GridSelection.prototype._click = EditableGridManager._click;
        Telerik.Web.UI.GridTableView.prototype._resizeGridOnColumnResize = EditableGridManager._resizeGridOnColumnResize;
        EditableGridManager._instance = new EditableGridManager("rwLookup", "EditableGridSearch.aspx");
    }

    return EditableGridManager._instance;
}

EditableGridManager.ShowLookup = function(elem) {
    EditableGridManager.getInstance().CreateLookupManager(elem);

    return false;
}

EditableGridManager.RegisterGridInformation = function(gridClientID, pageSiteControlID, gridLayoutPosition) {
    return EditableGridManager.getInstance().AddGrid(gridClientID, pageSiteControlID, gridLayoutPosition);
}

EditableGridManager.OnGridCreated = function(grid) {
    var editableGrid = EditableGridManager.getInstance().GetGrid(grid.ClientID);
    if (editableGrid != null) {
        editableGrid.GridCreated(grid);
    }
}

EditableGridManager.Delete = function(gridClientID) {
    EditableGridManager.getInstance().GetGrid(gridClientID).Delete();

    return false;
}

EditableGridManager.Update = function(gridClientID) {
    EditableGridManager.getInstance().GetGrid(gridClientID).Update();

    return false;
}
//End EditableGridManager -------------------------------------------------------------------------------

//ContainerElement --------------------------------------------------------------------------------------
//A wrapper for a container element
EditableGridManager.ContainerElement = function(elem) {
    this.elem = elem;
}

EditableGridManager.ContainerElement.prototype = {
    GetRowPrefix: function() {
        return this.elem.id.split("%")[0];
    },

    GetColumnName: function() {
        return this.elem.id.split("%")[1];
    },

    GetRowIndex: function() {
        return this.elem.id.split("%")[2];
    },

    IsNewRow: function() {
        return this.GetRowIndex() == "-1";
    },

    ID: function() {
        return this.elem.id;
    }
}
//End ContainerElement ----------------------------------------------------------------------------------

//EditableGrid ----------------------------------------------------------------------------------
//Manages the bulk processing related to an editable grid
EditableGridManager.EditableGrid = function(id, pageSiteControlID, gridLayoutPosition) {
    this._id = id;
    this.pageSiteControlID = pageSiteControlID;
    this.gridLayoutPosition = gridLayoutPosition;

    this._isNewRowSelected = false;

    this._columns = new Array();
    
    this.relatedValidatorsTemplates = new Array();
}

EditableGridManager.EditableGrid.prototype = {
    get_id: function() {
        return this._id;
    },

    get_serverID: function() {
        var ids = this._id.split("_");

        return ids[ids.length - 1];
    },

    get_gridControl: function() {
        return $find(this._id);
    },

    get_columns: function() {
        return this._columns;
    },

    get_insertRow: function() {
        var gridControl = this.get_gridControl();

        if (gridControl) {
            var tableHeaderViewElement = gridControl.get_masterTableViewHeader().get_element();

            //The assumption is that the insert row is the last row in the master table view header
            var headRows = tableHeaderViewElement.tHead.rows;

            if (headRows.length >= 1) {
                return headRows[headRows.length - 1];
            }
            else {
                return null;
            }
        }
        else {
            return null;
        }
    },

    set_IsNewRowSelected: function(value) {
        this._isNewRowSelected = value;

        if (value) {
            this.get_gridControl().get_masterTableView().clearSelectedItems();
        }
    },

    get_IsNewRowSelected: function(value) {
        return this._isNewRowSelected;
    },

    RegisterValidatorTemplate: function(validatorTemplate) {
        Array.add(this.relatedValidatorsTemplates, new EditableGridManager.ValidatorTemplate(validatorTemplate));
    },

    //Using ajax this will get called every time we update the contents
    GridCreated: function(sender, args) {
        var grid = sender;

        grid.add_gridDestroying(Function.createDelegate(this, this.GridDestroying));

        var gridElement = grid.get_element();
        var gridElementID = gridElement.id;
        //These handlers get cleared by the grid automatically on AJAX postbacks
        $addHandler(gridElement, "click", Function.createDelegate(this, this.GridClick));
        $addHandler(gridElement, "keydown", Function.createDelegate(this, this.OnKeyDown));

        var masterTableViewElement = grid.get_masterTableView().get_element();
        var insertRow = this.get_insertRow();

        var focusDelegate = Function.createDelegate(this, this.OnFocus);

        if (masterTableViewElement.attachEvent) {
            masterTableViewElement.attachEvent("onfocusin", focusDelegate);
            if (insertRow) {
                insertRow.attachEvent("onfocusin", focusDelegate);
            }
        }
        else {
            masterTableViewElement.addEventListener("focus", focusDelegate, true);
            if (insertRow) {
                insertRow.addEventListener("focus", focusDelegate, true);
            }
        }

        //In order for $clearHandlers to work later we need to setup the elements with the handlers
        masterTableViewElement._events = {};
        insertRow._events = {};
        masterTableViewElement._events["focus"] = [{ handler: focusDelegate, browserHandler: focusDelegate}]
        insertRow._events["focus"] = [{ handler: focusDelegate, browserHandler: focusDelegate}]

        if (insertRow) {
            var focusElem = this.FocusFirstFocusableElement(insertRow.cells);
            focusElem.focus();
        }
        else {
            var rows = this.get_gridControl().get_masterTableView().get_element().tBodies[0].rows;
            if (rows.length > 0) {
                var focusElem = this.FocusFirstFocusableElement(rows[0]);
                focusElem.focus();
            }
        }
    },

    FocusFirstFocusableElement: function(elements) {
        for (var i = 0; i < elements.length; i++) {
            if (elements[i].focus && elements[i].tagName == "INPUT") {
                return elements[i];
            }
            else if (elements[i].childNodes.length > 0) {
                var returnElement = this.FocusFirstFocusableElement(elements[i].childNodes);
                if (returnElement != null) {
                    return returnElement;
                }
            }
        }
    },

    GridDestroying: function(sender, args) {
        var gridControl = sender;

        $clearHandlers(gridControl.get_masterTableView().get_element());

        var insertRow = this.get_insertRow();
        if (insertRow) {
            $clearHandlers(insertRow);
        }

        Array.clear(this.relatedValidatorsTemplates);
    },

    IsAParentElement: function(parent, element) {
        return isParent(parent, element);

        function isParent(parent, element) {
            if (element.parentNode) {
                if (element.parentNode == parent)
                    return true;
                else
                    return isParent(parent, element.parentNode);
            }
            else
                return false;
        }
    },

    GridClick: function(sender) {
        var insertRow = this.get_insertRow();

        if (insertRow) {
            var isNewRowSelected = this.IsAParentElement(insertRow, sender.target);
            if (isNewRowSelected != this.get_IsNewRowSelected()) {
                this.set_IsNewRowSelected(isNewRowSelected);
            }
        }
    },

    OnFocus: function(ev) {
        if (ev == null) {
            ev = event;
        }

        var target;

        if (ev.srcElement) {
            target = ev.srcElement;
        }
        else {
            target = ev.target;
        }

        Array.forEach(this.relatedValidatorsTemplates, registerValidatorsIfNeeded, this);

        function registerValidatorsIfNeeded(relateValidatorTemplate) {
            var validationInfo = relateValidatorTemplate.GetElementValidationInfo(target.id);

            if (validationInfo != null && !validationInfo.get_ValidatedElementHasBeenSetup()) {
                relateValidatorTemplate.SetupValidation(validationInfo);
            }
        }
    },

    OnKeyDown: function(sender) {
        if (sender.keyCode == 115 || (sender.keyCode == 83 && sender.ctrlKey) || (sender.keyCode == 68 && sender.ctrlKey)) /* F4 lookup/ ctrl + s/ ctrl + d */{
            try { //Prevent browsers from performing their default action
                sender.rawEvent.keyCode = -1;
            }
            catch (e) {
            }

            sender.preventDefault();
        }

        if (sender.keyCode == 115) /* F4 lookup */{
            EditableGridManager.getInstance().CreateLookupManager(sender.target);
        }

        var containerElem;

        if (sender.keyCode == 27) /* Escape key to revert row*/{
            containerElem = EditableGridManager.getInstance().GetContainerElement(sender.target);

            if (containerElem != null) {
                Array.forEach(this.get_columns(), getColumnControlManager, this);
            }
        }

        function getColumnControlManager(column) {
            column.Revert(containerElem.IsNewRow(), containerElem.GetRowPrefix());
        }

        if (sender.keyCode == 83 && sender.ctrlKey) /* ctrl + s to do update */{
            this.Update();
        }

        if (sender.keyCode == 68 && sender.ctrlKey) /* ctrl + d to do delete */{
            this.Delete();
        }
    },

    LoadValidationForARow: function(rowIndex) {
        Array.forEach(this.relatedValidatorsTemplates, registerValidatorsIfNeeded, this);

        function registerValidatorsIfNeeded(relatedValidatorTemplate) {
            var validatorInfo = relatedValidatorTemplate.get_ValidationGroupValidatorInfoDictionary()[this.get_serverID() + "%" + rowIndex];

            if (validatorInfo != null && !validatorInfo.get_ValidatedElementHasBeenSetup()) {
                relatedValidatorTemplate.SetupValidation(validatorInfo);
            }
        }
    },

    //Creates a lookup manager by collecting information about the row and opens a lookup
    //by sending the row information in the url of the lookup page
    CreateLookupManager: function(lookupIframeElemID, lookupURL, rowPrefix, columnName, rowIndex) {
        var dataGridColumnID = this.GetColumn(columnName).get_columnID();
        var newRow = rowIndex == "-1";

        var urlParametersBuilder = new Array();
        Array.add(urlParametersBuilder, String.format("?DataGridColumnID={0}&PageSiteControlID={1}&DefaultDataGridPosition={2}&IsANewRecord={3}", dataGridColumnID, this.pageSiteControlID, this.gridLayoutPosition, newRow));

        var columnControlManagers = new Array();

        Array.forEach(this.get_columns(), getColumnControlManager, this);

        function getColumnControlManager(column) {
            Array.add(columnControlManagers, column.GetValueControlManager(newRow, rowPrefix));
        }

        var columnsAddedToQueryString = new Array();

        Array.forEach(columnControlManagers, getAssociatedColumnValues, this);

        function getAssociatedColumnValues(columnControlManager) {
            var columnName = columnControlManager.get_associatedColumnName();

            if (columnName != null) {
                Array.add(urlParametersBuilder, String.format("&{0}={1}", columnName, escape(columnControlManager.GetAssociatedValue())));

                Array.add(columnsAddedToQueryString, columnName);
            }
        }

        Array.forEach(columnControlManagers, getColumnValues, this);

        function getColumnValues(columnControlManager) {
            var columnName = columnControlManager.get_columnName();

            if (columnName != null && !Array.contains(columnsAddedToQueryString, columnName)) {
                Array.add(urlParametersBuilder, String.format("&{0}={1}", columnName, escape(columnControlManager.GetValue())));

                Array.add(columnsAddedToQueryString, columnName);
            }
        }

        if (!newRow) {
            var clientKeyNames = this.get_gridControl().get_masterTableView().get_clientDataKeyNames();
            var keyValues = this.get_gridControl()._clientKeyValues[rowIndex];

            Array.forEach(clientKeyNames, getKeyValues, this);
        }

        //The function needs to be outside the if statement to evaluate correctly
        function getKeyValues(clientKeyName) {
            if (!Array.contains(columnsAddedToQueryString, clientKeyName)) {
                Array.add(urlParametersBuilder, String.format("&{0}={1}", clientKeyName, escape(keyValues[clientKeyName])));
            }
        }

        var urlParameters = urlParametersBuilder.join("");

        return new EditableGridManager.LookupManager(lookupIframeElemID, this, rowPrefix, lookupURL + urlParameters);
    },

    //Used when loading the page to load related information about the column
    //Must return the grid so that we can continue to call grid methods
    AddColumn: function(columnName, columnID, changesAllowedOnAdd, changesAllowedOnUpdate, hasALookup, getDelegate, setDelegate, revertDelegate) {
        var column = new EditableGridManager.Column(columnName, columnID, changesAllowedOnAdd, changesAllowedOnUpdate, getDelegate, setDelegate, revertDelegate);
        column.set_hasALookup(hasALookup);

        Array.add(this._columns, column);

        return this;
    },

    //Used when loading the page to load related information about the column
    //Must return the grid so that we can continue to call grid methods
    AddColumnWithAssociatedColumn: function(columnName, columnID, changesAllowedOnAdd, changesAllowedOnUpdate, hasALookup, associatedColumnName, getDelegate, setDelegate, revertDelegate) {
        var column = new EditableGridManager.Column(columnName, columnID, changesAllowedOnAdd, changesAllowedOnUpdate, getDelegate, setDelegate, revertDelegate);
        column.set_hasALookup(hasALookup);
        column.set_associatedColumnName(associatedColumnName);

        Array.add(this._columns, column);

        return this;
    },

    //Returns EditableGridManager.Column if in grid
    GetColumn: function(columnName) {
        var returnColumn;

        Array.forEach(this._columns, getColumn, this);

        function getColumn(column) {
            if (column.get_columnName() == columnName) {
                returnColumn = column;
            }
        }

        return returnColumn;
    },

    BuildValidationGroupArray: function(validationGroup) {
        var validators = new Array();

        Array.forEach(this.relatedValidatorsTemplates, buildValidationGroupArray, this);

        function buildValidationGroupArray(validatorTemplate) {
            var validationGroupDictionary = validatorTemplate.get_ValidatorValidationGroupDictionary();

            if (validationGroup in validationGroupDictionary) {
                Array.add(validators, validationGroupDictionary[validationGroup]);
            }
        }

        return validators;
    },

    Update: function() {
        var validationPassed = true;
        var allValidators = Page_Validators;
        var allValidationSummaries = Page_ValidationSummaries;

        //Microsoft's built in validation doesn't allow for validation to be called on multiple validation groups
        //without clearing the results of each validation group.
        //Therefore what we do is fake the validation into performing validation on one validation group at a time
        //without overriding the results of the other validation groups.

        //Step 1 is to build a dictionary of validator summary arrays base on their validation group
        var validatorGroupSummaries = new Object();

        Array.forEach(Page_ValidationSummaries, validatorSummariesLoop);

        function validatorSummariesLoop(validatorSummary) {
            if (validatorGroupSummaries[validatorSummary.validationGroup] == null) {
                validatorGroupSummaries[validatorSummary.validationGroup] = new Array();
            }

            Array.add(validatorGroupSummaries[validatorSummary.validationGroup], validatorSummary);
        }

        //Step 2 is to loop through all the rows that are being validated and validate
        var rows = this.get_gridControl().get_masterTableView().get_element().tBodies[0].rows;

        //Start at -1 which is the insert row
        for (var i = -1; i < rows.length; i++) {
            //The validation group name was built on the server control ID and the row index.
            var validationGroup = this.get_serverID() + "%" + i;

            //We temporarily replace the validators for the page with only the validators that pertain to this validation group
            var validators = this.BuildValidationGroupArray(validationGroup);
            if (validators.length > 0) {
                Page_Validators = validators;

                //We do the same thing with the summaries
                Page_ValidationSummaries = validatorGroupSummaries[validationGroup];

                //Now when we validate, only validators within our validation group are checked.
                if (!Page_ClientValidate(validationGroup)) {
                    validationPassed = false;
                }
            }
        }

        //We now make sure that our valiators are set back to what they are supposed to be.
        Page_Validators = allValidators;
        Page_ValidationSummaries = allValidationSummaries;

        if (validationPassed) {
            //We need to perform insert in order to make the grid act correctly on the server side.
            this.get_gridControl().get_masterTableView().fireCommand("UpdateAll", "");
        }
    },

    Delete: function() {
        var selectedIndexes = this.get_gridControl()._selectedIndexes;

        if (selectedIndexes.length > 0 && confirm("Are you sure you wish to delete the selected row?")) {
            this.get_gridControl().get_masterTableView().fireCommand("DeleteWithoutRebinding", selectedIndexes[0]);
        }
    }
}
//End EditableGrid -------------------------------------------------------------------------------

//Column -------------------------------------------------------------------------------
//Contains information about each column in the grid and provides methods for updating/getting/reverting a cell value
EditableGridManager.Column = function(columnName, columnID, changesAllowedOnAdd, changesAllowedOnUpdate, getDelegate, setDelegate, revertDelegate) {
    this._columnName = columnName;
    this._columnID = columnID;
    this.getDelegate = getDelegate;
    this.setDelegate = setDelegate;
    this.revertDelegate = revertDelegate;
    this.changesAllowedOnAdd = changesAllowedOnAdd;
    this.changesAllowedOnUpdate = changesAllowedOnUpdate;

    this._associatedColumnName = null;
    this._hasALookup = false;
}

EditableGridManager.Column.prototype = {
    get_columnName: function() {
        return this._columnName;
    },

    get_columnID: function() {
        return this._columnID;
    },

    set_associatedColumnName: function(value) {
        this._associatedColumnName = value;
    },

    get_associatedColumnName: function() {
        return this._associatedColumnName;
    },

    set_hasALookup: function(value) {
        this._hasALookup = value;
    },

    GetValueControlManager: function(isNewRow, rowPrefix) {
        var controlManager = new EditableGridManager.ControlManager(this._columnName, this._associatedColumnName);

        this.ExecuteDelegate(this.getDelegate, controlManager, isNewRow, rowPrefix);

        return controlManager;
    },

    SetValue: function(isNewRow, rowPrefix, value, associatedValue) {
        var controlManager = new EditableGridManager.ControlManager(this._columnName, this._associatedColumnName);
        controlManager.SetValue(value);
        controlManager.SetAssociatedValue(associatedValue);

        this.ExecuteDelegate(this.setDelegate, controlManager, isNewRow, rowPrefix);
    },

    Revert: function(isNewRow, rowPrefix) {
        var controlManager = new EditableGridManager.ControlManager(this._columnName, this._associatedColumnName);
        
        this.ExecuteDelegate(this.revertDelegate, controlManager, isNewRow, rowPrefix);
    },

    ExecuteDelegate: function(delegate, controlManager, isNewRow, rowPrefix) {
        if (isNewRow) {
            delegate(controlManager, this.changesAllowedOnAdd, rowPrefix);
        }
        else {
            delegate(controlManager, this.changesAllowedOnUpdate, rowPrefix);
        }
    },

    HasALookup: function() {
        return this._hasALookup;
    }
}
//End Columm -------------------------------------------------------------------------------

//Control Manager -------------------------------------------------------------------------------
//A simple object used in getting/setting/reverting column information
EditableGridManager.ControlManager = function(columnName, associatedColumnName) {
    this._columnName = columnName;
    this._associatedColumnName = associatedColumnName;
}

EditableGridManager.ControlManager.prototype = {
    get_columnName: function() {
        return this._columnName;
    },

    get_associatedColumnName: function() {
        return this._associatedColumnName;
    },

    GetValue: function() {
        return this.value;
    },

    GetAssociatedValue: function() {
        return this.associatedValue;
    },

    SetValue: function(value) {
        this.value = value;
    },

    SetAssociatedValue: function(associatedValue) {
        this.associatedValue = associatedValue;
    }
}
//End Control Manager -------------------------------------------------------------------------------

//Lookup Manager -------------------------------------------------------------------------------
//Handles the transfer of values from the lookup iframe back to a row
EditableGridManager.LookupManager = function(lookupIframeElemID, grid, rowPrefix, url) {
    this.lookupIframeElemID = lookupIframeElemID;
    this.grid = grid;
    this.rowPrefix = rowPrefix;
    this.url = url;

    this.radLookupWindow = null;
}

EditableGridManager.LookupManager.prototype = {
    OpenLookupWindow: function() {
        this.radLookupWindow = window.radopen(this.url, this.lookupIframeElemID);

        // Size the radWindow
        this.radLookupWindow.setSize(600, 600);

        // Move the radWindow to the upper left of the screen
        this.radLookupWindow.MoveTo(50, 50);
    },

    OnLookupLoaded: function() {
        this.radLookupWindow.GetContentFrame().contentWindow.EditableGridManager.LookupManagerForLookup = this;
    },

    UpdateValue: function(returnColumnName, associatedColumnName, rowKeyValues, updateColumnName) {
        var newValue = rowKeyValues[returnColumnName];
        var newAssociatedValue = null;

        var updateColumn = this.grid.GetColumn(updateColumnName);

        var updateAssociatedColumnName = updateColumn.get_associatedColumnName();

        if (updateAssociatedColumnName != null) {
            newAssociatedValue = rowKeyValues[associatedColumnName];

            var updateAssociatedColumn = this.grid.GetColumn(updateAssociatedColumnName);

            if (updateAssociatedColumn != null) {
                updateAssociatedColumn.SetValue(true, this.rowPrefix, newAssociatedValue, null);
            }
        }

        this.grid.GetColumn(updateColumnName).SetValue(true, this.rowPrefix, newValue, newAssociatedValue);

        this.radLookupWindow.Close();
    },

    CloseWindow: function() {
        this.radLookupWindow.Close();
    }
}

//This static variable allows is set in  LookupManager.OnLookupLoaded so that when a user selects a value from the lookup
//we can call EditableGridManager.LookupManagerForLookup.UpdateValue from EditableGridManager.UpdateValue within the iframe
EditableGridManager.LookupManagerForLookup = null;

EditableGridManager.UpdateValue = function(returnColumnName, associatedColumnName, gridClientID, radioButtonsGroupName, updateColumnName) {

    //May return null/element/array
    var radioButtons = document.forms[0][radioButtonsGroupName];
    var selectedRadioButton = null;

    if (radioButtons) {
        if (radioButtons.checked) {
            selectedRadioButton = radioButtons;
        }
        else {
            for (var i = 0; i < radioButtons.length; i++) {
                if (radioButtons[i].checked) {
                    selectedRadioButton = radioButtons[i];
                }
            }
        }
    }

    if (selectedRadioButton) {
        var el = selectedRadioButton;

        var grid = $find(gridClientID);
        while (el && (el.parentNode.parentNode.parentNode != grid.get_element() && el.parentNode.parentNode.parentNode != grid._gridDataDiv && !Array.contains(grid.get_detailTables(), $find(el.parentNode.parentNode.id)))) {
            el = el.parentNode;
        }

        if (el) {
            var rowID = el.id.split("__")[1];
        }

        var rowKeyValues = grid._clientKeyValues[rowID];

        EditableGridManager.LookupManagerForLookup.UpdateValue(returnColumnName, associatedColumnName, rowKeyValues, updateColumnName);
    }
    else {
        alert("Please select an option.");
    }

    return false;
}

EditableGridManager.CloseWindow = function() {
    EditableGridManager.LookupManagerForLookup.CloseWindow();
}

//We hijack this function to allow to add validators based on validator templates
EditableGridManager.UpdateValidatorOnLoad = function() {
    if (window.ValidatorOnLoad) {
        //We override the validator methods since they have been optimized and ValidatorOnLoad does some processing to copy
        ValidatorOnLoad = EditableGridManager.ValidatorOnLoad;
        ValidatorHookupEvent = EditableGridManager.ValidatorHookupEvent;

        //We optimized the code in here and can debug this to see where performance issues are arising
        Sys.WebForms.PageRequestManager.prototype._onFormSubmitCompleted = EditableGridManager._onFormSubmitCompleted;
    }
}

EditableGridManager.ValidatorTemplate = function(validatorTemplateElem) {
    this.validatorTemplateElem = validatorTemplateElem;
    this.validatorsInfo = null;
    this.validatedElements = null;

    this.validatorProperties = null;

    this.insertValidatorInfo = null;

    this.validationGroupValidatorInfoDictionary = null;

    this.validatorValidationGroupDictionary = new Object();
}

EditableGridManager.ValidatorTemplate.prototype = {
    dispose: function() {
        for (var property in this.validatorValidationGroupDictionary) {
            this.validatorValidationGroupDictionary[property] = null;
        }

        Array.clear(this.get_validatorInfoArray());

        this.validatorTemplateElem = null;
    },

    get_RelatedGrid: function() {
        return this.validatorTemplateElem.RelatedGrid;
    },

    get_validatorInfoArray: function() {
        return window[String.format("{0}_Validators", this.validatorTemplateElem.id)];
    },

    get_ValidatorInfo: function() {
        if (this.validatorsInfo == null) {
            this.validatorsInfo = new Array();
            var validatorInfoArray = this.get_validatorInfoArray();

            Array.forEach(validatorInfoArray, validatorInfoBuilderLoop, this);
        }

        function validatorInfoBuilderLoop(validatorInfo) {
            var validatorInfo = new EditableGridManager.ValidatorInfo(this.validatorTemplateElem.ValidatorSuffix, this.validatorTemplateElem.ControlToValideSuffix, validatorInfo.id, validatorInfo.vg);

            if (validatorInfo.isInsertRowValidator()) {
                this.insertValidatorInfo = validatorInfo;
            }

            Array.add(this.validatorsInfo, validatorInfo);
        }

        return this.validatorsInfo;
    },

    get_ValidatedElementsValidatorInfoDictionary: function() {
        if (this.validatedElements == null) {
            this.validatedElements = new Object();

            Array.forEach(this.get_ValidatorInfo(), validatorInfoLoop, this);
        }

        function validatorInfoLoop(validatorInfo) {
            this.validatedElements[validatorInfo.get_ControlToValidateID()] = validatorInfo;
        }

        return this.validatedElements;
    },

    get_ValidatorValidationGroupDictionary: function() {
        return this.validatorValidationGroupDictionary;
    },

    get_ValidationGroupValidatorInfoDictionary: function() {
        if (this.validationGroupValidatorInfoDictionary == null) {
            this.validationGroupValidatorInfoDictionary = new Object();

            Array.forEach(this.get_ValidatorInfo(), buildDictionary, this);
        }

        function buildDictionary(validatorInfo) {
            this.validationGroupValidatorInfoDictionary[validatorInfo.get_ValidationGroup()] = validatorInfo;
        }

        return this.validationGroupValidatorInfoDictionary;
    },

    RegisterValidatorProperties: function(validatorElem, validationInfo) {
        if (this.validatorProperties == null) {
            this.validatorProperties = new Array();

            for (var validatorElementProperty in this.validatorTemplateElem) {
                if (validatorElementProperty != "RelatedGrid" && validatorElementProperty != "ValidatorSuffix" && validatorElementProperty != "dispose" && validatorElementProperty != "ControlToValideSuffix" && !(validatorElementProperty in validatorElem)) {
                    Array.add(this.validatorProperties, validatorElementProperty);
                }

                if (validatorElementProperty == "evaluationfunction") {
                    this.validatorTemplateElem.evaluationfunction = window[this.validatorTemplateElem.evaluationfunction];
                }
            }
        }

        //Copy the properties over from the template
        for (var i = 0; i < this.validatorProperties.length; i++) {
            var propertyToUpdate = this.validatorProperties[i];
            validatorElem[propertyToUpdate] = this.validatorTemplateElem[propertyToUpdate];
        }

        validatorElem.controltovalidate = validationInfo.get_ControlToValidateID();
        validatorElem.validationGroup = validationInfo.get_ValidationGroup();

        this.validatorValidationGroupDictionary[validatorElem.validationGroup] = validatorElem;
    },

    GetElementValidationInfo: function(elemID) {
        var validationInfoDictionary = this.get_ValidatedElementsValidatorInfoDictionary();
        if (elemID in validationInfoDictionary) {
            return validationInfoDictionary[elemID];
        }
        else {
            return null;
        }
    },

    SetupValidation: function(validatorInfo) {
        var validatorElem = $get(validatorInfo.get_ValidatorID());

        this.RegisterValidatorProperties(validatorElem, validatorInfo);

        ValidatorHookupControlID(validatorElem.controltovalidate, validatorElem);

        validatorInfo.set_ValidatedElementHasBeenSetup(true);
    }
}

EditableGridManager.ValidatorInfo = function(validatorTemplateSuffix, validatorTemplateControlToValideSuffix, validatorIDPrefix, validationGroup) {
    this.validatorID = validatorIDPrefix + validatorTemplateSuffix;
    this.controlToValidate = validatorIDPrefix + validatorTemplateControlToValideSuffix;
    this.validationGroup = validationGroup;

    this.validatedElementHasBeenSetup = false;
}

EditableGridManager.ValidatorInfo.prototype = {
    get_ValidatorID: function() {
        return this.validatorID;
    },

    get_ControlToValidateID: function() {
        return this.controlToValidate;
    },

    get_ValidationGroup: function() {
        return this.validationGroup;
    },

    get_ValidatedElementHasBeenSetup: function() {
        return this.validatedElementHasBeenSetup;
    },

    set_ValidatedElementHasBeenSetup: function(value) {
        this.validatedElementHasBeenSetup = value;
    },
    
    isInsertRowValidator: function() {
        return this.validationGroup.split("%")[1] == "-1";
    }
}


//We add validators to the client that act as a template. The validator contains information on what elements actually need to have validation
//applied to them and this is where we handle creating those validators.
EditableGridManager.ValidatorOnLoad = function() {
    if (window.Page_Validators) {
        var validatorsToRemove = new Array();
        //var validatorsToAdd = new Array();

        Array.forEach(Page_Validators, validatorsLoop);

        //We no longer need the template validators so we remove them to prevent validation done on templates.
        Array.forEach(validatorsToRemove, validatorsToRemoveLoop);
    }

    ValidationSummaryOnSubmit = MyValidationSummaryOnSubmit;

    function validatorsLoop(validator) {
        if (validator.ValidatorTemplate) {
            //Removing the validator now will mess up looping through the validators therefore we add them to array to be removed after looping.
            Array.add(validatorsToRemove, validator);
            if (validator.RelatedGrid) {
                $egm.getInstance().GetGrid(validator.RelatedGrid).RegisterValidatorTemplate(validator);
            }
        }
    }

    function validatorsToRemoveLoop(validator) {
        Array.remove(Page_Validators, validator);
    }

    //This is where the old ValidatorOnLoad code begins
    if (typeof (Page_Validators) == "undefined")
        return;
    var i, val;
    for (i = 0; i < Page_Validators.length; i++) {
        val = Page_Validators[i];
        if (typeof (val.evaluationfunction) == "string") {
            val.evaluationfunction = window[val.evaluationfunction];
        }
        if (typeof (val.isvalid) == "string") {
            if (val.isvalid == "False") {
                val.isvalid = false;
                Page_IsValid = false;
            }
            else {
                val.isvalid = true;
            }
        } else {
            val.isvalid = true;
        }
        if (typeof (val.enabled) == "string") {
            val.enabled = (val.enabled != "False");
        }
        if (typeof (val.controltovalidate) == "string") {
            ValidatorHookupControlID(val.controltovalidate, val);
        }
        if (typeof (val.controlhookup) == "string") {
            ValidatorHookupControlID(val.controlhookup, val);
        }
    }
    Page_ValidationActive = true;
}

//optimize ValidatorHookupEvent
EditableGridManager.ValidatorHookupEvent = function(control, eventType, functionPrefix) {
    var ev;
    ev = control[eventType];
    if (typeof (ev) == "function") {
        ev = ev.toString();
        ev = ev.substring(ev.indexOf("{") + 1, ev.lastIndexOf("}"));
    }
    else {
        ev = "";
    }

    var func;
    if (navigator.appName.toLowerCase().indexOf('explorer') > -1) {
        func = new Function(functionPrefix + " " + ev);
    }
    else {
        func = new Function("event", functionPrefix + " " + ev);
    }
    control[eventType] = func;
}

/*click---------------------------------------------------------------------------------------*/
//This funciton didn't allow for nested elements. We modified it to so that the row change will happen on nested elements too.
EditableGridManager._click = function(e) {
    var el = (e.target) ? e.target : e.srcElement;
    if (!el.tagName) {
        return;
    }
    if (this._owner.ClientSettings.Selecting && this._owner.ClientSettings.Selecting.AllowRowSelect) {
        var _147 = (el.tagName.toLowerCase() == "input" && el.type.toLowerCase() == "checkbox" && (el.id && el.id.indexOf("SelectCheckBox") != -1));
        /* Previous Code */
        //            if ((el.tagName.toLowerCase() == "input" && !_147) || el.tagName.toLowerCase() == "select" || el.tagName.toLowerCase() == "option" || el.tagName.toLowerCase() == "button" || el.tagName.toLowerCase() == "a" || el.tagName.toLowerCase() == "textarea" || el.tagName.toLowerCase() == "img") {
        //                return;
        //            }
        /* End Previous Code */
        /*New Code*/
        var newEl = el;
        var greatGrandParentNode = newEl;
        function hasParentNodeAtLevel(elem, levels) {
            if (levels == 1)
                return elem.parentNode != null;
            else if (elem.parentNode)
                return hasParentNodeAtLevel(elem.parentNode, levels - 1);
            else
                return false;
        }

        while (newEl && hasParentNodeAtLevel(newEl, 3) && (newEl.parentNode.parentNode.parentNode != this._owner.get_element() && newEl.parentNode.parentNode.parentNode != this._owner._gridDataDiv && !Array.contains(this._owner.get_detailTables(), $find(newEl.parentNode.parentNode.id)))) {
            newEl = newEl.parentNode;
        }
        if (newEl) {
            el = newEl
        }
        /*End New Code*/
        if (el.tagName.toLowerCase() != "tr") {
            el = Telerik.Web.UI.Grid.GetFirstParentByTagName(el, "tr");
        }
        if (el && (el.parentNode.parentNode.parentNode == this._owner.get_element() || el.parentNode.parentNode.parentNode == this._owner._gridDataDiv || Array.contains(this._owner.get_detailTables(), $find(el.parentNode.parentNode.id))) && el.id && el.id.split("__").length == 2) {
            if (this._owner.get_AllowMultiRowSelection()) {
                if (e.shiftKey && this._owner._selectedItemsInternal[0]) {
                    var _148 = $get(this._owner._selectedItemsInternal[0].id);
                    if (_148.rowIndex > el.rowIndex) {
                        for (var i = el.rowIndex; i < _148.rowIndex + 1; i++) {
                            var tr = _148.parentNode.parentNode.rows[i];
                            if (tr.id) {
                                this._selectRowInternal(tr, e, true, false, true);
                            }
                        }
                    }
                    if (_148.rowIndex < el.rowIndex) {
                        for (var i = _148.rowIndex; i < el.rowIndex + 1; i++) {
                            var tr = _148.parentNode.parentNode.rows[i];
                            if (tr.id) {
                                this._selectRowInternal(tr, e, true, false, true);
                            }
                        }
                    }
                    return;
                }
                this._selectRowInternal(el, e, _147, true, true);
            } else {
                this._selectRowInternal(el, e, false, false, true);
            }
        }
    }
    if (this._owner.ClientSettings && this._owner.ClientSettings.EnablePostBackOnRowClick && el) {
        if (el && el.tagName.toLowerCase() != "tr") {
            el = Telerik.Web.UI.Grid.GetFirstParentByTagName(el, "tr");
        }
        if (el && el.id != "" && el.id.split("__").length == 2) {
            var _14b = el.id.split("__")[1];
            var _14c = this._owner.ClientSettings.PostBackFunction;
            _14c = _14c.replace("{0}", this._owner.UniqueID);
            _14c = _14c.replace("{1}", "RowClick;" + _14b);
            setTimeout(function() {
                eval(_14c);
            }, 100);
        }
    }
}

//There was a bug in this function so this fixes it.
EditableGridManager._resizeGridOnColumnResize = function(_206, _207) {
    var _208;
    var _209;
    var _20a;
    if (this == this._owner.get_masterTableViewHeader()) {
        for (var i = 0; i < this.ColGroup.Cols.length; i++) {
            if (i != _206 && this.ColGroup.Cols[i].width == "") {
                this.ColGroup.Cols[i].width = this.HeaderRow.cells[i].scrollWidth + "px";
                this._owner.get_masterTableView().ColGroup.Cols[i].width = this.ColGroup.Cols[i].width;
                if (this._owner.get_masterTableViewFooter() &&
                    this._owner.get_masterTableViewFooter().ColGroup) {
                    this._owner.get_masterTableViewFooter().ColGroup.Cols[i].width = this.ColGroup.Cols[i].width;
                }
            }
        }
        this.get_element().style.width = (this.get_element().offsetWidth - _207) + "px";
        this._owner.get_masterTableView().get_element().style.width = this.get_element().style.width;
        if (this._owner.get_masterTableViewFooter() &&
            this._owner.get_masterTableViewFooter().get_element()) {
            this._owner.get_masterTableViewFooter().get_element().style.width = this.get_element().style.width;
        }
        var _20c = (this.get_element().scrollWidth > this.get_element().offsetWidth) ? this.get_element().scrollWidth : this.get_element().offsetWidth;
        var _20d = this._owner._gridDataDiv.offsetWidth;
        _208 = _20c + "px";
        _209 = _20d + "px";
        _20a = this._owner.get_element().offsetHeight + "px";
    } else {
        if (window.netscape || $telerik.isOpera) {
            this.get_element().style.width = (this.get_element().offsetWidth - _207) + "px";
            this._owner.get_element().style.width = this.get_element().style.width;
        }
        var _20c = (this.get_element().scrollWidth > this.get_element().offsetWidth) ? this.get_element().scrollWidth : this.get_element().offsetWidth;
        _208 = _20c + "px";
        _209 = this._owner.get_element().offsetWidth + "px";
        _20a = this._owner.get_element().offsetHeight + "px";
    }
    this._owner._resizedControl += this._data.UniqueID + "," + _208 + "," + _209 + "," + _20a + ";";
    this._owner.updateClientState();
}


Array.AddArrayToArray = function(arrayToAddToName, arrayToAdd) {
    if (typeof (window[arrayToAddToName]) === "undefined") {
        window[arrayToAddToName] = arrayToAdd;
    }
    else {
        Array.addRange(window[arrayToAddToName], arrayToAdd);
    }
}

EditableGridManager._onFormSubmitCompleted = function(sender, eventArgs) {
    this._processingRequest = true;

    var delimitByLengthDelimiter = '|';

    if (sender.get_timedOut()) {
        this._endPostBack(this._createPageRequestManagerTimeoutError(), sender);
        return;
    }

    if (sender.get_aborted()) {
        this._endPostBack(null, sender);
        return;
    }

    if (!this._request || sender.get_webRequest() !== this._request) {
        return;
    }

    var errorMessage;

    var delta = [];

    if (sender.get_statusCode() !== 200) {
        this._endPostBack(this._createPageRequestManagerServerError(sender.get_statusCode()), sender);
        return;
    }

    var reply = sender.get_responseData();
    var delimiterIndex, len, type, id, content;
    var replyIndex = 0;
    var parserErrorDetails = null;

    while (replyIndex < reply.length) {
        delimiterIndex = reply.indexOf(delimitByLengthDelimiter, replyIndex);
        if (delimiterIndex === -1) {
            parserErrorDetails = this._findText(reply, replyIndex);
            break;
        }

        len = parseInt(reply.substring(replyIndex, delimiterIndex), 10);

        if ((len % 1) !== 0) {
            parserErrorDetails = this._findText(reply, replyIndex);
            break;
        }

        replyIndex = delimiterIndex + 1;

        delimiterIndex = reply.indexOf(delimitByLengthDelimiter, replyIndex);

        if (delimiterIndex === -1) {
            parserErrorDetails = this._findText(reply, replyIndex);
            break;
        }

        type = reply.substring(replyIndex, delimiterIndex);

        replyIndex = delimiterIndex + 1;

        delimiterIndex = reply.indexOf(delimitByLengthDelimiter, replyIndex);

        if (delimiterIndex === -1) {
            parserErrorDetails = this._findText(reply, replyIndex);
            break;
        }

        id = reply.substring(replyIndex, delimiterIndex);

        replyIndex = delimiterIndex + 1;

        if ((replyIndex + len) >= reply.length) {
            parserErrorDetails = this._findText(reply, reply.length);
            break;
        }

        content = this._decodeString(reply.substr(replyIndex, len));

        replyIndex += len;

        if (reply.charAt(replyIndex) !== delimitByLengthDelimiter) {
            parserErrorDetails = this._findText(reply, replyIndex);
            break;
        }

        replyIndex++;

        Array.add(delta, { type: type, id: id, content: content });
    }


    if (parserErrorDetails) {
        this._endPostBack(this._createPageRequestManagerParserError(String.format(Sys.WebForms.Res.PRM_ParserErrorDetails, parserErrorDetails)), sender);
        return;
    }

    var updatePanelNodes = [];

    var hiddenFieldNodes = [];

    var arrayDeclarationNodes = [];

    var scriptBlockNodes = [];

    var expandoNodes = [];

    var onSubmitNodes = [];

    var dataItemNodes = [];

    var dataItemJsonNodes = [];

    var scriptDisposeNodes = [];

    var asyncPostBackControlIDsNode, postBackControlIDsNode,
            updatePanelIDsNode, asyncPostBackTimeoutNode,
            childUpdatePanelIDsNode, panelsToRefreshNode, formActionNode;

    for (var i = 0; i < delta.length; i++) {
        var deltaNode = delta[i];

        switch (deltaNode.type) {
            case "updatePanel":
                Array.add(updatePanelNodes, deltaNode);
                break;
            case "hiddenField":
                Array.add(hiddenFieldNodes, deltaNode);
                break;
            case "arrayDeclaration":
                Array.add(arrayDeclarationNodes, deltaNode);
                break;
            case "scriptBlock":
                Array.add(scriptBlockNodes, deltaNode);
                break;
            case "expando":
                Array.add(expandoNodes, deltaNode);
                break;
            case "onSubmit":
                Array.add(onSubmitNodes, deltaNode);
                break;
            case "asyncPostBackControlIDs":
                asyncPostBackControlIDsNode = deltaNode;
                break;
            case "postBackControlIDs":
                postBackControlIDsNode = deltaNode;
                break;
            case "updatePanelIDs":
                updatePanelIDsNode = deltaNode;
                break;
            case "asyncPostBackTimeout":
                asyncPostBackTimeoutNode = deltaNode;
                break;
            case "childUpdatePanelIDs":
                childUpdatePanelIDsNode = deltaNode;
                break;
            case "panelsToRefreshIDs":
                panelsToRefreshNode = deltaNode;
                break;
            case "formAction":
                formActionNode = deltaNode;
                break;
            case "dataItem":
                Array.add(dataItemNodes, deltaNode);
                break;
            case "dataItemJson":
                Array.add(dataItemJsonNodes, deltaNode);
                break;
            case "scriptDispose":
                Array.add(scriptDisposeNodes, deltaNode);
                break;
            case "pageRedirect":
                window.location.href = deltaNode.content;
                return;
            case "error":
                this._endPostBack(this._createPageRequestManagerServerError(Number.parseInvariant(deltaNode.id), deltaNode.content), sender);
                return;
            case "pageTitle":
                document.title = deltaNode.content;
                break;
            case "focus":
                this._controlIDToFocus = deltaNode.content;
                break;
            default:
                this._endPostBack(this._createPageRequestManagerParserError(String.format(Sys.WebForms.Res.PRM_UnknownToken, deltaNode.type)), sender);
                return;
        }
    }

    var i;

    if (asyncPostBackControlIDsNode && postBackControlIDsNode &&
            updatePanelIDsNode && panelsToRefreshNode &&
            asyncPostBackTimeoutNode && childUpdatePanelIDsNode) {

        this._oldUpdatePanelIDs = this._updatePanelIDs;

        var childUpdatePanelIDsString = childUpdatePanelIDsNode.content;

        this._childUpdatePanelIDs = childUpdatePanelIDsString.length ? childUpdatePanelIDsString.split(',') : [];

        var asyncPostBackControlIDsArray = this._splitNodeIntoArray(asyncPostBackControlIDsNode);

        var postBackControlIDsArray = this._splitNodeIntoArray(postBackControlIDsNode);

        var updatePanelIDsArray = this._splitNodeIntoArray(updatePanelIDsNode);

        this._panelsToRefreshIDs = this._splitNodeIntoArray(panelsToRefreshNode);

        for (i = 0; i < this._panelsToRefreshIDs.length; i++) {

            var panelClientID = this._uniqueIDToClientID(this._panelsToRefreshIDs[i]);

            if (!document.getElementById(panelClientID)) {
                this._endPostBack(Error.invalidOperation(String.format(Sys.WebForms.Res.PRM_MissingPanel, panelClientID)), sender);
                return;
            }
        }

        var asyncPostBackTimeout = asyncPostBackTimeoutNode.content;

        this._updateControls(updatePanelIDsArray, asyncPostBackControlIDsArray, postBackControlIDsArray, asyncPostBackTimeout);
    }

    this._dataItems = {};

    for (i = 0; i < dataItemNodes.length; i++) {
        var dataItemNode = dataItemNodes[i];
        this._dataItems[dataItemNode.id] = dataItemNode.content;
    }

    for (i = 0; i < dataItemJsonNodes.length; i++) {
        var dataItemJsonNode = dataItemJsonNodes[i];
        this._dataItems[dataItemJsonNode.id] = eval(dataItemJsonNode.content);
    }

    var handler = this._get_eventHandlerList().getHandler("pageLoading");

    if (handler) {
        handler(this, this._getPageLoadingEventArgs());
    }

    if (formActionNode) {
        this._form.action = formActionNode.content;
        this._form._initialAction = this._form.action;
    }

    for (i = 0; i < updatePanelNodes.length; i++) {

        var deltaUpdatePanel = updatePanelNodes[i];

        var deltaPanelID = deltaUpdatePanel.id;

        var deltaPanelRendering = deltaUpdatePanel.content;

        var updatePanelElement = document.getElementById(deltaPanelID);

        if (!updatePanelElement) {
            this._endPostBack(Error.invalidOperation(String.format(Sys.WebForms.Res.PRM_MissingPanel, deltaPanelID)), sender);
            return;
        }

        this._updatePanel(updatePanelElement, deltaPanelRendering);
    }

    for (i = 0; i < scriptDisposeNodes.length; i++) {
        var disposePanelId = scriptDisposeNodes[i].id;

        var disposeScript = scriptDisposeNodes[i].content;

        this._registerDisposeScript(disposePanelId, disposeScript);
    }

    for (i = 0; i < hiddenFieldNodes.length; i++) {
        var id = hiddenFieldNodes[i].id;
        var value = hiddenFieldNodes[i].content;

        var hiddenFieldElement = document.getElementById(id);

        if (!hiddenFieldElement) {
            hiddenFieldElement = document.createElement('input');
            hiddenFieldElement.id = id;
            hiddenFieldElement.name = id;
            hiddenFieldElement.type = 'hidden';
            this._form.appendChild(hiddenFieldElement);
        }

        hiddenFieldElement.value = value;
    }

    var arrayScript = '';

    var arrayScripts = new Object();

    //Build object of arrays based on variable name
    for (i = 0; i < arrayDeclarationNodes.length; i++) {
        if (!(arrayDeclarationNodes[i].id in arrayScripts)) {
            arrayScripts[arrayDeclarationNodes[i].id] = new Array();
            var declearationString = String.format("Array.AddArrayToArray('{0}', [{1}", arrayDeclarationNodes[i].id, arrayDeclarationNodes[i].content);
            Array.add(arrayScripts[arrayDeclarationNodes[i].id], declearationString);
        }
        else {
            Array.add(arrayScripts[arrayDeclarationNodes[i].id], "," + arrayDeclarationNodes[i].content);
        }
    }

    var arrayScriptsScriptBuilder = new Array();

    for (var objectName in arrayScripts) {
        Array.add(arrayScripts[objectName], "]);\r\n");
        Array.add(arrayScriptsScriptBuilder, arrayScripts[objectName].join(""));
    }

    arrayScript = arrayScriptsScriptBuilder.join("");

    var expandoScript = '';

    var expandoScriptsBuilder = new Array();

    for (i = 0; i < expandoNodes.length; i++) {
        var propertyReference = expandoNodes[i].id;
        var propertyValue = expandoNodes[i].content;
        Array.add(expandoScriptsBuilder, propertyReference + " = " + propertyValue + "\r\n");
    }

    expandoScript = expandoScriptsBuilder.join("");

    Sys._ScriptLoader.readLoadedScripts();

    Sys.Application.beginCreateComponents();

    var scriptLoader = Sys._ScriptLoader.getInstance();

    if (arrayScript.length) {
        scriptLoader.queueScriptBlock(arrayScript);
    }

    if (expandoScript.length) {
        scriptLoader.queueScriptBlock(expandoScript);
    }

    for (i = 0; i < scriptBlockNodes.length; i++) {

        var scriptBlockType = scriptBlockNodes[i].id;

        switch (scriptBlockType) {
            case "ScriptContentNoTags":
                scriptLoader.queueScriptBlock(scriptBlockNodes[i].content);
                break;
            case "ScriptContentWithTags":
                var scriptTagAttributes;
                eval("scriptTagAttributes = " + scriptBlockNodes[i].content);
                if (scriptTagAttributes.src && Sys._ScriptLoader.isScriptLoaded(scriptTagAttributes.src)) {
                    continue;
                }

                scriptLoader.queueCustomScriptTag(scriptTagAttributes);

                break;

            case "ScriptPath":
                if (Sys._ScriptLoader.isScriptLoaded(scriptBlockNodes[i].content)) {
                    continue;
                }

                scriptLoader.queueScriptReference(scriptBlockNodes[i].content);
                break;
        }

    }

    var onSubmitStatementScript = '';

    for (var i = 0; i < onSubmitNodes.length; i++) {
        if (i === 0) {
            onSubmitStatementScript = 'Array.add(Sys.WebForms.PageRequestManager.getInstance()._onSubmitStatements, function() {\r\n';
        }

        onSubmitStatementScript += onSubmitNodes[i].content + "\r\n";
    }

    if (onSubmitStatementScript.length) {
        onSubmitStatementScript += "\r\nreturn true;\r\n});\r\n";
        scriptLoader.queueScriptBlock(onSubmitStatementScript);
    }

    this._response = sender;

    scriptLoader.loadScripts(0, Function.createDelegate(this, this._scriptsLoadComplete), null, null);
}


MyValidationSummaryOnSubmit = function(validationGroup) {
    if (typeof (Page_ValidationSummaries) == "undefined")
        return;
    var summary, sums, s;
    for (sums = 0; sums < Page_ValidationSummaries.length; sums++) {
        summary = Page_ValidationSummaries[sums];
        summary.style.display = "none";

        var summaryContainer = summary.parentNode;
        while (summaryContainer) {
            if (summaryContainer.className == "ValidationSummary") {
                summaryContainer.style.display = "block";
                break;
            }

            summaryContainer = summaryContainer.parentNode;
        }

        if (summaryContainer) {
            summaryContainer.style.display = "none";
        }

        if (!Page_IsValid && IsValidationGroupMatch(summary, validationGroup)) {
            var i;
            if (summary.showsummary != "False") {
                summary.style.display = "";
                if (typeof (summary.displaymode) != "string") {
                    summary.displaymode = "BulletList";
                }
                switch (summary.displaymode) {
                    case "List":
                        headerSep = "<br>";
                        first = "";
                        pre = "";
                        post = "<br>";
                        end = "";
                        break;
                    case "BulletList":
                    default:
                        headerSep = "";
                        first = "<ul>";
                        pre = "<li>";
                        post = "</li>";
                        end = "</ul>";
                        break;
                    case "SingleParagraph":
                        headerSep = " ";
                        first = "";
                        pre = "";
                        post = " ";
                        end = "<br>";
                        break;
                }
                s = "";
                if (typeof (summary.headertext) == "string") {
                    s += summary.headertext + headerSep;
                }
                s += first;
                for (i = 0; i < Page_Validators.length; i++) {
                    if (!Page_Validators[i].isvalid && typeof (Page_Validators[i].errormessage) == "string") {
                        s += pre + Page_Validators[i].errormessage + post;

                    }
                }
                s += end;
                summary.innerHTML = s;

                if (summaryContainer) {
                    summaryContainer.style.display = "block";
                }
                
                window.scrollTo(0, 0);
            }
            if (summary.showmessagebox == "True") {
                s = "";
                if (typeof (summary.headertext) == "string") {
                    s += summary.headertext + "\r\n";
                }
                var lastValIndex = Page_Validators.length - 1;
                for (i = 0; i <= lastValIndex; i++) {
                    if (!Page_Validators[i].isvalid && typeof (Page_Validators[i].errormessage) == "string") {
                        switch (summary.displaymode) {
                            case "List":
                                s += Page_Validators[i].errormessage;
                                if (i < lastValIndex) {
                                    s += "\r\n";
                                }
                                break;
                            case "BulletList":
                            default:
                                s += "- " + Page_Validators[i].errormessage;
                                if (i < lastValIndex) {
                                    s += "\r\n";
                                }
                                break;
                            case "SingleParagraph":
                                s += Page_Validators[i].errormessage + " ";
                                break;
                        }
                    }
                }
                alert(s);
            }
        }
    }
}