var wNoResults = wTherearecurrentlynorowstodisplay; //"There are currently no rows to display.";
var wNoResultsCriteria = wTherearenoresultsfor0; //"There are no results for {criteria}.";
var WLDateFormat = jsDateFormat;
var WLLongDateFormat = jsWLLongDateFormat;
var WLLongDateTimeFormat = JsWLLongDateTimeFormat;
var regex = new RegExp(/{(.*?)}/i);
var wWorkingDataTablePatientList = JSON.parse("{}");
var wMasterDataTable = JSON.parse("{}");
var wWorkingDataTable = JSON.parse("{}");
var wDataTableCounter = JSON.parse("{}");
var wFilteringDataTable = JSON.parse("{}");
var wSystemConfiguredFilteringe = JSON.parse("{}");
var wFilteringSentence = JSON.parse("{}");
var wSortingDataTable = JSON.parse("{}");
var wGridCellCtrls = JSON.parse("{}");
var wDynamicGridCellCtrls = JSON.parse("{}");
var wGridAttributes = JSON.parse("{}");
var wGridObj = JSON.parse("{}");
var ShiftClicked = false;
var ActiveTabLoading = true;
var wGridRefreshTimer = {};
//var wGridRefreshTimerCounter = JSON.parse('{}');
//var refreshInterval = 0;
//var refreshCounterInterval = 60000;
var wAccountProxyElem = $("#cbxAccountProxy").length;
var wLoggedinPhyscianKey = $("#LoggedinPersonKey").length;
if (wAccountProxyElem > 0) {
    wActiveWorkingPersonKey = $("#cbxAccountProxy option:selected").val();
} else if (wLoggedinPhyscianKey > 0) {
    wActiveWorkingPersonKey = $("#LoggedinPersonKey").text();
}
function RegisterTableData(
    GuidID,
    jSonData,
    ColumnCtrls,
    DynamicColumnCtrls,
    GridAttributes
) {
    this.GuidID = GuidID;
    this.ActiveTabName = "";
    this.ActiveDataGuidName = GuidID;
    this.GridRefreshTimerCounter = JSON.parse("{}");
    this.ActiveTabLoading = true;
    //set ActiveTab(val){
    //    ActiveDataGuidName = GuidID;
    //    if (val !== undefined && val != null && val != "") {
    //        ActiveDataGuidName = GuidID + "_" + val;
    //    }
    //    this.ActiveTabName = value;
    //}
    if (GridAttributes.PrimaryKey != null) {
        this.PrimaryKey = GridAttributes.PrimaryKey;
    }
    if (GridAttributes.ActiveTabLoading != null) {
        this.ActiveTabLoading = GridAttributes.ActiveTabLoading;
        ActiveTabLoading = GridAttributes.ActiveTabLoading;
    }
    wGridObj[this.GuidID] = this;
    if (jSonData == null) {
        jSonData = JSON.parse("{}");
    }
    wMasterDataTable[
        this.ActiveTabLoading ? this.ActiveDataGuidName : this.GuidID
    ] = jSonData;
    wWorkingDataTable[
        this.ActiveTabLoading ? this.ActiveDataGuidName : this.GuidID
    ] = jSonData;
    wFilteringSentence[
        this.ActiveTabLoading ? this.ActiveDataGuidName : this.GuidID
    ] = "";
    //wFilteringDataTable[GuidID] = JSON.parse('{"first_name": ["andrew", "Drema"], "first_name": ["andrew", "Drema"],"requested_date":{"End": "-10","Start": "1982-10-10"}}');
    //wFilteringDataTable[GuidID] = JSON.parse('{"last_name": "reschedule", "filler_order_number": [8114, 8115],"requested_date":{"End": "-10","Start": "1982-10-10"}}');
    //wFilteringDataTable[GuidID] = JSON.parse('{"last_name": "reschedule", "requested_date":{"End": "-10","Start": "1982-10-10"}}');
    wFilteringDataTable[this.GuidID] = JSON.parse("{}");
    wGridCellCtrls[this.GuidID] = ColumnCtrls;
    wDynamicGridCellCtrls[this.GuidID] = DynamicColumnCtrls;
    wGridAttributes[this.GuidID] = GridAttributes;
    if (GridAttributes.SortBy != null) {
        wSortingDataTable[
            this.ActiveTabLoading ? this.ActiveDataGuidName : this.GuidID
        ] = GridAttributes.SortBy;
        SortWL(this.GuidID, this.ActiveDataGuidName);
    } else if (wGridAttributes[this.GuidID]["GroupByData"]) {
        SortWL(this.GuidID, this.ActiveDataGuidName);
    } else if (GridAttributes.DownloadingData) {
        BuildGridLoadingspinner(this.GuidID, this.ActiveDataGuidName);
    } else {
        BuildGridResults(this.GuidID, this.ActiveDataGuidName);
    }
    //FilterWL(GuidID)
    //this.GenerateWLPerPages();
    GenerateWLPerPages(this.GuidID, this.ActiveDataGuidName);
    GenerateWLPages(this.GuidID, this.ActiveDataGuidName);
}
RegisterTableData.prototype.SetActiveTabName = function (aTabName) {
    this.ActiveTabName = aTabName;
    this.ActiveDataGuidName = this.GuidID + "_" + aTabName;
    var wGrid = $("#" + this.GuidID + "");
    wGrid.attr("ActiveTabName", aTabName);
};
RegisterTableData.prototype.MasterData = function () {
    return wMasterDataTable;
};
RegisterTableData.prototype.attr = function (attributeName, value) {
    var wGrid = $("#" + this.GuidID + "");
    var GridAttrValue = "";
    if (!value) {
        GridAttrValue = wGrid.attr(attributeName);
    } else {
        wGrid.attr(attributeName, value);
        GridAttrValue = value;
    }
    return GridAttrValue;
};
RegisterTableData.prototype.ShowLoader = function () {
    var wWLRows = "";
    var GuidID = this.GuidID;
    var wGrid = $("#" + GuidID + "");
    var wGridColumns = $("#" + GuidID + " thead tr th");
    var wGridArea = $("#" + GuidID + " tbody");
    wWLRows += '
';
    wWLRows += '| ';
    wWLRows +=
        '';
    wWLRows += " | ";
    wWLRows += "
";
    $(wGridArea[0]).empty();
    $(wGridArea[0]).append(wWLRows);
    GenerateSpinner();
};
RegisterTableData.prototype.GridPatientList = function (aTabName, PatientList) {
    var wDatObjectName = this.GuidID;
    if (aTabName !== undefined && aTabName != null && aTabName != "") {
        wDatObjectName = this.GuidID + "_" + aTabName;
    }
    wWorkingDataTablePatientList[wDatObjectName] = PatientList;
};
RegisterTableData.prototype.UpdateData = function (
    wJsonData,
    aSearchCriteria,
    StayOnCurrentPage
) {
    this.UpdateGridData("", wJsonData, aSearchCriteria, StayOnCurrentPage);
};
RegisterTableData.prototype.UpdateGridCountData = function (
    aTabName,
    wDataCount
) {
    var wGrid = $("#" + this.GuidID + "");
    wDataTableCounter[wDatContainerName] = null;
    var wDatContainerName = this.GuidID;
    if (aTabName !== undefined && aTabName != null && aTabName != "") {
        wDatContainerName = this.GuidID + "_" + aTabName;
    }
    wDataTableCounter[wDatContainerName] = wDataCount;
};
RegisterTableData.prototype.UpdateGridData = function (
    aTabName,
    wJsonData,
    aSearchCriteria,
    StayOnCurrentPage
) {
    //var wJsonStringData = JSON.stringify(wJsonData);
    //wJsonStringData = wJsonStringData.replace(/\"/g, "\\"").replace(/\'/g, "\\'")
    //wJsonData = JSON.parse(wJsonStringData);
    $("#" + this.GuidID + " tfoot").show();
    StayOnCurrentPage =
        StayOnCurrentPage == null || StayOnCurrentPage == ""
            ? false
            : typeof StayOnCurrentPage !== "undefined"
              ? StayOnCurrentPage
              : false;
    var wGrid = $("#" + this.GuidID + "");
    var CurrentWLPage = wGrid.attr("Current-page") * 1;
    if (wJsonData == "[]") {
        jSonData = JSON.parse("{}");
    }
    if (aTabName == this.ActiveTabName) {
        $(document).trigger("WLUpdate", {
            GuidID: this.GuidID,
            WLData: wJsonData,
        });
    }
    var wDatObjectName = this.GuidID;
    if (aTabName !== undefined && aTabName != null && aTabName != "") {
        wDatObjectName = this.GuidID + "_" + aTabName;
    }
    wMasterDataTable[wDatObjectName] = wJsonData;
    wWorkingDataTable[wDatObjectName] = wJsonData;
    wFilteringSentence[this.GuidID] = "";
    if (aSearchCriteria != null && aSearchCriteria != "") {
        this.SearchCriteria = aSearchCriteria;
    }
    if (this.ActiveTabLoading) {
        if (aTabName == this.ActiveTabName) {
            FilterWL(this.GuidID, this.ActiveDataGuidName);
            SortWL(this.GuidID, this.ActiveDataGuidName);
            GenerateWLPerPages(this.GuidID, this.ActiveDataGuidName);
            //BuildGridResults(this.GuidID)
            GenerateWLPages(this.GuidID, this.ActiveDataGuidName);
            if (StayOnCurrentPage) {
                changePage(this.GuidID, CurrentWLPage, this.ActiveDataGuidName);
            } else {
                changePage(this.GuidID, 1, this.ActiveDataGuidName);
            }
        }
    } else {
        FilterWL(this.GuidID);
        SortWL(this.GuidID);
        GenerateWLPerPages(this.GuidID);
        //BuildGridResults(this.GuidID)
        GenerateWLPages(this.GuidID);
        if (StayOnCurrentPage) {
            changePage(this.GuidID, CurrentWLPage);
        } else {
            changePage(this.GuidID, 1);
        }
    }
};
RegisterTableData.prototype.GridRefreshTimer = function (aTabName) {
    var wDatObjectName = this.GuidID;
    if (aTabName !== undefined && aTabName != null && aTabName != "") {
        wDatObjectName = this.GuidID + "_" + aTabName;
    }
    wGridRefreshTimer[wDatObjectName] = setTimeout(
        "UpdateTabGridTimer('" + this.GuidID + "', '" + aTabName + "')",
        refreshCounterInterval
    );
};
RegisterTableData.prototype.LoadingGridResults = function () {
    var wWLRows = "";
    var wGrid = $("#" + this.GuidID + "");
    var wGridColumns = $("#" + this.GuidID + " thead tr th");
    var wGridArea = $("#" + this.GuidID + " tbody");
    var GuidID = this.GuidID;
    var CurrentGroupByDataValue;
    var GroupBy =
        wGridAttributes[GuidID]["GroupByData"] != null &&
        Object.keys(wGridAttributes[GuidID]["GroupByData"]).length > 0
            ? true
            : false;
    $(wGridArea[0]).empty();
    wWLRows += '';
    wWLRows += '| ';
    wWLRows +=
        '';
    wWLRows += " | ";
    wWLRows += "
";
    $(wGridArea[0]).empty();
    $(wGridArea[0]).append(wWLRows);
    GenerateSpinner();
};
RegisterTableData.prototype.RebuildResults = function () {
    SortWL(this.GuidID, this.ActiveDataGuidName);
    GenerateWLPerPages(this.GuidID, this.ActiveDataGuidName);
    BuildGridResults(this.GuidID, this.ActiveDataGuidName);
    GenerateWLPages(this.GuidID, this.ActiveDataGuidName);
};
RegisterTableData.prototype.findAndRemove = function (
    aColumn,
    aValue,
    aRebuildResults
) {
    jsonMasterData =
        wMasterDataTable[
            this.ActiveTabLoading ? this.ActiveDataGuidName : this.GuidID
        ];
    $.each(jsonMasterData, function (index, result) {
        if (result != undefined) {
            if (result[aColumn] == aValue) {
                //Remove from array
                jsonMasterData.splice(index, 1);
            }
        }
    });
    jsonData =
        wWorkingDataTable[
            this.ActiveTabLoading ? this.ActiveDataGuidName : this.GuidID
        ];
    $.each(jsonData, function (index, result) {
        if (result != undefined) {
            if (result[aColumn] == aValue) {
                //Remove from array
                jsonData.splice(index, 1);
                return false;
            }
        }
    });
    if (aRebuildResults !== undefined && aRebuildResults) {
        this.RebuildResults();
    }
};
RegisterTableData.prototype.AddRow = function (row, aRebuildResults) {
    jsonMasterData =
        wMasterDataTable[
            this.ActiveTabLoading ? this.ActiveDataGuidName : this.GuidID
        ];
    jsonMasterData.push(row);
    jsonData =
        wWorkingDataTable[
            this.ActiveTabLoading ? this.ActiveDataGuidName : this.GuidID
        ];
    jsonData.push(row);
    if (aRebuildResults === Boolean && aRebuildResults) {
        this.RebuildResults();
    }
};
RegisterTableData.prototype.GetCount = function () {
    jsonData =
        wWorkingDataTable[
            this.ActiveTabLoading ? this.ActiveDataGuidName : this.GuidID
        ];
    return jsonData.length;
};
RegisterTableData.prototype.Find = function (aValue) {
    return this.FindBy(this.PrimaryKey, aValue);
};
RegisterTableData.prototype.FindBy = function (aColumnName, aValue) {
    if (aColumnName == null) {
        console.log("No Column Defined");
        return null;
    }
    return Enumerable.From(wWorkingDataTable[this.ActiveDataGuidName])
        .Where("$." + aColumnName + "=='" + aValue + "'")
        .ToArray();
};
RegisterTableData.prototype.Where = function (aQuery) {
    return Enumerable.From(wWorkingDataTable[this.ActiveDataGuidName])
        .Where(aQuery)
        .ToArray();
};
RegisterTableData.prototype.SentencedFilterCritera = function () {
    return wFilteringSentence[this.GuidID];
};
RegisterTableData.prototype.AppliedSort = function () {
    return wSortingDataTable[this.GuidID];
};
RegisterTableData.prototype.ApplySort = function (aSort) {
    if (
        typeof aSort === "object" &&
        wActiveWorkingPersonKey !== undefined &&
        wActiveWorkingPersonKey > -1 &&
        wActiveWorkingPersonKey in aSort
    ) {
        if (wSortingDataTable[this.ActiveDataGuidName] == null) {
            wSortingDataTable[this.ActiveDataGuidName] = JSON.parse("{}");
        }
        wSortingDataTable[this.GuidID] = JSON.parse("{}");
        wSortingDataTable[this.GuidID] = aSort[wActiveWorkingPersonKey];
        wSortingDataTable[this.ActiveDataGuidName] =
            aSort[wActiveWorkingPersonKey];
        SortWL(this.GuidID, this.ActiveDataGuidName);
    } else {
        if (wSortingDataTable[this.ActiveDataGuidName] == null) {
            wSortingDataTable[this.ActiveDataGuidName] = JSON.parse("{}");
        }
        wSortingDataTable[this.GuidID] = JSON.parse("{}");
        wSortingDataTable[this.GuidID] = aSort;
        wSortingDataTable[this.ActiveDataGuidName] = aSort;
        SortWL(this.GuidID, this.ActiveDataGuidName);
    }
};
RegisterTableData.prototype.AppliedFilter = function () {
    return wFilteringDataTable[this.GuidID];
};
RegisterTableData.prototype.ApplyFilter = function (aQuery) {
    if (
        typeof aQuery === "object" &&
        wActiveWorkingPersonKey !== undefined &&
        wActiveWorkingPersonKey > -1 &&
        wActiveWorkingPersonKey in aQuery
    ) {
        wFilteringDataTable[this.GuidID] = JSON.parse("{}");
        wFilteringDataTable[this.GuidID] = aQuery[wActiveWorkingPersonKey];
        FilterWL(this.GuidID, this.ActiveDataGuidName);
    } else {
        wFilteringDataTable[this.GuidID] = JSON.parse("{}");
        wFilteringDataTable[this.GuidID] = aQuery;
        FilterWL(this.GuidID, this.ActiveDataGuidName);
    }
};
RegisterTableData.prototype.ApplySystemFilter = function (aQuery) {
    if (
        typeof aQuery === "object" &&
        wActiveWorkingPersonKey !== undefined &&
        wActiveWorkingPersonKey > -1 &&
        wActiveWorkingPersonKey in aQuery
    ) {
        wSystemConfiguredFilteringe[this.GuidID] = JSON.parse("{}");
        wSystemConfiguredFilteringe[this.GuidID] =
            aQuery[wActiveWorkingPersonKey];
    } else {
        wSystemConfiguredFilteringe[this.GuidID] = JSON.parse("{}");
        wSystemConfiguredFilteringe[this.GuidID] = aQuery;
    }
};
RegisterTableData.prototype.SystemFilter = function () {
    return wSystemConfiguredFilteringe[this.GuidID];
};
RegisterTableData.prototype.AddFilter = function (aQueryElement) {
    //wFilteringDataTable[this.GuidID].push(aQueryElement);
    jsonFilterData = wFilteringDataTable[this.GuidID];
    $.each(aQueryElement, function (Key, Data) {
        if (Data != null && Data != "") {
            jsonFilterData[Key] = Data;
            //$.extend(wFilteringDataTable[this.GuidID], aQueryElement);
        } else {
            delete jsonFilterData[Key];
        }
    });
    FilterWL(this.GuidID, this.ActiveDataGuidName);
};
RegisterTableData.prototype.RemoveFilter = function (aKey) {
    jsonFilterData = wFilteringDataTable[this.GuidID];
    //$.each(jsonFilterData, function (index, result) {
    //    if (result[aQueryElement]) {
    //        //Remove from array
    //        jsonFilterData.splice(index, 1);
    //    }
    //});
    delete jsonFilterData[Key];
    FilterWL(this.GuidID, this.ActiveDataGuidName);
};
RegisterTableData.prototype.SerializeData = function () {
    var wSerializedGridData = JSON.parse("{}");
    //wSerializedGridData.WLData              =   wWorkingDataTable[this.GuidID];
    wSerializedGridData.WLData =
        wMasterDataTable[
            this.ActiveTabLoading ? this.ActiveDataGuidName : this.GuidID
        ];
    wSerializedGridData.WLSort =
        wSortingDataTable[
            this.ActiveTabLoading ? this.ActiveDataGuidName : this.GuidID
        ];
    wSerializedGridData.WLColumnData =
        wGridCellCtrls[
            this.ActiveTabLoading ? this.ActiveDataGuidName : this.GuidID
        ];
    wSerializedGridData.WLDynamicColumnData =
        wDynamicGridCellCtrls[
            this.ActiveTabLoading ? this.ActiveDataGuidName : this.GuidID
        ];
    wSerializedGridData.WLAttributes = wGridAttributes[this.GuidID];
    wSerializedGridData.GridObj = wGridObj[this.GuidID];
    var wGrid = $("#" + this.GuidID + "");
    wSerializedGridData.CurrentPage = wGrid.attr("Current-page") * 1;
    return wSerializedGridData;
};
RegisterTableData.prototype.RebuildGrid = function (SerializedData) {
    wMasterDataTable[
        this.ActiveTabLoading ? this.ActiveDataGuidName : this.GuidID
    ] = SerializedData.WLData;
    wWorkingDataTable[
        this.ActiveTabLoading ? this.ActiveDataGuidName : this.GuidID
    ] = SerializedData.WLData;
    wSortingDataTable[this.GuidID] = SerializedData.WLSort;
    wGridCellCtrls[this.GuidID] = SerializedData.WLColumnData;
    wDynamicGridCellCtrls[this.GuidID] = SerializedData.WLDynamicColumnData;
    wGridAttributes[this.GuidID] = SerializedData.WLAttributes;
    wGridObj[this.GuidID] = SerializedData.GridObj;
    SortWL();
    GenerateWLPerPages(this.GuidID, this.ActiveDataGuidName);
    changePage(
        this.GuidID,
        this.ActiveDataGuidName,
        SerializedData.CurrentPage
    );
};
//RegisterTableData.prototype.Remove = function (aID, aColumnName) {
//    var wColumnName = aColumnName;
//    if (wColumnName == null) {
//        wColumnName = this.PrimaryKey;
//    }
//    if (wColumnName == null) {
//        console.log("No Column Defined");
//        return;
//    }
//    var wGridData = wWorkingDataTable[this.GuidID];
//    var wRecords = this.FindBy(wColumnName, aID);
//    $.each(wRecords, function (key, data) {
//        var wIndex = wGridData.indexOf(data);
//        if (wIndex > -1) {
//            delete wGridData[wIndex];
//        }
//    });
//    this.RebuildResults();
//};
$(document).ready(function () {
    $(function () {
        $(document).keypress(function (e) {
            ShiftClicked = e.shiftKey;
        });
        $(document).keyup(function (e) {
            ShiftClicked = false;
        });
    });
});
function UpdateTabGridTimer(GuidID, aTabName) {
    var wDatObjectName = GuidID;
    if (aTabName !== undefined && aTabName != null && aTabName != "") {
        wDatObjectName = GuidID + "_" + aTabName;
    }
    var wTabCounter = 0;
    if (SearchResults.GridRefreshTimerCounter.hasOwnProperty(wDatObjectName)) {
        wTabCounter = SearchResults.GridRefreshTimerCounter[wDatObjectName];
    }
    wTabCounter++;
    SearchResults.GridRefreshTimerCounter[wDatObjectName] = wTabCounter;
    var wrefreshTabIntervalId = wGridRefreshTimer[wDatObjectName];
    if (wTabCounter >= refreshInterval) {
        UpdateTabWLResults(GuidID, aTabName);
    } else {
        if (refreshInterval > 0) {
            if ($("#UpdateTimer").length != 0) {
                if (refreshIntervalId != null) {
                    clearTimeout(wrefreshTabIntervalId);
                }
                wGridRefreshTimer[wDatObjectName] = setTimeout(
                    "UpdateTabGridTimer('" + GuidID + "', '" + aTabName + "')",
                    refreshCounterInterval
                );
            }
        }
    }
    if (SearchResults.ActiveTabName == aTabName) {
        if (
            wTabCounter > 0 &&
            $(".update-data-button").length > 0 &&
            $(".update-data-button").hasClass("disabled")
        ) {
            $(".update-data-button").removeClass("disabled");
        }
        if (
            wTabCounter > 0 &&
            $(".update-data-button").length > 0 &&
            $(".update-data-button").is(":hidden")
        ) {
            $(".update-data-button").show();
        }
        $("#UpdateTimer")[0].innerHTML = String.format(wWL0MinAgo, wTabCounter);
    }
}
function UpdateTabWLResults(aGuidID, aTabName) {
    var wDatObjectName = aGuidID;
    if (aTabName !== undefined && aTabName != null && aTabName != "") {
        wDatObjectName = aGuidID + "_" + aTabName;
    }
    var wUpdatingTab = $(
        'div.row-tabs-wrapper ul.my-tabs a[tabname="' + aTabName + '"]'
    );
    var DataURL = wUpdatingTab.attr("update-src") + "NULL/DataOnly/";
    var wTabLoadingImg = wUpdatingTab.children("img");
    wTabLoadingImg.show();
    if (SearchResults.ActiveTabName == aTabName) {
        $(".update-data-button image").addClass("imageRotate");
        $(".update-data-button").addClass("disabled");
        $("#UpdateTimer")[0].innerHTML = "";
    }
    $.ajax({
        type: "POST",
        url: DataURL,
        GuidID: aGuidID,
        TabLoadingImg: wTabLoadingImg,
        TabLoading: wUpdatingTab,
        refreshCounterInterval: refreshCounterInterval,
    })
        .done(function (data) {
            var wTabName = this.TabLoading.attr("TabName");
            if (SearchResults.ActiveTabName == wTabName) {
                if ($(".update-data-button image").hasClass("imageRotate")) {
                    $(".update-data-button image").removeClass("imageRotate");
                }
                if (!$(".update-data-button image").hasClass("disabled")) {
                    $(".update-data-button").addClass("disabled");
                }
                $("#UpdateTimer")[0].innerHTML = "";
            }
            var wDatObjectName = this.GuidID;
            if (wTabName !== undefined && wTabName != null && wTabName != "") {
                wDatObjectName = this.GuidID + "_" + wTabName;
            }
            SearchResults.UpdateGridData(wTabName, data.WLData);
            //UpdateTabCounter(this.TabLoading);
            clearTimeout(wGridRefreshTimer[wDatObjectName]);
            SearchResults.GridRefreshTimerCounter[wDatObjectName] = 0;
            wGridRefreshTimer[wDatObjectName] = setTimeout(
                "UpdateTabGridTimer('" + this.GuidID + "', '" + wTabName + "')",
                refreshCounterInterval
            );
            if (SearchResults.ActiveTabName == wTabName) {
                SearchResults.RebuildResults(wTabName);
                ApplyMyView();
            }
            this.TabLoadingImg.hide();
            SearchResults.UpdateGridCountData(wTabName, data.length);
            UpdateTabCounter(this.TabLoading);
        })
        .error(function (data) {
            this.TabLoadingImg.hide();
            if (
                SearchResults.ActiveTabName == wTabName &&
                $(".update-data-button image").hasClass("imageRotate")
            ) {
                $(".update-data-button image").removeClass("imageRotate");
                $("#UpdateTimer")[0].innerHTML = String.format(
                    wWL0MinAgo,
                    wTabCounter
                );
            }
        });
}
function NoResults(GuidID, DataGuidName) {
    DataContainer = GuidID;
    if (DataGuidName !== undefined && DataGuidName != null) {
        DataContainer = DataGuidName;
    }
    var wNoResultsGrid = wNoResults;
    if (
        wGridAttributes[GuidID].NoResultsSentence != null &&
        wGridAttributes[GuidID].NoResultsSentence != null
    ) {
        wNoResultsGrid = wGridAttributes[GuidID].NoResultsSentence;
    }
    if (
        wGridObj[GuidID].SearchCriteria != null &&
        wGridObj[GuidID].SearchCriteria != ""
    ) {
        wNoResultsGrid = String.format(
            wNoResultsCriteria,
            "" + wGridObj[GuidID].SearchCriteria + ""
        ); //wNoResultsCriteria.replace("{criteria}", wGridObj[GuidID].SearchCriteria)
    }
    return wNoResultsGrid;
}
var mWorkingDesiredColumnValue;
function GenerateCellValue(
    GuidID,
    DataRow,
    DesiredColumnValue,
    CellFormat,
    CellCtrlData,
    DynamicData,
    DataContainer
) {
    wDataContainer = GuidID;
    if (DataContainer !== undefined && DataContainer != null) {
        wDataContainer = DataContainer;
    }
    if (CellFormat == null || CellFormat == "") {
        CellFormat = WLLongDateTimeFormat;
    }
    mWorkingDesiredColumnValue = DesiredColumnValue;
    var WLData = wWorkingDataTable[wDataContainer];
    if (!DesiredColumnValue || DesiredColumnValue == "") {
        return "";
    }
    var ctrlCtrl = DesiredColumnValue;
    var match;
    var matches = [];
    while ((match = regex.exec(ctrlCtrl)) !== null) {
        matches.push(match);
        var wColumnName = match[1];
        var wData = DataRow[wColumnName];
        var wColumnData = DataRow[wColumnName]
            ? DataRow[wColumnName]
            : " ";
        if (
            wColumnName.toLowerCase().indexOf("date") > -1 &&
            DataRow[wColumnName] != null &&
            Object.prototype.toString.call(
                new Date(parseInt(DataRow[wColumnName].substr(6))).toString() ==
                    "Invalid Date"
                    ? ""
                    : new Date(parseInt(DataRow[wColumnName].substr(6)))
            ) == "[object Date]" &&
            DataRow[wColumnName] != "01-01-0001"
        ) {
            if (wColumnData.indexOf("/Date(") > -1) {
                wColumnData = wColumnData
                    .replace("/Date(", "")
                    .replace(")/", "");
                if (parseFloat(wColumnData) < -2208900000000) {
                    wColumnData = "";
                } else {
                    var d = new Date(parseFloat(wColumnData));
                    var timeZoneOffset = d.getTimezoneOffset();
                    if (
                        timeZoneOffset >= 0 &&
                        DataContainer != "PACSMediaRequests" &&
                        (moment([
                            d.getFullYear(),
                            d.getDate(),
                            d.getMonth() + 1,
                        ]).isUTC() ||
                            wColumnName == "DateOfBirth" ||
                            wColumnName == "birth_date" ||
                            wColumnName == "created_date" ||
                            wColumnName == "ScheduledDate" ||
                            wColumnName == "scheduled_start_date" ||
                            wColumnName == "DisplayDate")
                    ) {
                        wColumnData = dateFormat(
                            new Date(parseFloat(wColumnData)),
                            CellFormat,
                            true
                        );
                    } else if (
                        timeZoneOffset < 0 &&
                        DataContainer != "PACSMediaRequests" &&
                        (moment([
                            d.getFullYear(),
                            d.getDate(),
                            d.getMonth() + 1,
                        ]).isUTC() ||
                            wColumnName == "created_date" ||
                            wColumnName == "ScheduledDate" ||
                            wColumnName == "scheduled_start_date" ||
                            wColumnName == "DisplayDate")
                    ) {
                        wColumnData = dateFormat(
                            new Date(parseFloat(wColumnData)),
                            CellFormat,
                            true
                        );
                    } else {
                        wColumnData = dateFormat(
                            new Date(parseFloat(wColumnData)),
                            CellFormat,
                            false
                        );
                    }
                }
            } else {
                var idx = wData.indexOf("T");
                var isNonOffsetDate = true;
                if (idx > -1) {
                    if (wData.indexOf("-", idx) > -1) {
                        isNonOffsetDate = false;
                    }
                    if (wData.indexOf("+", idx) > -1) {
                        isNonOffsetDate = false;
                    }
                    if (wData.indexOf(".", idx) > -1) {
                        isNonOffsetDate = false;
                    }
                } else if (
                    wData.toLowerCase().endsWith("am") ||
                    wData.toLowerCase().endsWith("pm") ||
                    wData.toLowerCase().endsWith(wTimeAM) ||
                    wData.toLowerCase().endsWith(wTimePM)
                ) {
                    isNonOffsetDate = false;
                } else if (wColumnName == "DateOfBirth") {
                    isNonOffsetDate = false;
                }
                wColumnData = dateFormat(
                    new Date(wColumnData),
                    CellFormat,
                    isNonOffsetDate
                );
                // wColumnData = dateFormat(new Date(wColumnData), CellFormat, false);
            }
        }
        if (typeof wColumnData === "string") {
            if (
                wColumnData.search("
 -1 &&
                Object.prototype.toString.call(
                    new Date(
                        parseInt(DataRow[wColumnName].substr(6))
                    ).toString() == "Invalid Date"
                        ? ""
                        : new Date(parseInt(DataRow[wColumnName].substr(6)))
                ) == "[object Date]" &&
                DataRow[wColumnName] != "01-01-0001"
            ) {
                if (wColumnData.indexOf("/Date(") > -1) {
                    wColumnData = wColumnData
                        .replace("/Date(", "")
                        .replace(")/", "");
                    var d = new Date(parseFloat(wColumnData));
                    var timeZoneOffset = d.getTimezoneOffset();
                    if (
                        timeZoneOffset >= 0 &&
                        (moment([
                            d.getFullYear(),
                            d.getDate(),
                            d.getMonth() + 1,
                        ]).isDST() ||
                            wColumnName == "birth_date" ||
                            wColumnName == "scheduled_start_date" ||
                            wColumnName == "DisplayDate")
                    ) {
                        wColumnData = dateFormat(
                            new Date(parseFloat(wColumnData)),
                            CellFormat,
                            true
                        );
                    } else if (
                        timeZoneOffset < 0 &&
                        (moment([
                            d.getFullYear(),
                            d.getDate(),
                            d.getMonth() + 1,
                        ]).isDST() ||
                            wColumnName == "scheduled_start_date" ||
                            wColumnName == "DisplayDate")
                    ) {
                        wColumnData = dateFormat(
                            new Date(parseFloat(wColumnData)),
                            CellFormat,
                            true
                        );
                    } else {
                        wColumnData = dateFormat(
                            new Date(parseFloat(wColumnData)),
                            CellFormat,
                            false
                        );
                    }
                } else {
                    var idx = wData.indexOf("T");
                    var isNonOffsetDate = true;
                    if (idx > -1) {
                        if (wData.indexOf("-", idx) > -1) {
                            isNonOffsetDate = false;
                        }
                        if (wData.indexOf("+", idx) > -1) {
                            isNonOffsetDate = false;
                        }
                        if (wData.indexOf(".", idx) > -1) {
                            isNonOffsetDate = false;
                        }
                    }
                    wColumnData = dateFormat(
                        new Date(wColumnData),
                        CellFormat,
                        isNonOffsetDate
                    );
                }
            }
            if (typeof wColumnData === "string") {
                if (
                    wColumnData.search("
 -1) {
                        wStringReplaceValue = wStringReplaceValue.replace(
                            /\"/g,
                            """
                        );
                    }
                    if (wStringReplaceValue.search("'") > -1) {
                        if (aPlaceHolder == "patient_name") {
                            wStringReplaceValue = wStringReplaceValue.replace(
                                /\'/g,
                                "\\'"
                            );
                        } else {
                            wStringReplaceValue = wStringReplaceValue.replace(
                                /\'/g,
                                "'"
                            );
                        }
                    }
                }
            }
    }
    return wStringReplaceValue;
}
function BuildGridLoadingspinner(GuidID, aDataGuidName) {
    wDataContainer = GuidID;
    if (
        ActiveTabLoading &&
        aDataGuidName !== undefined &&
        aDataGuidName != null
    ) {
        wDataContainer = aDataGuidName;
    }
    var WLData = wWorkingDataTable[wDataContainer];
    if (WLData.length <= 0) {
        var wWLRows = "";
        var wGrid = $("#" + GuidID + "");
        var wGridColumns = $("#" + GuidID + " thead tr th");
        var wGridArea = $("#" + GuidID + " tbody");
        wWLRows += '';
        wWLRows += '| ';
        wWLRows +=
            '';
        wWLRows += " | ";
        wWLRows += "
";
        $(wGridArea[0]).empty();
        $(wGridArea[0]).append(wWLRows);
        GenerateSpinner();
    } else {
        BuildGridResults(GuidID, wDataContainer);
    }
}
function BuildGridResults(GuidID, aDataGuidName) {
    wDataContainer = GuidID;
    if (
        ActiveTabLoading &&
        aDataGuidName !== undefined &&
        aDataGuidName != null
    ) {
        wDataContainer = aDataGuidName;
    }
    var WLData = wWorkingDataTable[wDataContainer];
    if (WLData === undefined) {
        if (wDataContainer != GuidID) {
            WLData = wWorkingDataTable[GuidID];
        }
    }
    var wWLRows = "";
    var wGrid = $("#" + GuidID + "");
    var wGridColumns = $("#" + GuidID + " thead tr th");
    var wGridArea = $("#" + GuidID + " tbody");
    var WLPerPage = wGrid.attr("Rows-per-page") * 1;
    if (WLPerPage > WLData.length) {
        WLPerPage = WLData.length;
    }
    if (
        wGridAttributes[GuidID].hasOwnProperty("FullResultSetDisplayed") &&
        wGridAttributes[GuidID]["FullResultSetDisplayed"] == true
    ) {
        WLPerPage = WLData.length;
        wGrid.attr("Rows-per-page", WLPerPage);
    }
    if (WLData.length <= 0) {
        wWLRows += "";
        wWLRows += '| ';
        wWLRows += NoResults(GuidID); // "there are currently no rows to display."; //wNoResultsCriteria//wNoResults
        wWLRows += " | ";
        wWLRows += "
";
    } else {
        var WLPage = wGrid.attr("Current-page") * 1;
        var wRowsPerPage = Math.ceil(WLData.length / WLPerPage);
        if (wRowsPerPage < WLPage) {
            wGrid.attr("Current-page", 1);
            WLPage = wGrid.attr("Current-page") * 1;
        }
        var CurrentGroupByDataValue;
        var GroupBy =
            wGridAttributes[GuidID]["GroupByData"] != null &&
            Object.keys(wGridAttributes[GuidID]["GroupByData"]).length > 0
                ? true
                : false;
        if (
            wGridAttributes[GuidID]["GroupByData"] &&
            wGridAttributes[GuidID]["GroupByData"]["Action"]
        ) {
            var wBaseGroupByAction = null;
            if (
                typeof wGridAttributes[GuidID]["GroupByData"]["Action"] ===
                "string"
            ) {
                wBaseGroupByAction =
                    wGridAttributes[GuidID]["GroupByData"]["Action"];
            } else {
                $.each(
                    wGridAttributes[GuidID]["GroupByData"]["Action"],
                    function (key, data) {
                        if (typeof data === "string") {
                            wBaseGroupByAction += data;
                        } else {
                        }
                    }
                );
            }
        }
        var wGroupItemsCollapsed = "";
        for (
            var i = (WLPage - 1) * WLPerPage;
            i < (WLPage - 1) * WLPerPage + WLPerPage && i < WLData.length;
            i++
        ) {
            if (GroupBy) {
                wGroupItemsCollapsed =
                    wGridAttributes[GuidID]["GroupByData"]["Collapsed"] !=
                        null &&
                    (wGridAttributes[GuidID]["GroupByData"]["Collapsed"]
                        .toString()
                        .toLowerCase() == "true" ||
                        wGridAttributes[GuidID]["GroupByData"]["Collapsed"]
                            .toString()
                            .toLowerCase() == "y")
                        ? "display: none;"
                        : "";
                if (
                    CurrentGroupByDataValue != 0 &&
                    WLData[i][
                        wGridAttributes[GuidID]["GroupByData"]["GroupBy"]
                    ] != CurrentGroupByDataValue
                ) {
                    var wGroupTitleValue = GenerateCellValue(
                        GuidID,
                        WLData[i],
                        wGridAttributes[GuidID]["GroupByData"]["Title"],
                        "",
                        null,
                        null,
                        wDataContainer
                    );
                    var wGroupCellValue = GenerateCellValue(
                        GuidID,
                        WLData[i],
                        wGridAttributes[GuidID]["GroupByData"]["Text"],
                        "",
                        null,
                        null,
                        wDataContainer
                    );
                    CurrentGroupByDataValue =
                        WLData[i][
                            wGridAttributes[GuidID]["GroupByData"]["GroupBy"]
                        ];
                    //style=\"border-top-color: "+StyleColor+ "; border-top-width: 1px; border-top-style: solid;\"
                    wWLRows +=
                        '';
                    //todo: changed title to data-original-title
                    wWLRows +=
                        '| ';
                    wWLRows +=
                        '' +
                        wGroupCellValue +
                        "";
                    if (
                        wBaseGroupByAction &&
                        wBaseGroupByAction != null &&
                        wBaseGroupByAction != ""
                    ) {
                        var wGroupByAction = GenerateCellValue(
                            GuidID,
                            WLData[i],
                            wBaseGroupByAction,
                            "",
                            null,
                            null,
                            wDataContainer,
                            wDataContainer
                        );
                        wWLRows +=
                            '' +
                            wGroupByAction +
                            "";
                    }
                    wWLRows += " | ";
                    wWLRows += "
";
                }
            }
            var wDynamicClass = "";
            if (
                wGridAttributes[GuidID]["RowClass"] != null &&
                Object.keys(wGridAttributes[GuidID]["RowClass"]).length > 0
            ) {
                $.each(
                    wGridAttributes[GuidID]["RowClass"],
                    function (key, data) {
                        var wFieldValue = GenerateCellValue(
                            GuidID,
                            WLData[i],
                            key,
                            null,
                            null,
                            null,
                            wDataContainer
                        );
                        if (wFieldValue in data) {
                            wDynamicClass += data[wFieldValue] + " ";
                        }
                    }
                );
            }
            var wDynamicStyle = "";
            if (
                wGridAttributes[GuidID]["RowStyle"] != null &&
                Object.keys(wGridAttributes[GuidID]["RowStyle"]).length > 0
            ) {
                $.each(
                    wGridAttributes[GuidID]["RowStyle"],
                    function (key, data) {
                        var wFieldValue = GenerateCellValue(
                            GuidID,
                            WLData[i],
                            key,
                            null,
                            null,
                            null,
                            wDataContainer
                        );
                        if (wFieldValue in data) {
                            wDynamicStyle += data[wFieldValue] + " ";
                        }
                    }
                );
            }
            wWLRows +=
                "';
            $.each(wGridColumns, function (key, data) {
                var columnName = $(data).find("a").attr("ColumnName");
                if (columnName == null) {
                    columnName = $(data).find("span").attr("ColumnName");
                }
                if (columnName == null) {
                    columnName = $(data).attr("ColumnName");
                }
                //if (columnName == null) {
                //    columnName = $(data).find('a').attr('columnname');
                //}
                //if (columnName == null) {
                //    columnName = $(data).attr('columnname');
                //}
                if (columnName == null) {
                    columnName = "";
                }
                var columnValue = $(data).find("a").attr("ColumnValue");
                if (columnValue == null) {
                    columnValue = $(data).find("span").attr("ColumnValue");
                }
                if (columnValue == null) {
                    columnValue = "";
                }
                var wDisplayFormat = "";
                if (
                    $(data).attr("DisplayFormat") != null &&
                    $(data).attr("DisplayFormat") != ""
                ) {
                    wDisplayFormat = $(data).attr("DisplayFormat");
                }
                var wTitleCellValue = "";
                if (
                    $(data).attr("TitleValue") != null &&
                    $(data).attr("TitleValue") != ""
                ) {
                    wTitleCellValue = $(data).attr("TitleValue");
                }
                var wTitleFormat = "";
                if ($(data).attr("TitleFormat") != null) {
                    wTitleFormat = $(data).attr("TitleFormat");
                }
                //var wfieldDataValue = GenerateCellValue(GuidID, WLData[i], (columnValue != "" ? columnValue : "{"+columnName+"}"), wDisplayFormat, wTitleValue, wTitleFormat, wDynamicGridCellCtrls[GuidID][columnName]);
                var wClassValue = "";
                wTitleFormat =
                    wTitleFormat == "" &&
                    columnName.indexOf("date") > -1 &&
                    columnName.indexOf("birth") == -1
                        ? WLLongDateTimeFormat
                        : wTitleFormat;
                wDisplayFormat =
                    wDisplayFormat == "" && columnName.indexOf("date") > -1
                        ? columnName.indexOf("birth") > -1
                            ? WLDateFormat
                            : WLLongDateFormat
                        : wDisplayFormat;
                //do we want non birth date date fields to alwasy have an extended date value dispalyed.
                //if ((wTitleValue == null || wTitleValue == "") && columnName.indexOf("date") > -1 && columnName.indexOf("birth") == -1) {
                //    wTitleValue = (columnValue != "" ? columnValue : "{" + columnName + "}");
                //}
                var wTitleValue = GenerateCellValue(
                    GuidID,
                    WLData[i],
                    wTitleCellValue,
                    wTitleFormat,
                    null,
                    null,
                    wDataContainer
                );
                var wCellValue = GenerateCellValue(
                    GuidID,
                    WLData[i],
                    columnValue != "" ? columnValue : "{" + columnName + "}",
                    wDisplayFormat,
                    wGridCellCtrls[GuidID][columnName],
                    wDynamicGridCellCtrls[GuidID][columnName],
                    wDataContainer
                );
                if (
                    $(data).attr("class") != null &&
                    $(data).attr("class") != ""
                ) {
                    wClassValue = $(data).attr("class");
                }
                var wStyleValue = "";
                if (
                    $(data).attr("style") != null &&
                    $(data).attr("style") != ""
                ) {
                    wStyleValue = $(data).attr("style");
                }
                //todo: changed title to data-original-title
                wWLRows +=
                    '| ';
                wWLRows += wCellValue.replace(
                    /]*>( |\s)<\/a>/gi,
                    ""
                );
                wWLRows += " | ";
            });
            wWLRows += "
";
        }
    }
    //wGridArea.val(wWLRows);
    //wGridArea[0].innerHTML = wWLRows;
    //$(wGridArea).val(wWLRows);
    $(wGridArea[0]).empty();
    $(wGridArea[0]).append(wWLRows);
    //GenerateSpinner();
    var wPreviouseAttachmentList;
    $("#" + GuidID + ' tbody [data-toggle="popover-attachments"]').popover({
        html: true,
        trigger: "click",
        content: function () {
            var wAttachmentResultHTML = $(this).attr("Attachment_Result_List");
            if (
                wAttachmentResultHTML === undefined ||
                wAttachmentResultHTML == ""
            ) {
                $.ajax({
                    type: "POST",
                    url: $(this).data("loadurl"),
                    AttachmentRow: $("#Attachment_list"),
                    popoverIcon: $(this),
                    success: function (data) {
                        this.popoverIcon.attr("Attachment_Result_List", data);
                        this.AttachmentRow.html(data);
                        this.popoverIcon
                            .next()
                            .find("#Attachment_list")
                            .html(data);
                        var popover = this.popoverIcon.data("bs.popover");
                        //popover({ placement: 'right' });
                        //popover.$tip.addClass(popover.options.placement);
                        //if (popover !== undefined) {
                        //    popover.setContent();
                        //    //popover.options.content = popover.options.content;
                        //    //var tip = popover.tip();
                        //    //if (tip.is(':visible')) {
                        //    //    tip.find('#Attachment_list').html(data);
                        //    //}
                        //}
                        this.popoverIcon
                            .parent()
                            .find('[id^="popover"].popover:visible')
                            .popover("reposition");
                    },
                });
            } else {
                $(this)
                    .next()
                    .find("#Attachment_list")
                    .html(wAttachmentResultHTML);
            }
            if (wPreviouseAttachmentList !== undefined) {
                $(wPreviouseAttachmentList)
                    .find('[id^="popover"].popover:visible')
                    .popover("hide");
            }
            wPreviouseAttachmentList = $(this).parent();
            return $(this).next().html(); //$(this).parent().find('.popover').html();
        },
    });
    $("#" + GuidID + ' tbody [data-toggle="popover"]').popover({
        html: true,
        trigger: "click",
        content: function () {
            var row = $(this)
                .parent()
                .parent()
                .parent()
                .children()
                .not(".overflow");
            var icons = $(this)
                .parent()
                .parent()
                .find(".popovercontent")
                .html();
            var contents = '';
            for (var i = 0; i < row.length; i++) {
                if (
                    !$(row.get(i)).is(
                        ".no-summary, .more-info-icons, .quick-launch-icons, .column-hidden, :visible"
                    )
                ) {
                    var $td = $(row.get(i));
                    var $th = $td.closest("table").find("th").eq(i);
                    contents +=
                        "
" +
                        $th.text() +
                        "" +
                        $td.html() +
                        "
";
                }
            }
            contents += "
 ";
            return icons + contents;
        },
    });
    $('[data-toggle="WLtooltip"]').tooltip({ container: "body" });
    $("#" + GuidID + ' tbody [data-toggle^="popover-"]').popover({
        html: true,
        trigger: "click",
        content: function () {
            //var contents = '';
            //contents = "-Attachments-"
            //contents += '
';
            return $(this).parent().children()[1].innerHTML;
        },
    });
}
function changePage(GuidID, aPage, aDataGuidName) {
    wDataContainer = GuidID;
    if (
        ActiveTabLoading &&
        aDataGuidName !== undefined &&
        aDataGuidName != null
    ) {
        wDataContainer = aDataGuidName;
    }
    $("#" + GuidID + "").attr("Current-page", aPage);
    var WLData = wWorkingDataTable[wDataContainer];
    var pagingSize = $("#" + "SearchResults").attr("Rows-per-page");
    $(
        ".my-pageable-grid-table .RowsPerPage option[value=" + pagingSize + "]"
    ).prop("selected", "selected");
    $(".my-pageable-grid-table #RowsPerPage option").each(function () {
        if ($(this).val() == pagingSize) {
            $("#" + GuidID + "").attr("Rows-per-page", pagingSize);
            $(
                ".my-pageable-grid-table .RowsPerPage option[value=" +
                    pagingSize +
                    "]"
            ).prop("selected", "selected");
            return false;
        } else {
            $("#" + "SearchResults").attr("Rows-per-page", 10);
        }
    });
    BuildGridResults(GuidID, wDataContainer);
    GenerateWLPages(GuidID, wDataContainer);
    if (typeof WLGenericTabSelectedPage === "function") {
        WLGenericTabSelectedPage(aPage);
    }
}
function ClosePopover() {
    $('[id^="popover"].popover:visible').popover("hide");
}
$(".my-pageable-grid-table .RowsPerPage").change(function () {
    var WLPerPage = parseInt($(this)[0].value);
    if (typeof WLGenericTabSelectedRowsPerPage === "function") {
        WLGenericTabSelectedRowsPerPage(WLPerPage);
    }
    var wGrid = $(this).closest("table");
    var GuidID = wGrid.attr("id");
    var wTabName = wGrid.attr("ActiveTabName");
    var wDataContainer = GuidID;
    if (wTabName !== undefined) {
        wDataContainer = GuidID + "_" + wTabName;
    }
    wGrid.attr("Rows-per-page", WLPerPage);
    BuildGridResults(GuidID, wDataContainer);
    GenerateWLPages(GuidID, wDataContainer);
    GenerateWLPerPages(GuidID, wDataContainer);
    var WLPage = wGrid.attr("Current-page") * 1;
    if (WLPage > 1) {
        changePage(GuidID, 1, wDataContainer);
    }
});
function GenerateWLPages(GuidID, aDataGuidName) {
    wDataContainer = GuidID;
    if (
        ActiveTabLoading &&
        aDataGuidName !== undefined &&
        aDataGuidName != null
    ) {
        wDataContainer = aDataGuidName;
    }
    var WLData = wWorkingDataTable[wDataContainer];
    if (WLData === undefined) {
        if (wDataContainer != GuidID) {
            WLData = wWorkingDataTable[GuidID];
        }
    }
    var WLTotalRows = WLData.length;
    var wGrid = $("#" + GuidID + "");
    var WLPerPage = wGrid.attr("Rows-per-page") * 1;
    var WLPage = wGrid.attr("Current-page") * 1;
    var wGridFooterPages = $("#" + GuidID + " tfoot .PageCount");
    if (WLData.length <= WLPerPage) {
        $("#" + GuidID + " tfoot").hide();
        return;
    } else {
        $("#" + GuidID + " tfoot").show();
    }
    if (
        wGridAttributes[GuidID].hasOwnProperty("FullResultSetDisplayed") &&
        wGridAttributes[GuidID]["FullResultSetDisplayed"] == true
    ) {
        $("#" + GuidID + " tfoot").hide();
    }
    wWLPages = "";
    if (WLPage > 1) {
        //var wWLPages = "« Previous";
        var wWLPages =
            '" +
            wArrowPrev +
            ""; //« Prev
    }
    i = 1;
    var wPageCount = Math.ceil(WLTotalRows / WLPerPage);
    var wSparsePages = false;
    var wSparseSeparator = "...";
    if (wGridAttributes[GuidID].PageSpacingCount != null) {
        if (wPageCount > wGridAttributes[GuidID].PageSpacingCount) {
            wSparsePages = true;
        }
        if (wGridAttributes[GuidID].PageSpacingSeparator != null) {
            wSparseSeparator = wGridAttributes[GuidID].PageSpacingSeparator;
        }
        var StartCount = 1;
        var MidCount = 3;
        var EndCount = 1;
        if (wGridAttributes[GuidID].PageSpacingFormat != null) {
            if (wGridAttributes[GuidID].PageSpacingFormat.length > 0) {
                StartCount =
                    wGridAttributes[GuidID].PageSpacingFormat[0].length;
            }
            if (wGridAttributes[GuidID].PageSpacingFormat.length > 1) {
                MidCount = wGridAttributes[GuidID].PageSpacingFormat[1].length;
            }
            if (wGridAttributes[GuidID].PageSpacingFormat.length > 2) {
                EndCount = wGridAttributes[GuidID].PageSpacingFormat[2].length;
            }
        }
    }
    while (i <= Math.ceil(WLTotalRows / WLPerPage)) {
        Appliedclass = "";
        if (i == WLPage) {
            Appliedclass = ' class="active"';
        }
        if (wSparsePages) {
            if (WLPage == 1) {
                if (StartCount < MidCount) {
                    StartCount = MidCount;
                }
            } else if (WLPage >= wPageCount - MidCount - 1) {
                if (EndCount < MidCount - 1) {
                    EndCount = MidCount - 1;
                }
            }
            if (
                i > StartCount &&
                i < WLPage - Math.floor(MidCount * 0.5) &&
                i < wPageCount + 1 - EndCount
            ) {
                if (wSparseSeparator != null && wSparseSeparator != "") {
                    wWLPages +=
                        '' +
                        wSparseSeparator +
                        "";
                    wWLPages += "";
                }
                i = WLPage - Math.floor(MidCount * 0.5);
                continue;
            } else if (
                i > WLPage + Math.floor(MidCount * 0.5) &&
                i < wPageCount + 1 - EndCount &&
                i > StartCount
            ) {
                if (wSparseSeparator != null && wSparseSeparator != "") {
                    wWLPages +=
                        '' +
                        wSparseSeparator +
                        "";
                    wWLPages += "";
                }
                i = wPageCount + 1 - EndCount;
                continue;
            }
        }
        wWLPages +=
            "" +
            i +
            "";
        i++;
    }
    if (WLPage < i - 1) {
        wWLPages +=
            '" +
            wArrowNext +
            ""; //Next »
    }
    wGridFooterPages[0].innerHTML = wWLPages;
    //$('#' + GuidID +' ul.pagination').menu();
}
function SetTotalRow(GuidID, aDataGuidName) {
    wDataContainer = GuidID;
    if (
        ActiveTabLoading &&
        aDataGuidName !== undefined &&
        aDataGuidName != null
    ) {
        wDataContainer = aDataGuidName;
    }
    var WLMasterData = wMasterDataTable[wDataContainer];
    var WLData = wWorkingDataTable[wDataContainer];
    var WLLengthCount = WLMasterData.length;
    if (typeof ActiveBaseFilterCount === "function") {
        var wActiveSystemCriteria = null;
        if (
            wlSystemCriteria !== undefined &&
            wlSystemCriteria != null &&
            wlSystemCriteria.hasOwnProperty(GuidID) &&
            wlSystemCriteria[GuidID] != null
        ) {
            wActiveSystemCriteria = wlSystemCriteria[GuidID];
        }
        WLLengthCount = ActiveBaseFilterCount(
            wFilteringDataTable[GuidID],
            wMasterDataTable[wDataContainer],
            wActiveSystemCriteria
        );
    }
    if (WLData.length <= 0) {
        $("#" + GuidID + " .TotalRowCount").hide();
    } else {
        $("#" + GuidID + " .TotalRowCount").show();
        if (WLData.length < WLLengthCount) {
            $("#" + GuidID + " .TotalRowCount")[0].innerHTML = String.format(
                wResultsoftotalrows,
                WLData.length,
                WLLengthCount
            ); //" of " + WLData.length + " of total:" +WLLengthCount;
        } else {
            $("#" + GuidID + " .TotalRowCount")[0].innerHTML = String.format(
                wResultsofrows,
                WLData.length
            ); //" of " + WLData.length + " Rows";
        }
    }
}
function GenerateWLPerPages(GuidID, aDataGuidName) {
    wDataContainer = GuidID;
    if (
        ActiveTabLoading &&
        aDataGuidName !== undefined &&
        aDataGuidName != null
    ) {
        wDataContainer = aDataGuidName;
    }
    var WLData = wWorkingDataTable[wDataContainer];
    if (WLData === undefined) {
        if (wDataContainer != GuidID) {
            WLData = wWorkingDataTable[GuidID];
        }
    }
    var WLTotalRows = WLData.length;
    var wGrid = $("#" + GuidID + "");
    if (
        wGridAttributes[GuidID].hasOwnProperty("FullResultSetDisplayed") &&
        wGridAttributes[GuidID]["FullResultSetDisplayed"] == true
    ) {
        wGrid.attr("Rows-per-page", WLTotalRows);
    }
    var WLPerPage = wGrid.attr("Rows-per-page");
    var WLPage = wGrid.attr("Current-page");
    var WLDefaultPerPage = true;
    var select = $("#" + GuidID + " tfoot .RowsPerPage")[0];
    if (WLData.length <= WLPerPage) {
        $("#" + GuidID + " tfoot").hide();
        return;
    }
    if (WLData.length <= 0) {
        $(select).hide();
    } else {
        $(select).show();
    }
    select.innerHTML = "";
    lastCount = 0;
    i = 5;
    while (i < WLTotalRows) {
        lastCount = i;
        var opt = document.createElement("option");
        opt.value = i;
        opt.innerHTML = i;
        if (WLPerPage == i) {
            opt.selected = true;
            WLDefaultPerPage = false;
        }
        select.appendChild(opt);
        switch (i) {
            case 5:
                i += 5;
                break;
            case 10:
                i += 15;
                break;
            case 25:
                i += 25;
                break;
            default:
                i += 50;
                break;
        }
    }
    if (lastCount < WLTotalRows) {
        var opt = document.createElement("option");
        opt.value = WLTotalRows;
        if (WLPerPage == WLTotalRows) {
            opt.selected = true;
            WLDefaultPerPage = false;
        }
        opt.innerHTML = WLTotalRows;
        select.appendChild(opt);
    }
    if (
        WLDefaultPerPage &&
        wlSystemCriteria !== undefined &&
        wlSystemCriteria != null &&
        wlSystemCriteria.hasOwnProperty("Rows-per-page")
    ) {
        var DefaultValue = wlSystemCriteria["Rows-per-page"] * 1;
        if (DefaultValue > 1 && DefaultValue == WLPerPage) {
            var opt = document.createElement("option");
            opt.value = DefaultValue;
            opt.selected = true;
            opt.innerHTML = DefaultValue;
            select.appendChild(opt);
        }
    }
    SetTotalRow(GuidID, aDataGuidName);
}
$(".my-data-table").on("click", "tr.sub-heading", function (e) {
    if (e.target.tagName == "A" || e.target.tagName == "BUTTON") {
        return;
    }
    GroupID = $(this).attr("grouped-id");
    if (GroupID && GroupID != "") {
        $("tr[groupbyidvalue='" + GroupID + "']").toggle();
    }
});
//$(".my-data-table ").on("click", "tr.sub-heading", ToggleCollapseGroupedRows);
//var ToggleCollapseGroupedRows = function () {
//    GroupID = $(this).attr('grouped-id');
//    if (GroupID && GroupID != "") {
//        $("tr[groupbyidvalue='" + GroupID + "']").toggle();
//    }
//}
$(".my-pageable-grid-table th a").click(function () {
    var wGrid = $(this).closest("table");
    var GuidID = wGrid.attr("id");
    var wTabName = wGrid.attr("ActiveTabName");
    var wDataContainer = GuidID;
    if (ActiveTabLoading && wTabName !== undefined) {
        wDataContainer = GuidID + "_" + wTabName;
    }
    wSortingDataTable[wDataContainer] = JSON.parse("{}");
    if (wSortingDataTable[wDataContainer] == null) {
        wSortingDataTable[wDataContainer] = JSON.parse("{}");
    }
    var ColumnSortOrder = "ASC";
    SortOrder = "ASC";
    SortType = "Alph";
    selectedColumn = $(this).attr("ColumnName");
    if ($(this).attr("sortByColumn") !== undefined) {
        selectedColumn = $(this).attr("sortByColumn");
    }
    //$("#" + GuidID + ".my-custom-grid-table th a").each(function () {
    $("#" + GuidID + ".my-pageable-grid-table.my-data-table th a").each(
        function () {
            if (selectedColumn == $(this).attr("ColumnName")) {
                if (selectedColumn.toLowerCase().indexOf("date") > -1) {
                    SortType = "Numeric";
                    if (
                        $(this).find("span.glyphicon-sort-by-order").length != 0
                    ) {
                        ColumnSortOrder = "DESC";
                        SortOrder = "DESC";
                    }
                } else {
                    if (
                        $(this).find("span.glyphicon-sort-by-alphabet")
                            .length != 0
                    ) {
                        ColumnSortOrder = "DESC";
                        SortOrder = "DESC";
                    }
                }
            }
        }
    );
    wSortingDataTable[wDataContainer][selectedColumn] = JSON.parse(
        '"' + ColumnSortOrder + '"'
    );
    $.each($("#" + GuidID + " .glyphicon"), function (key, data) {
        var wSortingColumnHeader = $(data).parent().parent();
        if ($(data).parent().attr("OriginalStyleWidth")) {
            var wOriginalWidth =
                wSortingColumnHeader.attr("OriginalStyleWidth");
            if (
                wOriginalWidth !== undefined &&
                wOriginalWidth != null &&
                wOriginalWidth != ""
            ) {
                wSortingColumnHeader.width(
                    wSortingColumnHeader.attr("OriginalStyleWidth")
                );
            }
        }
        wSortingColumnHeader.removeAttr("OriginalStyleWidth");
    });
    if (!ShiftClicked) {
        $(".my-pageable-grid-table th a .glyphicon").remove();
    } else {
        $("[ColumnName=" + selectedColumn + "] .glyphicon").remove();
    }
    var wWorkingColumn = $(this);
    var wCurrentWidth = wWorkingColumn.parent().width();
    var wAppliedStyleWidth = true;
    if (wCurrentWidth == "") {
        wCurrentWidth = wWorkingColumn.parent()[0].offsetWidth;
        wAppliedStyleWidth = false;
    }
    var wCurrentParentOffsetHeight = wWorkingColumn.parent()[0].offsetHeight;
    $(this)[0].innerHTML +=
        '';
    if (wCurrentParentOffsetHeight < wWorkingColumn.parent()[0].offsetHeight) {
        wCurrentParentOffsetHeight = wWorkingColumn.parent()[0].offsetHeight;
        if (wAppliedStyleWidth) {
            wWorkingColumn[0].setAttribute("OriginalStyleWidth", wCurrentWidth);
        }
        wWorkingColumn.parent().width(wCurrentWidth + 40);
        if (
            wCurrentParentOffsetHeight > wWorkingColumn.parent()[0].offsetHeight
        ) {
            wCurrentParentOffsetHeight =
                wWorkingColumn.parent()[0].offsetHeight;
            wWorkingColumn.parent().width(wCurrentWidth + 20);
            if (
                wCurrentParentOffsetHeight <
                wWorkingColumn.parent()[0].offsetHeight
            ) {
                wWorkingColumn.parent().width(wCurrentWidth + 40);
            }
        }
    }
    SortWL(GuidID, wDataContainer);
});
function SortWL(GuidID, aDataGuidName) {
    wDataContainer = GuidID;
    if (
        ActiveTabLoading &&
        aDataGuidName !== undefined &&
        aDataGuidName != null
    ) {
        wDataContainer = aDataGuidName;
    }
    var counter = 1;
    var sortScript = "";
    if (wGridAttributes[GuidID]["GroupByData"]) {
        counter = 2;
        var GroupBySortData =
            "$." + wGridAttributes[GuidID]["GroupByData"]["GroupBy"];
        sortScript = Enumerable.From(
            wWorkingDataTable[wDataContainer]
        ).OrderByDescending(GroupBySortData);
        //wWorkingDataTable[GuidID] = Enumerable.From(wWorkingDataTable[GuidID]).GroupBy(GroupBySortData).ToArray()
    }
    if (wSortingDataTable[wDataContainer] != null) {
        $.each(wSortingDataTable[wDataContainer], function (key, data) {
            if (key.toLowerCase().indexOf("date") > -1) {
                var wDisplayFormat =
                    key.toLowerCase().indexOf("birth") > -1
                        ? WLDateFormat
                        : WLLongDateFormat;
                sortby = function (x) {
                    return new Date(parseInt(x[key].substr(6)));
                };
            } else {
                sortby = "$." + key;
            }
            if (typeof data === "object") {
                const firstKey = Object.keys(data)[0];
                const firstValue = data[firstKey];
                if (firstValue.toUpperCase() == "DESC") {
                    if (counter == 1) {
                        sortScript = Enumerable.From(
                            wWorkingDataTable[wDataContainer]
                        ).OrderByDescending(sortby);
                    } else {
                        sortScript = sortScript.ThenByDescending(sortby);
                    }
                } else {
                    if (counter == 1) {
                        sortScript = Enumerable.From(
                            wWorkingDataTable[wDataContainer]
                        ).OrderBy(sortby);
                    } else {
                        sortScript = sortScript.ThenBy(sortby);
                    }
                }
            } else {
                if (data.toUpperCase() == "DESC") {
                    if (counter == 1) {
                        sortScript = Enumerable.From(
                            wWorkingDataTable[wDataContainer]
                        ).OrderByDescending(sortby);
                    } else {
                        sortScript = sortScript.ThenByDescending(sortby);
                    }
                } else {
                    if (counter == 1) {
                        sortScript = Enumerable.From(
                            wWorkingDataTable[wDataContainer]
                        ).OrderBy(sortby);
                    } else {
                        sortScript = sortScript.ThenBy(sortby);
                    }
                }
            }
        });
        if (this.PrimaryKey != null && this.PrimaryKey != "") {
            if ((sortScript = "")) {
                sortScript = Enumerable.From(
                    wWorkingDataTable[wDataContainer]
                ).OrderByDescending("$." + this.PrimaryKey);
            } else {
                sortScript = sortScript.ThenByDescending(
                    "$." + this.PrimaryKey
                );
            }
        }
    }
    if (sortScript != "") {
        //wWorkingDataTable[GuidID]= Enumerable.From(sortScript).ToArray();
        wWorkingDataTable[wDataContainer] = sortScript.ToArray();
    }
    BuildGridResults(GuidID, wDataContainer);
}
function FilterWL(GuidID, aDataGuidName) {
    wDataContainerName = GuidID;
    if (
        ActiveTabLoading &&
        aDataGuidName !== undefined &&
        aDataGuidName != null
    ) {
        wDataContainerName = aDataGuidName;
    }
    SearchCriteria = wFilteringDataTable[GuidID];
    var wFilteredData = FilterWLData(
        GuidID,
        SearchCriteria,
        wDataContainerName
    );
    var wGrid = $("#" + GuidID + "");
    var WLPerPage = wGrid.attr("Rows-per-page");
    if (WLPerPage % 5 == 0 || WLPerPage == wFilteredData.Data.length) {
        wGrid.attr("Rows-per-page", WLPerPage);
    }
    wFilteringSentence[GuidID] = wFilteredData.Sentence;
    wWorkingDataTable[wDataContainerName] = wFilteredData.Data;
    SortWL(GuidID, wDataContainerName);
    GenerateWLPerPages(GuidID, wDataContainerName);
    GenerateWLPages(GuidID, wDataContainerName);
}
function FilterWLData(GuidID, SearchCriteria, FullGuidDataName) {
    var wFilterData = JSON.parse("{}");
    wFilterData.Data = [];
    if (SearchCriteria != null) {
        if (wMasterDataTable != null) {
            var wDataSet = null;
            if (wMasterDataTable.hasOwnProperty(FullGuidDataName)) {
                wDataSet = wMasterDataTable[FullGuidDataName];
            } else if (wMasterDataTable.hasOwnProperty(GuidID)) {
                wDataSet = wMasterDataTable[GuidID];
            }
            var wResult = FilterData(SearchCriteria, wDataSet);
            wFilterData.Data = wResult.Data;
            //wFilteringSentence[FullGuidDataName]= "Patients {0}with {1}{2}exams {3} for {4}.".format((SearchCriteria['patient_name']== null ? "" : "matching \"" +SearchCriteria['patient_name']+ "\" "), (SearchCriteria['status_code'] == null ? "": "" + SearchCriteria['status_code']+ " "), wModalityCriteria, wDayRangeCriteria, (SearchCriteria['requested_by_person_key']== null || SearchCriteria['requested_by_person_key'].length == OrderingProviderList.length ? "all providers" : "" +SearchCriteria['requested_by_person_key'].length + " provider" +(SearchCriteria['requested_by_person_key'].length > 1 ? "s": "")));
            wFilterData.Sentence = wResult.FilterSentence;
        }
    }
    return wFilterData;
}
function FilterData(SearchCriteria, WLData) {
    var wFilterToolBarText = wTodayBRYesterday; //"Today &
Yesterday";
    var wFilterText = wTodayandYesterday; //"today and yesterday";
    var wFilterRange = "-1/0";
    var WFilteredStatus;
    var wStatusFilterCriteriaName;
    var wStatusCriteriaName;
    if (
        SearchCriteria.hasOwnProperty("portal_status_code") &&
        SearchCriteria.portal_status_code != null &&
        SearchCriteria.portal_status_code != ""
    ) {
        WFilteredStatus = SearchCriteria.portal_status_code;
    }
    if (
        SearchCriteria.hasOwnProperty("status_code") &&
        SearchCriteria.status_code != null &&
        SearchCriteria.status_code != ""
    ) {
        if (Array.isArray(SearchCriteria.status_code)) {
            if (Array.isArray(WFilteredStatus)) {
                WFilteredStatus = WFilteredStatus.concat(
                    SearchCriteria.status_code
                );
            } else if (WFilteredStatus != "" && WFilteredStatus !== undefined) {
                var wCurrentFilteredStatus = WFilteredStatus;
                WFilteredStatus = SearchCriteria.status_code;
                WFilteredStatus.push(wCurrentFilteredStatus);
            } else {
                WFilteredStatus = SearchCriteria.status_code;
            }
        } else {
            if (Array.isArray(WFilteredStatus)) {
                WFilteredStatus.push(SearchCriteria.status_code);
            } else {
                WFilteredStatus = [WFilteredStatus, SearchCriteria.status_code];
            }
            WFilteredStatus = SearchCriteria.status_code;
        }
        $.each(WFilteredStatus, function (index, data) {
            if (Array.isArray(wStatusFilterCriteriaName)) {
                wStatusFilterCriteriaName.push(TranslateStatusCode(data));
            } else {
                wStatusFilterCriteriaName = [
                    wStatusFilterCriteriaName,
                    TranslateStatusCode(data),
                ];
            }
        });
        wStatusCriteriaName = wStatusFilterCriteriaName.filter(function (x) {
            if (x !== undefined) {
                return x;
            }
        });
    }
    if (WFilteredStatus != null && WFilteredStatus != "") {
        if (Array.isArray(WFilteredStatus)) {
            if (
                $.isInArray("Completed", WFilteredStatus) ||
                $.isInArray("Approved", WFilteredStatus) ||
                $.isInArray("Signed1", WFilteredStatus) ||
                $.isInArray("ExamDoneTechOnly", WFilteredStatus) ||
                $.isInArray("ExtReportVerified", WFilteredStatus) ||
                $.isInArray("Dictated", WFilteredStatus) ||
                $.isInArray("TentativelySigned1", WFilteredStatus) ||
                $.isInArray("Transcribed", WFilteredStatus) ||
                $.isInArray("ExamDone", WFilteredStatus) ||
                $.isInArray("RepeatDone", WFilteredStatus) ||
                $.isInArray("ReportDrafted", WFilteredStatus) ||
                $.isInArray("OrderSigned", WFilteredStatus) ||
                $.isInArray("OrderPendingApproval", WFilteredStatus) ||
                $.isInArray("Pending Approval", WFilteredStatus) ||
                $.isInArray("To be Scheduled", WFilteredStatus)
            ) {
                if ($.isInArray("Scheduled", WFilteredStatus)) {
                    wFilterToolBarText = wTodayplusminusDay; //"Today 
+/- 1 day";//"Today 
+/- 1 day";
                    wFilterText = wTodayYesterdayTomorrow; //"today, yesterday, and tomorrow ";
                    var wFilterRange = "-1/1";
                } else {
                    wFilterToolBarText = wTodayBRYesterday; //"Today &
Yesterday";
                    wFilterText = wTodayandYesterday; //"today and yesterday";
                    var wFilterRange = "-1/0";
                }
            } else if ($.isInArray("Scheduled", WFilteredStatus)) {
                wFilterToolBarText = wTodayBRTomorrow; //"Today &
Tomorrow";
                wFilterText = wTodayandTomorrow; //"today and tomorrow";
                var wFilterRange = "1/1";
            }
        } else {
            if (
                WFilteredStatus == "Completed" ||
                WFilteredStatus == "Approved" ||
                WFilteredStatus == "Signed1" ||
                WFilteredStatus == "ExamDoneTechOnly" ||
                WFilteredStatus == "ExtReportVerified" ||
                WFilteredStatus == "Dictated" ||
                WFilteredStatus == "TentativelySigned1" ||
                WFilteredStatus == "Transcribed" ||
                WFilteredStatus == "ExamDone" ||
                WFilteredStatus == "RepeatDone" ||
                WFilteredStatus == "ReportDrafted" ||
                WFilteredStatus == "OrderSigned" ||
                WFilteredStatus == "OrderPendingApproval" ||
                WFilteredStatus == "Pending Approval" ||
                WFilteredStatus == "To be Scheduled"
            ) {
                wFilterToolBarText = wTodayBRYesterday; //"Today &
Yesterday";
                wFilterText = wTodayandYesterday; //"today and yesterday";
            } else if (WFilteredStatus == "Scheduled") {
                wFilterToolBarText = wTodayBRTomorrow; //"Today &
Tomorrow";
                wFilterText = wTodayandTomorrow; //"today and tomorrow";
            }
        }
    }
    var query = "";
    var wExtraSerachCriteria = "";
    var wDayRangeCriteria = "";
    var wModalityCriteria = "";
    let wAccountProxyElem = $("#cbxAccountProxy").length;
    let wviewingForPersonkey = false;
    var wActiveWorkingPersonKey = -1;
    if (wAccountProxyElem > 0) {
        wActiveWorkingPersonKey = $("#cbxAccountProxy option:selected").val();
        if (
            wActiveWorkingPersonKey !== undefined &&
            wActiveWorkingPersonKey > -1 &&
            SearchCriteria != null &&
            wActiveWorkingPersonKey in SearchCriteria
        ) {
            wviewingForPersonkey = true;
        }
    }
    if (wviewingForPersonkey) {
        if (SearchCriteria[wActiveWorkingPersonKey]["modality_type"] != null) {
            if (
                Array.isArray(
                    SearchCriteria[wActiveWorkingPersonKey]["modality_type"]
                )
            ) {
                wModalityCriteria =
                    Enumerable.From(
                        SearchCriteria[wActiveWorkingPersonKey]["modality_type"]
                    )
                        .Join(
                            ProcedureGroupList,
                            "selection=>selection",
                            "ProcedureGroup=>ProcedureGroup.Value",
                            "(selection,ProcedureGroup)=>{Value:ProcedureGroup.Value, Text:ProcedureGroup.Text}"
                        )
                        .Select("$.Text")
                        .ToArray()
                        .join(",") + " ";
            } else {
                wModalityCriteria =
                    SearchCriteria[wActiveWorkingPersonKey][
                        "modality_type"
                    ].join(",") + " ";
            }
        }
    } else {
        if (SearchCriteria["modality_type"] != null) {
            if (Array.isArray(SearchCriteria["modality_type"])) {
                wModalityCriteria =
                    Enumerable.From(SearchCriteria["modality_type"])
                        .Join(
                            ProcedureGroupList,
                            "selection=>selection",
                            "ProcedureGroup=>ProcedureGroup.Value",
                            "(selection,ProcedureGroup)=>{Value:ProcedureGroup.Value, Text:ProcedureGroup.Text}"
                        )
                        .Select("$.Text")
                        .ToArray()
                        .join(",") + " ";
            } else {
                wModalityCriteria =
                    SearchCriteria["modality_type"].join(",") + " ";
            }
        }
    }
    //(SearchCriteria['modality_type']== null ? "": "" +SearchCriteria['modality_type'].join(",") + " ");
    if (wModalityCriteria != "") {
        pos = wModalityCriteria.lastIndexOf(",");
        if (pos > 0) {
            wModalityCriteria = String.format(
                wExamtypelist,
                wModalityCriteria.substring(0, pos),
                wModalityCriteria.substring(pos + 1)
            ); //wModalityCriteria.substring(0, pos) + " and " + wModalityCriteria.substring(pos + 1) + " ";
        }
    }
    var wIncludeIfCCed = false;
    if (SearchCriteria.IncludeIfCCed != null) {
        wIncludeIfCCed = SearchCriteria.IncludeIfCCed.toLowerCase() == "true";
    }
    $.each(SearchCriteria, function (key, data) {
        //debugger;
        if (
            key == "IncludeIfCCed" ||
            key == "FilterCriteriaSentence" ||
            key == "patient_name"
        ) {
            return true;
        }
        //if ((key == "requested_by_person_key" || key == "modality_type") && data == "SELECTED ALL") {
        //    return true;
        //}
        if (data == undefined || data == "") {
            return;
        }
        var wSpecificSearchCriteria = false;
        if (
            key == "patient_name" ||
            key == "status_code" ||
            key == "requested_by_person_key" ||
            key == "modality_type"
        ) {
            wSpecificSearchCriteria = true;
        }
        filter = "";
        if (
            SearchCriteria[key] != null &&
            SearchCriteria[key] != "" &&
            SearchCriteria[key] != "[]" &&
            SearchCriteria[key].toString() != "SELECTED ALL"
        ) {
            if (query != "") {
                filter = " && ";
            }
            if (
                key[0] != key[0].toUpperCase() ||
                key == "UMStatusCode" ||
                key == "UMResolutionCode"
            ) {
                if (Array.isArray(SearchCriteria[key])) {
                    if (
                        WLData != undefined &&
                        WLData.length > 0 &&
                        Array.isArray(WLData[0][key])
                    ) {
                        filter += " (";
                        $.each(data, function (index, data) {
                            if (index > 0) {
                                filter += " || ";
                            }
                            if (
                                filter != "" &&
                                filter != " &&  (" &&
                                !filter.endsWith("|| ")
                            ) {
                                filter += " || ";
                            }
                            if (data.toLowerCase() == "null") {
                                filter +=
                                    "Enumerable.From($." +
                                    key +
                                    ").Any('$==null')";
                            } else {
                                filter +=
                                    "Enumerable.From($." +
                                    key +
                                    ").Any('$==\"" +
                                    data +
                                    "\"')";
                            }
                        });
                        filter += ") ";
                    } else {
                        filter += " (";
                        $.each(data, function (index, data) {
                            if (index > 0) {
                                filter += " || ";
                            }
                            if (data.toLowerCase() == "null") {
                                filter += "$." + key + "==null";
                            } else {
                                filter += "$." + key + "=='" + data + "'";
                            }
                            //filter += "$." + key + "=='" + data + "'";
                        });
                        if (
                            key == "requested_by_person_key" &&
                            wIncludeIfCCed
                        ) {
                            $.each(data, function (index, data) {
                                if (index > 0) {
                                    filter += " || ";
                                }
                                if (
                                    filter != "" &&
                                    filter != " &&  (" &&
                                    !filter.endsWith("|| ")
                                ) {
                                    filter += " || ";
                                }
                                filter +=
                                    "Enumerable.From($.cc_doctor_key).Any('$==\"" +
                                    data +
                                    "\"')";
                            });
                        }
                        filter += ") ";
                        if (!wSpecificSearchCriteria) {
                            wExtraSerachCriteria +=
                                wWLFilterCriteriaAnd +
                                " " +
                                data.length +
                                "" +
                                key +
                                (data.length > 1 ? "s" : ""); //Add applied Filter
                        }
                    }
                } else if (typeof SearchCriteria[key] === "object") {
                    SubQuery = "";
                    SubFilter = "";
                    $.each(SearchCriteria[key], function (CriteriaKey, data) {
                        if (SubQuery != "") {
                            SubFilter = " && ";
                        }
                        var Days = false;
                        if (data % 1 === 0) {
                            if (data == 0) {
                                data = 1;
                            }
                            Days = true;
                            data = dateFormat(
                                new Date(
                                    new Date().setDate(
                                        new Date().getDate() + Number(data)
                                    )
                                ),
                                "mm/dd/yyyy"
                            );
                            //todo:date format
                        }
                        //new Date(parseInt(x[mDayRangeColumn].substr(6)))
                        switch (CriteriaKey.toLowerCase()) {
                            case "contains":
                                SubFilter += "$." + key + "=='%" + data + "%'";
                                if (!wSpecificSearchCriteria) {
                                    wExtraSerachCriteria += String.format(
                                        wWLFilterCriteriaColumnContains,
                                        key,
                                        data
                                    ); //"and " + key + " contains" + data;//Add applied Filter
                                }
                                break;
                            case "start":
                                SubFilter +=
                                    "new Date(parseInt($." +
                                    key +
                                    ".substr(6))) >= new Date('" +
                                    data +
                                    "')";
                                wDayRangeCriteria +=
                                    " " +
                                    (Days
                                        ? String.format(
                                              wWLFilterCriteriaWithinThe01Days,
                                              (data.toString()[0] == "-"
                                                  ? wWLDayFilterPreviousCriteria
                                                  : wWLDayFilterLastCriteria,
                                              data.toString()[0] == "-" ||
                                              data.toString()[0] == "+"
                                                  ? data.toString().substr(1)
                                                  : data)
                                          )
                                        : String.format(
                                              wWLFilterCriteriaGreaterThen0,
                                              dateFormat(
                                                  new Date(data),
                                                  jsDateFormat
                                              )
                                          )); //Add applied Filter
                                //SubFilter += "$." + key + " >= '" + data + "'";
                                break;
                            case "end":
                                SubFilter +=
                                    "new Date(parseInt($." +
                                    key +
                                    ".substr(6))) <= new Date('" +
                                    data +
                                    "')";
                                wDayRangeCriteria +=
                                    " " +
                                    (Days
                                        ? String.format(
                                              wWLFilterCriteriaWithinThe01Days,
                                              data.toString()[0] == "-"
                                                  ? wWLDayFilterPreviousCriteria
                                                  : wWLDayFilterLastCriteria,
                                              data.toString()[0] == "-" ||
                                                  data.toString()[0] == "+"
                                                  ? data.toString().substr(1)
                                                  : data
                                          )
                                        : String.format(
                                              wWLFilterCriteriaLessThen0,
                                              dateFormat(
                                                  new Date(data),
                                                  jsDateFormat
                                              )
                                          )); //Add applied Filter
                                //SubFilter += "$." + key + " <= '" + data + "'";
                                break;
                        }
                        SubQuery += SubFilter;
                    });
                    filter += SubQuery;
                } else if (WLData.length > 0 && Array.isArray(WLData[0][key])) {
                    filter +=
                        "Enumerable.From($." +
                        key +
                        ").Any('$==\"" +
                        data +
                        "\"')";
                } else {
                    if (data.toLowerCase() == "null") {
                        filter += "$." + key + "==null";
                    } else {
                        filter += "$." + key + "=='" + data + "'";
                    }
                    //filter += "$." + key + "=='" + data + "'";
                    if (!wSpecificSearchCriteria) {
                        wExtraSerachCriteria += String.format(
                            wWLFilterCriteriaColumnMatching,
                            key,
                            data
                        ); //"and " + key + " matching" + data;//Add applied Filter
                    }
                }
            } else {
                SubFilter = "";
                if (typeof mDayRangeColumn === "undefined") {
                    mDayRangeColumn = "requested_date";
                }
                switch (key) {
                    case "DayRange":
                        var wStatusSpecficRangeColumn = mDayRangeColumn;
                        if (SearchCriteria.portal_status_code != null) {
                            if (
                                $.inArray(
                                    "Completed",
                                    SearchCriteria.portal_status_code
                                ) > -1 ||
                                $.inArray(
                                    "Approved",
                                    SearchCriteria.portal_status_code
                                ) > -1
                            ) {
                                wStatusSpecficRangeColumn = "performed_date";
                            }
                        } else if (SearchCriteria.status_code != null) {
                            if (
                                $.inArray(
                                    "Dictated",
                                    SearchCriteria.status_code
                                ) > -1 ||
                                $.inArray(
                                    "ExamDone",
                                    SearchCriteria.status_code
                                ) > -1 ||
                                $.inArray(
                                    "ExamDoneTechOnly",
                                    SearchCriteria.status_code
                                ) > -1 ||
                                $.inArray(
                                    "ExtReportVerified",
                                    SearchCriteria.status_code
                                ) > -1 ||
                                $.inArray(
                                    "RepeatDone",
                                    SearchCriteria.status_code
                                ) > -1 ||
                                $.inArray(
                                    "ReportDrafted",
                                    SearchCriteria.status_code
                                ) > -1 ||
                                $.inArray(
                                    "Signed1",
                                    SearchCriteria.status_code
                                ) > -1 ||
                                $.inArray(
                                    "TentativelySigned1",
                                    SearchCriteria.status_code
                                ) > -1 ||
                                $.inArray(
                                    "Transcribed",
                                    SearchCriteria.status_code
                                ) > -1
                            ) {
                                wStatusSpecficRangeColumn = "performed_date";
                            }
                        }
                        var wRange = data;
                        if ($.isArray(data) && data.length > 0) {
                            wRange = data[0];
                        }
                        //if (data % 1 === 0) {
                        //    data = dateFormat(new Date(new Date().setDate(new Date().getDate() + Number(data * -1))), "mm/dd/yyyy");
                        //}
                        switch (wRange) {
                            case "0":
                            case 0:
                            case "-1":
                            case -1:
                                wDayRangeCriteria = wFilterText; //"today and tomorrow";
                                var StartDate = dateFormat(
                                    new Date(
                                        new Date().setDate(
                                            new Date().getDate() - 1
                                        )
                                    ),
                                    "mm/dd/yyyy"
                                );
                                var EndDate = dateFormat(
                                    new Date(
                                        new Date().setDate(
                                            new Date().getDate() + 2
                                        )
                                    ),
                                    "mm/dd/yyyy"
                                );
                                if (wFilterRange == "-1/0") {
                                    StartDate = dateFormat(
                                        new Date(
                                            new Date().setDate(
                                                new Date().getDate() - 1
                                            )
                                        ),
                                        "mm/dd/yyyy"
                                    );
                                    EndDate = dateFormat(
                                        new Date(
                                            new Date().setDate(
                                                new Date().getDate() + 1
                                            )
                                        ),
                                        "mm/dd/yyyy"
                                    );
                                } else if (wFilterRange == "-1/1") {
                                    StartDate = dateFormat(
                                        new Date(
                                            new Date().setDate(
                                                new Date().getDate() - 1
                                            )
                                        ),
                                        "mm/dd/yyyy"
                                    );
                                    EndDate = dateFormat(
                                        new Date(
                                            new Date().setDate(
                                                new Date().getDate() + 2
                                            )
                                        ),
                                        "mm/dd/yyyy"
                                    );
                                }
                                SubFilter +=
                                    "new Date(parseInt($." +
                                    wStatusSpecficRangeColumn +
                                    ".substr(6))) >= new Date('" +
                                    StartDate +
                                    "')";
                                SubFilter += " && ";
                                SubFilter +=
                                    "new Date(parseInt($." +
                                    wStatusSpecficRangeColumn +
                                    ".substr(6))) <= new Date('" +
                                    EndDate +
                                    "')";
                                break;
                            default:
                                if (SearchCriteria.portal_status_code != null) {
                                    var StatusDateFilter = "";
                                    if (
                                        $.inArray(
                                            "Scheduled",
                                            SearchCriteria.portal_status_code
                                        ) > -1
                                    ) {
                                        var StartDate = dateFormat(
                                            new Date(
                                                new Date().setDate(
                                                    new Date().getDate() +
                                                        Number(data * -1)
                                                )
                                            ),
                                            "mm/dd/yyyy"
                                        );
                                        if (StatusDateFilter != "") {
                                            StatusDateFilter += " && ";
                                        }
                                        StatusDateFilter +=
                                            "new Date(parseInt($." +
                                            wStatusSpecficRangeColumn +
                                            ".substr(6))) >= new Date('" +
                                            StartDate +
                                            "')";
                                        if (wDayRangeCriteria != "") {
                                            wDayRangeCriteria +=
                                                " " +
                                                wWLFilterCriteriaAnd +
                                                " ";
                                        }
                                        wDayRangeCriteria =
                                            wWLDayFilterNextCriteria;
                                    }
                                    if (
                                        $.inArray(
                                            "Completed",
                                            SearchCriteria.portal_status_code
                                        ) > -1 ||
                                        $.inArray(
                                            "Approved",
                                            SearchCriteria.status_code
                                        ) > -1 ||
                                        $.inArray(
                                            "OrderSigned",
                                            SearchCriteria.status_code
                                        ) > -1 ||
                                        $.inArray(
                                            "To be Scheduled",
                                            SearchCriteria.portal_status_code
                                        ) > -1 ||
                                        $.inArray(
                                            "OrderDrafted",
                                            SearchCriteria.status_code
                                        ) > -1 ||
                                        $.inArray(
                                            "Order Drafted",
                                            SearchCriteria.portal_status_code
                                        ) > -1 ||
                                        $.inArray(
                                            "OrderPendingApproval",
                                            SearchCriteria.status_code
                                        ) > -1 ||
                                        $.inArray(
                                            "Pending Approval",
                                            SearchCriteria.portal_status_code
                                        ) > -1
                                    ) {
                                        var StartDate = dateFormat(
                                            new Date(
                                                new Date().setDate(
                                                    new Date().getDate() +
                                                        Number(data * -1)
                                                )
                                            ),
                                            "mm/dd/yyyy"
                                        );
                                        if (StatusDateFilter != "") {
                                            StatusDateFilter += " && ";
                                        }
                                        StatusDateFilter +=
                                            "new Date(parseInt($." +
                                            wStatusSpecficRangeColumn +
                                            ".substr(6))) >= new Date('" +
                                            StartDate +
                                            "')";
                                        if (wDayRangeCriteria != "") {
                                            wDayRangeCriteria +=
                                                " " +
                                                wWLFilterCriteriaAnd +
                                                " ";
                                        }
                                        wDayRangeCriteria +=
                                            wWLDayFilterPreviousCriteria;
                                    }
                                    SubFilter += StatusDateFilter;
                                } else if (SearchCriteria.status_code != null) {
                                    var StatusDateFilter = "";
                                    if (
                                        $.inArray(
                                            "Scheduled",
                                            SearchCriteria.status_code
                                        ) > -1
                                    ) {
                                        var StartDate = dateFormat(
                                            new Date(
                                                new Date().setDate(
                                                    new Date().getDate() +
                                                        Number(data * -1)
                                                )
                                            ),
                                            "mm/dd/yyyy"
                                        );
                                        if (StatusDateFilter != "") {
                                            StatusDateFilter += " && ";
                                        }
                                        StatusDateFilter +=
                                            "new Date(parseInt($." +
                                            wStatusSpecficRangeColumn +
                                            ".substr(6))) >= new Date('" +
                                            StartDate +
                                            "')";
                                        if (wDayRangeCriteria != "") {
                                            wDayRangeCriteria +=
                                                " " +
                                                wWLFilterCriteriaAnd +
                                                " ";
                                        }
                                        wDayRangeCriteria =
                                            wWLDayFilterNextCriteria;
                                    }
                                    if (
                                        $.inArray(
                                            "Dictated",
                                            SearchCriteria.status_code
                                        ) > -1 ||
                                        $.inArray(
                                            "ExamDone",
                                            SearchCriteria.status_code
                                        ) > -1 ||
                                        $.inArray(
                                            "ExamDoneTechOnly",
                                            SearchCriteria.status_code
                                        ) > -1 ||
                                        $.inArray(
                                            "ExtReportVerified",
                                            SearchCriteria.status_code
                                        ) > -1 ||
                                        $.inArray(
                                            "RepeatDone",
                                            SearchCriteria.status_code
                                        ) > -1 ||
                                        $.inArray(
                                            "ReportDrafted",
                                            SearchCriteria.status_code
                                        ) > -1 ||
                                        $.inArray(
                                            "Signed1",
                                            SearchCriteria.status_code
                                        ) > -1 ||
                                        $.inArray(
                                            "TentativelySigned1",
                                            SearchCriteria.status_code
                                        ) > -1 ||
                                        $.inArray(
                                            "Transcribed",
                                            SearchCriteria.status_code
                                        ) > -1 ||
                                        $.inArray(
                                            "OrderSigned",
                                            SearchCriteria.status_code
                                        ) > -1 ||
                                        $.inArray(
                                            "OrderDrafted",
                                            SearchCriteria.status_code
                                        ) > -1 ||
                                        $.inArray(
                                            "OrderPendingSigned",
                                            SearchCriteria.status_code
                                        ) > -1
                                    ) {
                                        var StartDate = dateFormat(
                                            new Date(
                                                new Date().setDate(
                                                    new Date().getDate() +
                                                        Number(data * -1)
                                                )
                                            ),
                                            "mm/dd/yyyy"
                                        );
                                        if (StatusDateFilter != "") {
                                            StatusDateFilter += " && ";
                                        }
                                        StatusDateFilter +=
                                            "new Date(parseInt($." +
                                            wStatusSpecficRangeColumn +
                                            ".substr(6))) >= new Date('" +
                                            StartDate +
                                            "')";
                                        if (wDayRangeCriteria != "") {
                                            wDayRangeCriteria +=
                                                " " +
                                                wWLFilterCriteriaAnd +
                                                " ";
                                        }
                                        wDayRangeCriteria +=
                                            wWLDayFilterPreviousCriteria;
                                    }
                                    SubFilter += StatusDateFilter;
                                } else {
                                    wDayRangeCriteria =
                                        wWLDayFilterPreviousAndNextCriteria;
                                    var StartDate = dateFormat(
                                        new Date(
                                            new Date().setDate(
                                                new Date().getDate() +
                                                    Number(data * -1)
                                            )
                                        ),
                                        "mm/dd/yyyy"
                                    );
                                    var EndDate = dateFormat(
                                        new Date(
                                            new Date().setDate(
                                                new Date().getDate() +
                                                    (Number(data) + 1)
                                            )
                                        ),
                                        "mm/dd/yyyy"
                                    );
                                    SubFilter +=
                                        "new Date(parseInt($." +
                                        wStatusSpecficRangeColumn +
                                        ".substr(6))) >= new Date('" +
                                        StartDate +
                                        "')";
                                    SubFilter += " && ";
                                    SubFilter +=
                                        "new Date(parseInt($." +
                                        wStatusSpecficRangeColumn +
                                        ".substr(6))) <= new Date('" +
                                        EndDate +
                                        "')";
                                }
                                wDayRangeCriteria = String.format(
                                    wWLDayFilterCriteria,
                                    wDayRangeCriteria,
                                    wRange
                                );
                                break;
                        }
                        filter += SubFilter;
                        //SubFilter += "new Date(parseInt($." + mDayRangeColumn + ".substr(6))) >= new Date('" +data + "')";
                        break;
                    default:
                        // Copy of lowercase filter, duplicated filter criteria in case where upper case does need ot be ahndled differently
                        if (Array.isArray(SearchCriteria[key])) {
                            if (
                                WLData != undefined &&
                                WLData.length > 0 &&
                                Array.isArray(WLData[0][key])
                            ) {
                                filter += " (";
                                $.each(data, function (index, data) {
                                    if (index > 0) {
                                        filter += " || ";
                                    }
                                    if (
                                        filter != "" &&
                                        filter != " &&  (" &&
                                        !filter.endsWith("|| ")
                                    ) {
                                        filter += " || ";
                                    }
                                    filter +=
                                        "Enumerable.From($." +
                                        key +
                                        ").Any('$==\"" +
                                        data +
                                        "\"')";
                                });
                                filter += ") ";
                            } else {
                                filter += " (";
                                $.each(data, function (index, data) {
                                    if (index > 0) {
                                        filter += " || ";
                                    }
                                    //filter += "$." + key + "=='" + data + "'";
                                    if (data.toLowerCase() == "null") {
                                        filter += "$." + key + "==null";
                                    } else {
                                        filter +=
                                            "$." + key + "=='" + data + "'";
                                    }
                                });
                                if (
                                    key == "requested_by_person_key" &&
                                    wIncludeIfCCed
                                ) {
                                    $.each(data, function (index, data) {
                                        if (index > 0) {
                                            filter += " || ";
                                        }
                                        if (
                                            filter != "" &&
                                            filter != " &&  (" &&
                                            !filter.endsWith("|| ")
                                        ) {
                                            filter += " || ";
                                        }
                                        filter +=
                                            "Enumerable.From($.cc_doctor_key).Any('$==\"" +
                                            data +
                                            "\"')";
                                    });
                                }
                                filter += ") ";
                                if (!wSpecificSearchCriteria) {
                                    wExtraSerachCriteria +=
                                        "and " +
                                        data.length +
                                        "" +
                                        key +
                                        (data.length > 1 ? "s" : ""); //Add applied Filter
                                }
                            }
                        } else if (typeof SearchCriteria[key] === "object") {
                            SubQuery = "";
                            SubFilter = "";
                            $.each(
                                SearchCriteria[key],
                                function (CriteriaKey, data) {
                                    if (SubQuery != "") {
                                        SubFilter = " && ";
                                    }
                                    var Days = false;
                                    if (data % 1 === 0) {
                                        Days = true;
                                        data = dateFormat(
                                            new Date(
                                                new Date().setDate(
                                                    new Date().getDate() +
                                                        Number(data)
                                                )
                                            ),
                                            "mm/dd/yyyy"
                                        );
                                        //todo:date format
                                    }
                                    //new Date(parseInt(x[mDayRangeColumn].substr(6)))
                                    switch (CriteriaKey.toLowerCase()) {
                                        case "contains":
                                            SubFilter +=
                                                "$." +
                                                key +
                                                "=='%" +
                                                data +
                                                "%'";
                                            if (!wSpecificSearchCriteria) {
                                                wExtraSerachCriteria +=
                                                    "and " +
                                                    key +
                                                    " contains" +
                                                    data; //Add applied Filter
                                            }
                                            break;
                                        case "start":
                                            SubFilter +=
                                                "new Date(parseInt($." +
                                                key +
                                                ".substr(6))) >= new Date('" +
                                                data +
                                                "')";
                                            wDayRangeCriteria +=
                                                "" +
                                                (Days
                                                    ? " within the " +
                                                      (data.toString()[0] == "-"
                                                          ? "previous "
                                                          : "last ") +
                                                      (data.toString()[0] ==
                                                          "-" ||
                                                      data.toString()[0] == "+"
                                                          ? data
                                                                .toString()
                                                                .substr(1)
                                                          : data) +
                                                      " days"
                                                    : "greater then " +
                                                      dateFormat(
                                                          new Date(data),
                                                          jsDateFormat
                                                      )); //Add applied Filter
                                            //SubFilter += "$." + key + " >= '" + data + "'";
                                            break;
                                        case "end":
                                            SubFilter +=
                                                "new Date(parseInt($." +
                                                key +
                                                ".substr(6))) <= new Date('" +
                                                data +
                                                "')";
                                            wDayRangeCriteria +=
                                                "" +
                                                (Days
                                                    ? " within the " +
                                                      (data.toString()[0] == "-"
                                                          ? "previous "
                                                          : "last ") +
                                                      (data.toString()[0] ==
                                                          "-" ||
                                                      data.toString()[0] == "+"
                                                          ? data
                                                                .toString()
                                                                .substr(1)
                                                          : data) +
                                                      " days"
                                                    : "less then " +
                                                      dateFormat(
                                                          new Date(data),
                                                          jsDateFormat
                                                      )); //Add applied Filter
                                            //SubFilter += "$." + key + " <= '" + data + "'";
                                            break;
                                    }
                                    SubQuery += SubFilter;
                                }
                            );
                            filter += SubQuery;
                        } else if (
                            WLData.length > 0 &&
                            Array.isArray(WLData[0][key])
                        ) {
                            filter +=
                                "Enumerable.From($." +
                                key +
                                ").Any('$==\"" +
                                data +
                                "\"')";
                        } else {
                            //filter += "$." + key + "=='" + data + "'";
                            if (data.toLowerCase() == "null") {
                                filter += "$." + key + "==null";
                            } else {
                                filter += "$." + key + "=='" + data + "'";
                            }
                            if (!wSpecificSearchCriteria) {
                                wExtraSerachCriteria +=
                                    "and " + key + " matching" + data; //Add applied Filter
                            }
                        }
                        break;
                }
            }
            if (filter == " && " || filter == " || ") {
                filter = "";
            }
        }
        query += filter;
    });
    query = query.replaceAll("&&  &&", "&&");
    query = query.replaceAll("||  ||", "||");
    if (query.endsWith("&& ")) {
        query = query.substring(0, query.lastIndexOf("&&"));
    }
    if (query.endsWith("|| ")) {
        query = query.substring(0, query.lastIndexOf("||"));
    }
    query = query.trim();
    var FilteredData = Enumerable.From(WLData).Where(query).ToArray();
    if (SearchCriteria.patient_name != null) {
        FilteredData = Enumerable.From(FilteredData)
            .Where(function (x) {
                return (
                    x.patient_name
                        .toLowerCase()
                        .indexOf(SearchCriteria.patient_name.toLowerCase()) !==
                    -1
                );
            })
            .ToArray();
        wExtraSerachCriteria +=
            "and " +
            SearchCriteria.patient_name +
            " contains" +
            SearchCriteria.patient_name;
    }
    var wRequestedByCriteriaName = "";
    if (wviewingForPersonkey) {
        if (
            SearchCriteria[wActiveWorkingPersonKey][
                "requested_by_person_key"
            ] != null &&
            SearchCriteria[wActiveWorkingPersonKey][
                "requested_by_person_key"
            ] != "SELECTED ALL" &&
            SearchCriteria[wActiveWorkingPersonKey]["requested_by_person_key"]
                .length <= 2
        ) {
            var wRequestedQuery = "";
            var wRequestedByNamesArry = Enumerable.From(OrderingProviderList)
                .Where(function (x) {
                    return Enumerable.From(
                        SearchCriteria[wActiveWorkingPersonKey][
                            "requested_by_person_key"
                        ]
                    ).Contains(x.Value);
                })
                .Select("$.Text")
                .ToArray();
            if (
                SearchCriteria[wActiveWorkingPersonKey][
                    "requested_by_person_key"
                ].length > 0
            ) {
                if (wRequestedByNamesArry.length == 0) {
                    try {
                        if (ProviderFilterList !== undefined) {
                            wRequestedByNamesArry = Enumerable.From(
                                ProviderFilterList
                            )
                                .Where(function (x) {
                                    return Enumerable.From(
                                        SearchCriteria[wActiveWorkingPersonKey][
                                            "requested_by_person_key"
                                        ]
                                    ).Contains(x.Value);
                                })
                                .Select("$.Text")
                                .ToArray();
                        }
                    } catch (e) {
                        console.log("ProviderFilterList not defined");
                    }
                }
            }
            var wRequestedByCriteriaName =
                wRequestedByNamesArry == null
                    ? ""
                    : "" + wRequestedByNamesArry.join("~");
            if (wRequestedByCriteriaName != "") {
                pos = wRequestedByCriteriaName.lastIndexOf("~");
                if (pos > 0) {
                    wRequestedByCriteriaName =
                        wRequestedByCriteriaName.substring(0, pos) +
                        " or " +
                        wRequestedByCriteriaName.substring(pos + 1);
                }
                wRequestedByCriteriaName = wRequestedByCriteriaName.replace(
                    new RegExp("~", "g"),
                    ","
                );
            }
        }
    } else {
        if (
            SearchCriteria["requested_by_person_key"] != null &&
            SearchCriteria["requested_by_person_key"] != "SELECTED ALL" &&
            SearchCriteria["requested_by_person_key"].length <= 2
        ) {
            var wRequestedQuery = "";
            var wRequestedByNamesArry = Enumerable.From(OrderingProviderList)
                .Where(function (x) {
                    return Enumerable.From(
                        SearchCriteria["requested_by_person_key"]
                    ).Contains(x.Value);
                })
                .Select("$.Text")
                .ToArray();
            if (SearchCriteria["requested_by_person_key"].length > 0) {
                if (wRequestedByNamesArry.length == 0) {
                    try {
                        if (ProviderFilterList !== undefined) {
                            wRequestedByNamesArry = Enumerable.From(
                                ProviderFilterList
                            )
                                .Where(function (x) {
                                    return Enumerable.From(
                                        SearchCriteria[
                                            "requested_by_person_key"
                                        ]
                                    ).Contains(x.Value);
                                })
                                .Select("$.Text")
                                .ToArray();
                        }
                    } catch (e) {
                        console.log("ProviderFilterList not defined");
                    }
                }
            }
            var wRequestedByCriteriaName =
                wRequestedByNamesArry == null
                    ? ""
                    : "" + wRequestedByNamesArry.join("~");
            if (wRequestedByCriteriaName != "") {
                pos = wRequestedByCriteriaName.lastIndexOf("~");
                if (pos > 0) {
                    wRequestedByCriteriaName =
                        wRequestedByCriteriaName.substring(0, pos) +
                        " or " +
                        wRequestedByCriteriaName.substring(pos + 1);
                }
                wRequestedByCriteriaName = wRequestedByCriteriaName.replace(
                    new RegExp("~", "g"),
                    ","
                );
            }
        }
    }
    var ProcedureGroupListlength = "";
    var ProcedureGroupListlengthValue = "";
    var StatusList = "";
    //var wRequestedByFilter = (SearchCriteria['requested_by_person_key'] == null || SearchCriteria['requested_by_person_key'].length == OrderingProviderList.length ? "all providers" : "" + (SearchCriteria['requested_by_person_key'].length > 2 || (wRequestedByCriteriaName != null && wRequestedByCriteriaName != "") ? SearchCriteria['requested_by_person_key'].length + " provider" + (SearchCriteria['requested_by_person_key'].length > 1 ? "s" : "") : wRequestedByCriteriaName) + (wIncludeIfCCed ? " including cc doctors" : ""))
    var wRequestedByFilter = "";
    if (wviewingForPersonkey) {
        if (
            SearchCriteria[wActiveWorkingPersonKey][
                "requested_by_person_key"
            ] == null ||
            SearchCriteria[wActiveWorkingPersonKey][
                "requested_by_person_key"
            ] == "SELECTED ALL"
        ) {
            wRequestedByFilter = wAllProviders;
        } else {
            if (
                SearchCriteria[wActiveWorkingPersonKey][
                    "requested_by_person_key"
                ].length > 2
            ) {
                if (wIncludeIfCCed) {
                    wRequestedByFilter = String.format(
                        wIncludingccdoctors,
                        String.format(
                            wProviders,
                            SearchCriteria[wActiveWorkingPersonKey][
                                "requested_by_person_key"
                            ].length
                        )
                    );
                } else {
                    wRequestedByFilter = String.format(
                        wProviders,
                        SearchCriteria[wActiveWorkingPersonKey][
                            "requested_by_person_key"
                        ].length
                    );
                }
            } else {
                if (wIncludeIfCCed) {
                    wRequestedByFilter = String.format(
                        wIncludingccdoctors,
                        wRequestedByCriteriaName
                    );
                } else {
                    wRequestedByFilter = wRequestedByCriteriaName;
                }
            }
        }
    } else {
        if (
            SearchCriteria["requested_by_person_key"] == null ||
            SearchCriteria["requested_by_person_key"] == "SELECTED ALL"
        ) {
            wRequestedByFilter = wAllProviders;
        } else {
            if (SearchCriteria["requested_by_person_key"].length > 2) {
                if (wIncludeIfCCed) {
                    wRequestedByFilter = String.format(
                        wIncludingccdoctors,
                        String.format(
                            wProviders,
                            SearchCriteria["requested_by_person_key"].length
                        )
                    );
                } else {
                    wRequestedByFilter = String.format(
                        wProviders,
                        SearchCriteria["requested_by_person_key"].length
                    );
                }
            } else {
                if (wIncludeIfCCed) {
                    wRequestedByFilter = String.format(
                        wIncludingccdoctors,
                        wRequestedByCriteriaName
                    );
                } else {
                    wRequestedByFilter = wRequestedByCriteriaName;
                }
            }
        }
    }
    if (
        $.inArray("Completed", SearchCriteria.portal_status_code) > -1 ||
        ($.inArray("Approved", SearchCriteria.portal_status_code) > -1 &&
            $.inArray("Completed", SearchCriteria.portal_status_code) > -1)
    ) {
        ProcedureGroupListlength = "completed exams";
        ProcedureGroupListlengthValue = " completed ";
        //$.ajax({ type: "POST", url: BaseRootURL + '/AJAX/CountersAction', data: { counter_type_code: "completed_tab_rp" } });
        //LogMyCounter("completed_tab_rp");
    } else if ($.inArray("Scheduled", SearchCriteria.portal_status_code) > -1) {
        ProcedureGroupListlength = "scheduled exams";
        ProcedureGroupListlengthValue = "scheduled ";
        //LogMyCounter("scheduled_tab_rp");
    } else if (
        $.inArray("In Progress", SearchCriteria.portal_status_code) > -1
    ) {
        ProcedureGroupListlength = "in progress exams";
        ProcedureGroupListlengthValue = " in progress ";
        wDayRangeCriteria = "";
        //LogMyCounter("inprogress_tab_rp");
    } else if ($.inArray("OrderSigned", SearchCriteria.status_code) > -1) {
        ProcedureGroupListlength = "ordered exams";
        ProcedureGroupListlengthValue = " ordered ";
    } else {
        var WFilteredStatus;
        if (
            SearchCriteria.hasOwnProperty("portal_status_code") &&
            SearchCriteria.portal_status_code != null &&
            SearchCriteria.portal_status_code != ""
        ) {
            WFilteredStatus = SearchCriteria.portal_status_code;
        }
        if (
            SearchCriteria.hasOwnProperty("status_code") &&
            SearchCriteria.status_code != null &&
            SearchCriteria.status_code != ""
        ) {
            if (Array.isArray(SearchCriteria.status_code)) {
                if (Array.isArray(WFilteredStatus)) {
                    WFilteredStatus = WFilteredStatus.concat(
                        SearchCriteria.status_code
                    );
                } else if (
                    WFilteredStatus != "" &&
                    WFilteredStatus !== undefined
                ) {
                    var wCurrentFilteredStatus = WFilteredStatus;
                    WFilteredStatus = TranslateStatusCode(
                        SearchCriteria.status_code
                    );
                    WFilteredStatus.push(wCurrentFilteredStatus);
                } else {
                    WFilteredStatus = TranslateStatusCode(
                        SearchCriteria.status_code
                    );
                }
            } else {
                if (Array.isArray(WFilteredStatus)) {
                    WFilteredStatus.push(
                        TranslateStatusCode(SearchCriteria.status_code)
                    );
                } else {
                    WFilteredStatus = [
                        WFilteredStatus,
                        TranslateStatusCode(SearchCriteria.status_code),
                    ];
                }
                WFilteredStatus = TranslateStatusCode(
                    SearchCriteria.status_code
                );
            }
        }
        if (Array.isArray(WFilteredStatus)) {
            StatusList = WFilteredStatus.toString();
        } else {
            StatusList = WFilteredStatus;
        }
        ProcedureGroupListlength = String.format(wSingleExamType, StatusList); //StatusList+" exams";
        ProcedureGroupListlengthValue = " " + StatusList + " ";
    }
    //var wModalityTypeFilter = (SearchCriteria['modality_type'] == null ? ProcedureGroupListlength : (SearchCriteria['modality_type'].length == ProcedureGroupList.length ? ProcedureGroupListlengthValue+" all exam types" : ProcedureGroupListlengthValue + (SearchCriteria['modality_type'].length > 0 ? wModalityCriteria + " exams" : + "")));
    var wModalityTypeFilter = "";
    if (wviewingForPersonkey) {
        if (
            SearchCriteria[wActiveWorkingPersonKey]["modality_type"] == null ||
            SearchCriteria[wActiveWorkingPersonKey]["modality_type"].length ==
                ProcedureGroupList.length ||
            SearchCriteria[wActiveWorkingPersonKey]["modality_type"] ==
                "SELECTED ALL"
        ) {
            wModalityTypeFilter = wAllexamtypes;
        } else if (
            SearchCriteria[wActiveWorkingPersonKey]["modality_type"].length > 2
        ) {
            wModalityTypeFilter = String.format(
                wExamtypes,
                SearchCriteria[wActiveWorkingPersonKey]["modality_type"].length
            );
        } else {
            wModalityTypeFilter = String.format(
                wPortalSearchSummarySentenceExamType,
                wModalityCriteria
            );
        }
    } else {
        if (
            SearchCriteria["modality_type"] == null ||
            SearchCriteria["modality_type"].length ==
                ProcedureGroupList.length ||
            SearchCriteria["modality_type"] == "SELECTED ALL"
        ) {
            wModalityTypeFilter = wAllexamtypes;
        } else if (SearchCriteria["modality_type"].length > 2) {
            wModalityTypeFilter = String.format(
                wExamtypes,
                SearchCriteria["modality_type"].length
            );
        } else {
            wModalityTypeFilter = String.format(
                wPortalSearchSummarySentenceExamType,
                wModalityCriteria
            );
        }
    }
    //var wModalityTypeFilter = (SearchCriteria['modality_type'] == null || SearchCriteria['modality_type'].length == ProcedureGroupList.length ? ProcedureGroupListlength : ProcedureGroupListlengthValue + (SearchCriteria['modality_type'].length > 0 ? wModalityCriteria + " exams" : + ""));
    //var Sentence = "Patients {0}with {1}{2} {3} by {4}.".format((SearchCriteria['patient_name'] == null ? "" : "matching \"" + SearchCriteria['patient_name'] + "\" "), (SearchCriteria['status_code'] == null ? "" : ""), wModalityTypeFilter, wDayRangeCriteria, wRequestedByFilter);
    var Sentence = String.format(
        wPortalSearchSummarySentence,
        SearchCriteria["patient_name"] == null
            ? ""
            : "" +
                  String.format(
                      wPortalSearchSummarySentenceMatchName,
                      SearchCriteria["patient_name"]
                  ) +
                  "",
        wStatusCriteriaName == null
            ? ""
            : String.format(
                  wPortalSearchSummarySentenceStatus,
                  wStatusCriteriaName
              ),
        wModalityTypeFilter,
        wDayRangeCriteria,
        wRequestedByFilter
    );
    return { Data: FilteredData, FilterSentence: Sentence };
}
/*--------------------------------------------------------------------------
* linq.js - LINQ for JavaScript
* ver 2.2.0.2 (Jan. 21th, 2011)
*
* created and maintained by neuecc 
* licensed under Microsoft Public License(Ms-PL)
* http://neue.cc/
* http://linqjs.codeplex.com/
*--------------------------------------------------------------------------*/
Enumerable = (function ()
{
    var Enumerable = function (getEnumerator)
    {
        this.GetEnumerator = getEnumerator;
    }
    // Generator
    Enumerable.Choice = function () // variable argument
    {
        var args = (arguments[0] instanceof Array) ? arguments[0] : arguments;
        return new Enumerable(function ()
        {
            return new IEnumerator(
                Functions.Blank,
                function ()
                {
                    return this.Yield(args[Math.floor(Math.random() * args.length)]);
                },
                Functions.Blank);
        });
    }
    Enumerable.Cycle = function () // variable argument
    {
        var args = (arguments[0] instanceof Array) ? arguments[0] : arguments;
        return new Enumerable(function ()
        {
            var index = 0;
            return new IEnumerator(
                Functions.Blank,
                function ()
                {
                    if (index >= args.length) index = 0;
                    return this.Yield(args[index++]);
                },
                Functions.Blank);
        });
    }
    Enumerable.Empty = function ()
    {
        return new Enumerable(function ()
        {
            return new IEnumerator(
                Functions.Blank,
                function () { return false; },
                Functions.Blank);
        });
    }
    Enumerable.From = function (obj)
    {
        if (obj == null)
        {
            return Enumerable.Empty();
        }
        if (obj instanceof Enumerable)
        {
            return obj;
        }
        if (typeof obj == Types.Number || typeof obj == Types.Boolean)
        {
            return Enumerable.Repeat(obj, 1);
        }
        if (typeof obj == Types.String)
        {
            return new Enumerable(function ()
            {
                var index = 0;
                return new IEnumerator(
                    Functions.Blank,
                    function ()
                    {
                        return (index < obj.length) ? this.Yield(obj.charAt(index++)) : false;
                    },
                    Functions.Blank);
            });
        }
        if (typeof obj != Types.Function)
        {
            // array or array like object
            if (typeof obj.length == Types.Number)
            {
                return new ArrayEnumerable(obj);
            }
            // JScript's IEnumerable
            if (!(obj instanceof Object) && Utils.IsIEnumerable(obj))
            {
                return new Enumerable(function ()
                {
                    var isFirst = true;
                    var enumerator;
                    return new IEnumerator(
                        function () { enumerator = new Enumerator(obj); },
                        function ()
                        {
                            if (isFirst) isFirst = false;
                            else enumerator.moveNext();
                            return (enumerator.atEnd()) ? false : this.Yield(enumerator.item());
                        },
                        Functions.Blank);
                });
            }
        }
        // case function/object : Create KeyValuePair[]
        return new Enumerable(function ()
        {
            var array = [];
            var index = 0;
            return new IEnumerator(
                function ()
                {
                    for (var key in obj)
                    {
                        if (!(obj[key] instanceof Function))
                        {
                            array.push({ Key: key, Value: obj[key] });
                        }
                    }
                },
                function ()
                {
                    return (index < array.length)
                        ? this.Yield(array[index++])
                        : false;
                },
                Functions.Blank);
        });
    },
    Enumerable.Return = function (element)
    {
        return Enumerable.Repeat(element, 1);
    }
    // Overload:function(input, pattern)
    // Overload:function(input, pattern, flags)
    Enumerable.Matches = function (input, pattern, flags)
    {
        if (flags == null) flags = "";
        if (pattern instanceof RegExp)
        {
            flags += (pattern.ignoreCase) ? "i" : "";
            flags += (pattern.multiline) ? "m" : "";
            pattern = pattern.source;
        }
        if (flags.indexOf("g") === -1) flags += "g";
        return new Enumerable(function ()
        {
            var regex;
            return new IEnumerator(
                function () { regex = new RegExp(pattern, flags) },
                function ()
                {
                    var match = regex.exec(input);
                    return (match) ? this.Yield(match) : false;
                },
                Functions.Blank);
        });
    }
    // Overload:function(start, count)
    // Overload:function(start, count, step)
    Enumerable.Range = function (start, count, step)
    {
        if (step == null) step = 1;
        return Enumerable.ToInfinity(start, step).Take(count);
    }
    // Overload:function(start, count)
    // Overload:function(start, count, step)
    Enumerable.RangeDown = function (start, count, step)
    {
        if (step == null) step = 1;
        return Enumerable.ToNegativeInfinity(start, step).Take(count);
    }
    // Overload:function(start, to)
    // Overload:function(start, to, step)
    Enumerable.RangeTo = function (start, to, step)
    {
        if (step == null) step = 1;
        return (start < to)
            ? Enumerable.ToInfinity(start, step).TakeWhile(function (i) { return i <= to; })
            : Enumerable.ToNegativeInfinity(start, step).TakeWhile(function (i) { return i >= to; })
    }
    // Overload:function(obj)
    // Overload:function(obj, num)
    Enumerable.Repeat = function (obj, num)
    {
        if (num != null) return Enumerable.Repeat(obj).Take(num);
        return new Enumerable(function ()
        {
            return new IEnumerator(
                Functions.Blank,
                function () { return this.Yield(obj); },
                Functions.Blank);
        });
    }
    Enumerable.RepeatWithFinalize = function (initializer, finalizer)
    {
        initializer = Utils.CreateLambda(initializer);
        finalizer = Utils.CreateLambda(finalizer);
        return new Enumerable(function ()
        {
            var element;
            return new IEnumerator(
                function () { element = initializer(); },
                function () { return this.Yield(element); },
                function ()
                {
                    if (element != null)
                    {
                        finalizer(element);
                        element = null;
                    }
                });
        });
    }
    // Overload:function(func)
    // Overload:function(func, count)
    Enumerable.Generate = function (func, count)
    {
        if (count != null) return Enumerable.Generate(func).Take(count);
        func = Utils.CreateLambda(func);
        return new Enumerable(function ()
        {
            return new IEnumerator(
                Functions.Blank,
                function () { return this.Yield(func()); },
                Functions.Blank);
        });
    }
    // Overload:function()
    // Overload:function(start)
    // Overload:function(start, step)
    Enumerable.ToInfinity = function (start, step)
    {
        if (start == null) start = 0;
        if (step == null) step = 1;
        return new Enumerable(function ()
        {
            var value;
            return new IEnumerator(
                function () { value = start - step },
                function () { return this.Yield(value += step); },
                Functions.Blank);
        });
    }
    // Overload:function()
    // Overload:function(start)
    // Overload:function(start, step)
    Enumerable.ToNegativeInfinity = function (start, step)
    {
        if (start == null) start = 0;
        if (step == null) step = 1;
        return new Enumerable(function ()
        {
            var value;
            return new IEnumerator(
                function () { value = start + step },
                function () { return this.Yield(value -= step); },
                Functions.Blank);
        });
    }
    Enumerable.Unfold = function (seed, func)
    {
        func = Utils.CreateLambda(func);
        return new Enumerable(function ()
        {
            var isFirst = true;
            var value;
            return new IEnumerator(
                Functions.Blank,
                function ()
                {
                    if (isFirst)
                    {
                        isFirst = false;
                        value = seed;
                        return this.Yield(value);
                    }
                    value = func(value);
                    return this.Yield(value);
                },
                Functions.Blank);
        });
    }
    // Extension Methods
    Enumerable.prototype =
    {
        /* Projection and Filtering Methods */
        // Overload:function(func)
        // Overload:function(func, resultSelector)
        // Overload:function(func, resultSelector)
        CascadeBreadthFirst: function (func, resultSelector)
        {
            var source = this;
            func = Utils.CreateLambda(func);
            resultSelector = Utils.CreateLambda(resultSelector);
            return new Enumerable(function ()
            {
                var enumerator;
                var nestLevel = 0;
                var buffer = [];
                return new IEnumerator(
                    function () { enumerator = source.GetEnumerator(); },
                    function ()
                    {
                        while (true)
                        {
                            if (enumerator.MoveNext())
                            {
                                buffer.push(enumerator.Current());
                                return this.Yield(resultSelector(enumerator.Current(), nestLevel));
                            }
                            var next = Enumerable.From(buffer).SelectMany(function (x) { return func(x); });
                            if (!next.Any())
                            {
                                return false;
                            }
                            else
                            {
                                nestLevel++;
                                buffer = [];
                                Utils.Dispose(enumerator);
                                enumerator = next.GetEnumerator();
                            }
                        }
                    },
                    function () { Utils.Dispose(enumerator); });
            });
        },
        // Overload:function(func)
        // Overload:function(func, resultSelector)
        // Overload:function(func, resultSelector)
        CascadeDepthFirst: function (func, resultSelector)
        {
            var source = this;
            func = Utils.CreateLambda(func);
            resultSelector = Utils.CreateLambda(resultSelector);
            return new Enumerable(function ()
            {
                var enumeratorStack = [];
                var enumerator;
                return new IEnumerator(
                    function () { enumerator = source.GetEnumerator(); },
                    function ()
                    {
                        while (true)
                        {
                            if (enumerator.MoveNext())
                            {
                                var value = resultSelector(enumerator.Current(), enumeratorStack.length);
                                enumeratorStack.push(enumerator);
                                enumerator = Enumerable.From(func(enumerator.Current())).GetEnumerator();
                                return this.Yield(value);
                            }
                            if (enumeratorStack.length <= 0) return false;
                            Utils.Dispose(enumerator);
                            enumerator = enumeratorStack.pop();
                        }
                    },
                    function ()
                    {
                        try { Utils.Dispose(enumerator); }
                        finally { Enumerable.From(enumeratorStack).ForEach(function (s) { s.Dispose(); }) }
                    });
            });
        },
        Flatten: function ()
        {
            var source = this;
            return new Enumerable(function ()
            {
                var enumerator;
                var middleEnumerator = null;
                return new IEnumerator(
                    function () { enumerator = source.GetEnumerator(); },
                    function ()
                    {
                        while (true)
                        {
                            if (middleEnumerator != null)
                            {
                                if (middleEnumerator.MoveNext())
                                {
                                    return this.Yield(middleEnumerator.Current());
                                }
                                else
                                {
                                    middleEnumerator = null;
                                }
                            }
                            if (enumerator.MoveNext())
                            {
                                if (enumerator.Current() instanceof Array)
                                {
                                    Utils.Dispose(middleEnumerator);
                                    middleEnumerator = Enumerable.From(enumerator.Current())
                                        .SelectMany(Functions.Identity)
                                        .Flatten()
                                        .GetEnumerator();
                                    continue;
                                }
                                else
                                {
                                    return this.Yield(enumerator.Current());
                                }
                            }
                            return false;
                        }
                    },
                    function ()
                    {
                        try { Utils.Dispose(enumerator); }
                        finally { Utils.Dispose(middleEnumerator); }
                    });
            });
        },
        Pairwise: function (selector)
        {
            var source = this;
            selector = Utils.CreateLambda(selector);
            return new Enumerable(function ()
            {
                var enumerator;
                return new IEnumerator(
                    function ()
                    {
                        enumerator = source.GetEnumerator();
                        enumerator.MoveNext();
                    },
                    function ()
                    {
                        var prev = enumerator.Current();
                        return (enumerator.MoveNext())
                            ? this.Yield(selector(prev, enumerator.Current()))
                            : false;
                    },
                    function () { Utils.Dispose(enumerator); });
            });
        },
        // Overload:function(func)
        // Overload:function(seed,func)
        // Overload:function(seed,func,resultSelector)
        Scan: function (seed, func, resultSelector)
        {
            if (resultSelector != null) return this.Scan(seed, func).Select(resultSelector);
            var isUseSeed;
            if (func == null)
            {
                func = Utils.CreateLambda(seed); // arguments[0]
                isUseSeed = false;
            }
            else
            {
                func = Utils.CreateLambda(func);
                isUseSeed = true;
            }
            var source = this;
            return new Enumerable(function ()
            {
                var enumerator;
                var value;
                var isFirst = true;
                return new IEnumerator(
                    function () { enumerator = source.GetEnumerator(); },
                    function ()
                    {
                        if (isFirst)
                        {
                            isFirst = false;
                            if (!isUseSeed)
                            {
                                if (enumerator.MoveNext())
                                {
                                    return this.Yield(value = enumerator.Current());
                                }
                            }
                            else
                            {
                                return this.Yield(value = seed);
                            }
                        }
                        return (enumerator.MoveNext())
                            ? this.Yield(value = func(value, enumerator.Current()))
                            : false;
                    },
                    function () { Utils.Dispose(enumerator); });
            });
        },
        // Overload:function(selector)
        // Overload:function(selector)
        Select: function (selector)
        {
            var source = this;
            selector = Utils.CreateLambda(selector);
            return new Enumerable(function ()
            {
                var enumerator;
                var index = 0;
                return new IEnumerator(
                    function () { enumerator = source.GetEnumerator(); },
                    function ()
                    {
                        return (enumerator.MoveNext())
                            ? this.Yield(selector(enumerator.Current(), index++))
                            : false;
                    },
                    function () { Utils.Dispose(enumerator); })
            });
        },
        // Overload:function(collectionSelector)
        // Overload:function(collectionSelector)
        // Overload:function(collectionSelector,resultSelector)
        // Overload:function(collectionSelector,resultSelector)
        SelectMany: function (collectionSelector, resultSelector)
        {
            var source = this;
            collectionSelector = Utils.CreateLambda(collectionSelector);
            if (resultSelector == null) resultSelector = function (a, b) { return b; }
            resultSelector = Utils.CreateLambda(resultSelector);
            return new Enumerable(function ()
            {
                var enumerator;
                var middleEnumerator = undefined;
                var index = 0;
                return new IEnumerator(
                    function () { enumerator = source.GetEnumerator(); },
                    function ()
                    {
                        if (middleEnumerator === undefined)
                        {
                            if (!enumerator.MoveNext()) return false;
                        }
                        do
                        {
                            if (middleEnumerator == null)
                            {
                                var middleSeq = collectionSelector(enumerator.Current(), index++);
                                middleEnumerator = Enumerable.From(middleSeq).GetEnumerator();
                            }
                            if (middleEnumerator.MoveNext())
                            {
                                return this.Yield(resultSelector(enumerator.Current(), middleEnumerator.Current()));
                            }
                            Utils.Dispose(middleEnumerator);
                            middleEnumerator = null;
                        } while (enumerator.MoveNext())
                        return false;
                    },
                    function ()
                    {
                        try { Utils.Dispose(enumerator); }
                        finally { Utils.Dispose(middleEnumerator); }
                    })
            });
        },
        // Overload:function(predicate)
        // Overload:function(predicate)
        Where: function (predicate)
        {
            predicate = Utils.CreateLambda(predicate);
            var source = this;
            return new Enumerable(function ()
            {
                var enumerator;
                var index = 0;
                return new IEnumerator(
                    function () { enumerator = source.GetEnumerator(); },
                    function ()
                    {
                        while (enumerator.MoveNext())
                        {
                            if (predicate(enumerator.Current(), index++))
                            {
                                return this.Yield(enumerator.Current());
                            }
                        }
                        return false;
                    },
                    function () { Utils.Dispose(enumerator); })
            });
        },
        OfType: function (type)
        {
            var typeName;
            switch (type)
            {
                case Number: typeName = Types.Number; break;
                case String: typeName = Types.String; break;
                case Boolean: typeName = Types.Boolean; break;
                case Function: typeName = Types.Function; break;
                default: typeName = null; break;
            }
            return (typeName === null)
                ? this.Where(function (x) { return x instanceof type })
                : this.Where(function (x) { return typeof x === typeName });
        },
        // Overload:function(second,selector)
        // Overload:function(second,selector)
        Zip: function (second, selector)
        {
            selector = Utils.CreateLambda(selector);
            var source = this;
            return new Enumerable(function ()
            {
                var firstEnumerator;
                var secondEnumerator;
                var index = 0;
                return new IEnumerator(
                    function ()
                    {
                        firstEnumerator = source.GetEnumerator();
                        secondEnumerator = Enumerable.From(second).GetEnumerator();
                    },
                    function ()
                    {
                        if (firstEnumerator.MoveNext() && secondEnumerator.MoveNext())
                        {
                            return this.Yield(selector(firstEnumerator.Current(), secondEnumerator.Current(), index++));
                        }
                        return false;
                    },
                    function ()
                    {
                        try { Utils.Dispose(firstEnumerator); }
                        finally { Utils.Dispose(secondEnumerator); }
                    })
            });
        },
        /* Join Methods */
        // Overload:function (inner, outerKeySelector, innerKeySelector, resultSelector)
        // Overload:function (inner, outerKeySelector, innerKeySelector, resultSelector, compareSelector)
        Join: function (inner, outerKeySelector, innerKeySelector, resultSelector, compareSelector)
        {
            outerKeySelector = Utils.CreateLambda(outerKeySelector);
            innerKeySelector = Utils.CreateLambda(innerKeySelector);
            resultSelector = Utils.CreateLambda(resultSelector);
            compareSelector = Utils.CreateLambda(compareSelector);
            var source = this;
            return new Enumerable(function ()
            {
                var outerEnumerator;
                var lookup;
                var innerElements = null;
                var innerCount = 0;
                return new IEnumerator(
                    function ()
                    {
                        outerEnumerator = source.GetEnumerator();
                        lookup = Enumerable.From(inner).ToLookup(innerKeySelector, Functions.Identity, compareSelector);
                    },
                    function ()
                    {
                        while (true)
                        {
                            if (innerElements != null)
                            {
                                var innerElement = innerElements[innerCount++];
                                if (innerElement !== undefined)
                                {
                                    return this.Yield(resultSelector(outerEnumerator.Current(), innerElement));
                                }
                                innerElement = null;
                                innerCount = 0;
                            }
                            if (outerEnumerator.MoveNext())
                            {
                                var key = outerKeySelector(outerEnumerator.Current());
                                innerElements = lookup.Get(key).ToArray();
                            }
                            else
                            {
                                return false;
                            }
                        }
                    },
                    function () { Utils.Dispose(outerEnumerator); })
            });
        },
        // Overload:function (inner, outerKeySelector, innerKeySelector, resultSelector)
        // Overload:function (inner, outerKeySelector, innerKeySelector, resultSelector, compareSelector)
        GroupJoin: function (inner, outerKeySelector, innerKeySelector, resultSelector, compareSelector)
        {
            outerKeySelector = Utils.CreateLambda(outerKeySelector);
            innerKeySelector = Utils.CreateLambda(innerKeySelector);
            resultSelector = Utils.CreateLambda(resultSelector);
            compareSelector = Utils.CreateLambda(compareSelector);
            var source = this;
            return new Enumerable(function ()
            {
                var enumerator = source.GetEnumerator();
                var lookup = null;
                return new IEnumerator(
                    function ()
                    {
                        enumerator = source.GetEnumerator();
                        lookup = Enumerable.From(inner).ToLookup(innerKeySelector, Functions.Identity, compareSelector);
                    },
                    function ()
                    {
                        if (enumerator.MoveNext())
                        {
                            var innerElement = lookup.Get(outerKeySelector(enumerator.Current()));
                            return this.Yield(resultSelector(enumerator.Current(), innerElement));
                        }
                        return false;
                    },
                    function () { Utils.Dispose(enumerator); })
            });
        },
        /* Set Methods */
        All: function (predicate)
        {
            predicate = Utils.CreateLambda(predicate);
            var result = true;
            this.ForEach(function (x)
            {
                if (!predicate(x))
                {
                    result = false;
                    return false; // break
                }
            });
            return result;
        },
        // Overload:function()
        // Overload:function(predicate)
        Any: function (predicate)
        {
            predicate = Utils.CreateLambda(predicate);
            var enumerator = this.GetEnumerator();
            try
            {
                if (arguments.length == 0) return enumerator.MoveNext(); // case:function()
                while (enumerator.MoveNext()) // case:function(predicate)
                {
                    if (predicate(enumerator.Current())) return true;
                }
                return false;
            }
            finally { Utils.Dispose(enumerator); }
        },
        Concat: function (second)
        {
            var source = this;
            return new Enumerable(function ()
            {
                var firstEnumerator;
                var secondEnumerator;
                return new IEnumerator(
                    function () { firstEnumerator = source.GetEnumerator(); },
                    function ()
                    {
                        if (secondEnumerator == null)
                        {
                            if (firstEnumerator.MoveNext()) return this.Yield(firstEnumerator.Current());
                            secondEnumerator = Enumerable.From(second).GetEnumerator();
                        }
                        if (secondEnumerator.MoveNext()) return this.Yield(secondEnumerator.Current());
                        return false;
                    },
                    function ()
                    {
                        try { Utils.Dispose(firstEnumerator); }
                        finally { Utils.Dispose(secondEnumerator); }
                    })
            });
        },
        Insert: function (index, second)
        {
            var source = this;
            return new Enumerable(function ()
            {
                var firstEnumerator;
                var secondEnumerator;
                var count = 0;
                var isEnumerated = false;
                return new IEnumerator(
                    function ()
                    {
                        firstEnumerator = source.GetEnumerator();
                        secondEnumerator = Enumerable.From(second).GetEnumerator();
                    },
                    function ()
                    {
                        if (count == index && secondEnumerator.MoveNext())
                        {
                            isEnumerated = true;
                            return this.Yield(secondEnumerator.Current());
                        }
                        if (firstEnumerator.MoveNext())
                        {
                            count++;
                            return this.Yield(firstEnumerator.Current());
                        }
                        if (!isEnumerated && secondEnumerator.MoveNext())
                        {
                            return this.Yield(secondEnumerator.Current());
                        }
                        return false;
                    },
                    function ()
                    {
                        try { Utils.Dispose(firstEnumerator); }
                        finally { Utils.Dispose(secondEnumerator); }
                    })
            });
        },
        Alternate: function (value)
        {
            value = Enumerable.Return(value);
            return this.SelectMany(function (elem)
            {
                return Enumerable.Return(elem).Concat(value);
            }).TakeExceptLast();
        },
        // Overload:function(value)
        // Overload:function(value, compareSelector)
        Contains: function (value, compareSelector)
        {
            compareSelector = Utils.CreateLambda(compareSelector);
            var enumerator = this.GetEnumerator();
            try
            {
                while (enumerator.MoveNext())
                {
                    if (compareSelector(enumerator.Current()) === value) return true;
                }
                return false;
            }
            finally { Utils.Dispose(enumerator) }
        },
        DefaultIfEmpty: function (defaultValue)
        {
            var source = this;
            return new Enumerable(function ()
            {
                var enumerator;
                var isFirst = true;
                return new IEnumerator(
                    function () { enumerator = source.GetEnumerator(); },
                    function ()
                    {
                        if (enumerator.MoveNext())
                        {
                            isFirst = false;
                            return this.Yield(enumerator.Current());
                        }
                        else if (isFirst)
                        {
                            isFirst = false;
                            return this.Yield(defaultValue);
                        }
                        return false;
                    },
                    function () { Utils.Dispose(enumerator); })
            });
        },
        // Overload:function()
        // Overload:function(compareSelector)
        Distinct: function (compareSelector)
        {
            return this.Except(Enumerable.Empty(), compareSelector);
        },
        // Overload:function(second)
        // Overload:function(second, compareSelector)
        Except: function (second, compareSelector)
        {
            compareSelector = Utils.CreateLambda(compareSelector);
            var source = this;
            return new Enumerable(function ()
            {
                var enumerator;
                var keys;
                return new IEnumerator(
                    function ()
                    {
                        enumerator = source.GetEnumerator();
                        keys = new Dictionary(compareSelector);
                        Enumerable.From(second).ForEach(function (key) { keys.Add(key); });
                    },
                    function ()
                    {
                        while (enumerator.MoveNext())
                        {
                            var current = enumerator.Current();
                            if (!keys.Contains(current))
                            {
                                keys.Add(current);
                                return this.Yield(current);
                            }
                        }
                        return false;
                    },
                    function () { Utils.Dispose(enumerator); })
            });
        },
        // Overload:function(second)
        // Overload:function(second, compareSelector)
        Intersect: function (second, compareSelector)
        {
            compareSelector = Utils.CreateLambda(compareSelector);
            var source = this;
            return new Enumerable(function ()
            {
                var enumerator;
                var keys;
                var outs;
                return new IEnumerator(
                    function ()
                    {
                        enumerator = source.GetEnumerator();
                        keys = new Dictionary(compareSelector);
                        Enumerable.From(second).ForEach(function (key) { keys.Add(key); });
                        outs = new Dictionary(compareSelector);
                    },
                    function ()
                    {
                        while (enumerator.MoveNext())
                        {
                            var current = enumerator.Current();
                            if (!outs.Contains(current) && keys.Contains(current))
                            {
                                outs.Add(current);
                                return this.Yield(current);
                            }
                        }
                        return false;
                    },
                    function () { Utils.Dispose(enumerator); })
            });
        },
        // Overload:function(second)
        // Overload:function(second, compareSelector)
        SequenceEqual: function (second, compareSelector)
        {
            compareSelector = Utils.CreateLambda(compareSelector);
            var firstEnumerator = this.GetEnumerator();
            try
            {
                var secondEnumerator = Enumerable.From(second).GetEnumerator();
                try
                {
                    while (firstEnumerator.MoveNext())
                    {
                        if (!secondEnumerator.MoveNext()
                            || compareSelector(firstEnumerator.Current()) !== compareSelector(secondEnumerator.Current()))
                        {
                            return false;
                        }
                    }
                    if (secondEnumerator.MoveNext()) return false;
                    return true;
                }
                finally { Utils.Dispose(secondEnumerator); }
            }
            finally { Utils.Dispose(firstEnumerator); }
        },
        Union: function (second, compareSelector)
        {
            compareSelector = Utils.CreateLambda(compareSelector);
            var source = this;
            return new Enumerable(function ()
            {
                var firstEnumerator;
                var secondEnumerator;
                var keys;
                return new IEnumerator(
                    function ()
                    {
                        firstEnumerator = source.GetEnumerator();
                        keys = new Dictionary(compareSelector);
                    },
                    function ()
                    {
                        var current;
                        if (secondEnumerator === undefined)
                        {
                            while (firstEnumerator.MoveNext())
                            {
                                current = firstEnumerator.Current();
                                if (!keys.Contains(current))
                                {
                                    keys.Add(current);
                                    return this.Yield(current);
                                }
                            }
                            secondEnumerator = Enumerable.From(second).GetEnumerator();
                        }
                        while (secondEnumerator.MoveNext())
                        {
                            current = secondEnumerator.Current();
                            if (!keys.Contains(current))
                            {
                                keys.Add(current);
                                return this.Yield(current);
                            }
                        }
                        return false;
                    },
                    function ()
                    {
                        try { Utils.Dispose(firstEnumerator); }
                        finally { Utils.Dispose(secondEnumerator); }
                    })
            });
        },
        /* Ordering Methods */
        OrderBy: function (keySelector)
        {
            return new OrderedEnumerable(this, keySelector, false);
        },
        OrderByDescending: function (keySelector)
        {
            return new OrderedEnumerable(this, keySelector, true);
        },
        Reverse: function ()
        {
            var source = this;
            return new Enumerable(function ()
            {
                var buffer;
                var index;
                return new IEnumerator(
                    function ()
                    {
                        buffer = source.ToArray();
                        index = buffer.length;
                    },
                    function ()
                    {
                        return (index > 0)
                            ? this.Yield(buffer[--index])
                            : false;
                    },
                    Functions.Blank)
            });
        },
        Shuffle: function ()
        {
            var source = this;
            return new Enumerable(function ()
            {
                var buffer;
                return new IEnumerator(
                    function () { buffer = source.ToArray(); },
                    function ()
                    {
                        if (buffer.length > 0)
                        {
                            var i = Math.floor(Math.random() * buffer.length);
                            return this.Yield(buffer.splice(i, 1)[0]);
                        }
                        return false;
                    },
                    Functions.Blank)
            });
        },
        /* Grouping Methods */
        // Overload:function(keySelector)
        // Overload:function(keySelector,elementSelector)
        // Overload:function(keySelector,elementSelector,resultSelector)
        // Overload:function(keySelector,elementSelector,resultSelector,compareSelector)
        GroupBy: function (keySelector, elementSelector, resultSelector, compareSelector)
        {
            var source = this;
            keySelector = Utils.CreateLambda(keySelector);
            elementSelector = Utils.CreateLambda(elementSelector);
            if (resultSelector != null) resultSelector = Utils.CreateLambda(resultSelector);
            compareSelector = Utils.CreateLambda(compareSelector);
            return new Enumerable(function ()
            {
                var enumerator;
                return new IEnumerator(
                    function ()
                    {
                        enumerator = source.ToLookup(keySelector, elementSelector, compareSelector)
                            .ToEnumerable()
                            .GetEnumerator();
                    },
                    function ()
                    {
                        while (enumerator.MoveNext())
                        {
                            return (resultSelector == null)
                                ? this.Yield(enumerator.Current())
                                : this.Yield(resultSelector(enumerator.Current().Key(), enumerator.Current()));
                        }
                        return false;
                    },
                    function () { Utils.Dispose(enumerator); })
            });
        },
        // Overload:function(keySelector)
        // Overload:function(keySelector,elementSelector)
        // Overload:function(keySelector,elementSelector,resultSelector)
        // Overload:function(keySelector,elementSelector,resultSelector,compareSelector)
        PartitionBy: function (keySelector, elementSelector, resultSelector, compareSelector)
        {
            var source = this;
            keySelector = Utils.CreateLambda(keySelector);
            elementSelector = Utils.CreateLambda(elementSelector);
            compareSelector = Utils.CreateLambda(compareSelector);
            var hasResultSelector;
            if (resultSelector == null)
            {
                hasResultSelector = false;
                resultSelector = function (key, group) { return new Grouping(key, group) }
            }
            else
            {
                hasResultSelector = true;
                resultSelector = Utils.CreateLambda(resultSelector);
            }
            return new Enumerable(function ()
            {
                var enumerator;
                var key;
                var compareKey;
                var group = [];
                return new IEnumerator(
                    function ()
                    {
                        enumerator = source.GetEnumerator();
                        if (enumerator.MoveNext())
                        {
                            key = keySelector(enumerator.Current());
                            compareKey = compareSelector(key);
                            group.push(elementSelector(enumerator.Current()));
                        }
                    },
                    function ()
                    {
                        var hasNext;
                        while ((hasNext = enumerator.MoveNext()) == true)
                        {
                            if (compareKey === compareSelector(keySelector(enumerator.Current())))
                            {
                                group.push(elementSelector(enumerator.Current()));
                            }
                            else break;
                        }
                        if (group.length > 0)
                        {
                            var result = (hasResultSelector)
                                ? resultSelector(key, Enumerable.From(group))
                                : resultSelector(key, group);
                            if (hasNext)
                            {
                                key = keySelector(enumerator.Current());
                                compareKey = compareSelector(key);
                                group = [elementSelector(enumerator.Current())];
                            }
                            else group = [];
                            return this.Yield(result);
                        }
                        return false;
                    },
                    function () { Utils.Dispose(enumerator); })
            });
        },
        BufferWithCount: function (count)
        {
            var source = this;
            return new Enumerable(function ()
            {
                var enumerator;
                return new IEnumerator(
                function () { enumerator = source.GetEnumerator(); },
                function ()
                {
                    var array = [];
                    var index = 0;
                    while (enumerator.MoveNext())
                    {
                        array.push(enumerator.Current());
                        if (++index >= count) return this.Yield(array);
                    }
                    if (array.length > 0) return this.Yield(array);
                    return false;
                },
                function () { Utils.Dispose(enumerator); })
            });
        },
        /* Aggregate Methods */
        // Overload:function(func)
        // Overload:function(seed,func)
        // Overload:function(seed,func,resultSelector)
        Aggregate: function (seed, func, resultSelector)
        {
            return this.Scan(seed, func, resultSelector).Last();
        },
        // Overload:function()
        // Overload:function(selector)
        Average: function (selector)
        {
            selector = Utils.CreateLambda(selector);
            var sum = 0;
            var count = 0;
            this.ForEach(function (x)
            {
                sum += selector(x);
                ++count;
            });
            return sum / count;
        },
        // Overload:function()
        // Overload:function(predicate)
        Count: function (predicate)
        {
            predicate = (predicate == null) ? Functions.True : Utils.CreateLambda(predicate);
            var count = 0;
            this.ForEach(function (x, i)
            {
                if (predicate(x, i)) ++count;
            });
            return count;
        },
        // Overload:function()
        // Overload:function(selector)
        Max: function (selector)
        {
            if (selector == null) selector = Functions.Identity;
            return this.Select(selector).Aggregate(function (a, b) { return (a > b) ? a : b; });
        },
        // Overload:function()
        // Overload:function(selector)
        Min: function (selector)
        {
            if (selector == null) selector = Functions.Identity;
            return this.Select(selector).Aggregate(function (a, b) { return (a < b) ? a : b; });
        },
        MaxBy: function (keySelector)
        {
            keySelector = Utils.CreateLambda(keySelector);
            return this.Aggregate(function (a, b) { return (keySelector(a) > keySelector(b)) ? a : b });
        },
        MinBy: function (keySelector)
        {
            keySelector = Utils.CreateLambda(keySelector);
            return this.Aggregate(function (a, b) { return (keySelector(a) < keySelector(b)) ? a : b });
        },
        // Overload:function()
        // Overload:function(selector)
        Sum: function (selector)
        {
            if (selector == null) selector = Functions.Identity;
            return this.Select(selector).Aggregate(0, function (a, b) { return a + b; });
        },
        /* Paging Methods */
        ElementAt: function (index)
        {
            var value;
            var found = false;
            this.ForEach(function (x, i)
            {
                if (i == index)
                {
                    value = x;
                    found = true;
                    return false;
                }
            });
            if (!found) throw new Error("index is less than 0 or greater than or equal to the number of elements in source.");
            return value;
        },
        ElementAtOrDefault: function (index, defaultValue)
        {
            var value;
            var found = false;
            this.ForEach(function (x, i)
            {
                if (i == index)
                {
                    value = x;
                    found = true;
                    return false;
                }
            });
            return (!found) ? defaultValue : value;
        },
        // Overload:function()
        // Overload:function(predicate)
        First: function (predicate)
        {
            if (predicate != null) return this.Where(predicate).First();
            var value;
            var found = false;
            this.ForEach(function (x)
            {
                value = x;
                found = true;
                return false;
            });
            if (!found) throw new Error("First:No element satisfies the condition.");
            return value;
        },
        // Overload:function(defaultValue)
        // Overload:function(defaultValue,predicate)
        FirstOrDefault: function (defaultValue, predicate)
        {
            if (predicate != null) return this.Where(predicate).FirstOrDefault(defaultValue);
            var value;
            var found = false;
            this.ForEach(function (x)
            {
                value = x;
                found = true;
                return false;
            });
            return (!found) ? defaultValue : value;
        },
        // Overload:function()
        // Overload:function(predicate)
        Last: function (predicate)
        {
            if (predicate != null) return this.Where(predicate).Last();
            var value;
            var found = false;
            this.ForEach(function (x)
            {
                found = true;
                value = x;
            });
            if (!found) throw new Error("Last:No element satisfies the condition.");
            return value;
        },
        // Overload:function(defaultValue)
        // Overload:function(defaultValue,predicate)
        LastOrDefault: function (defaultValue, predicate)
        {
            if (predicate != null) return this.Where(predicate).LastOrDefault(defaultValue);
            var value;
            var found = false;
            this.ForEach(function (x)
            {
                found = true;
                value = x;
            });
            return (!found) ? defaultValue : value;
        },
        // Overload:function()
        // Overload:function(predicate)
        Single: function (predicate)
        {
            if (predicate != null) return this.Where(predicate).Single();
            var value;
            var found = false;
            this.ForEach(function (x)
            {
                if (!found)
                {
                    found = true;
                    value = x;
                }
                else throw new Error("Single:sequence contains more than one element.");
            });
            if (!found) throw new Error("Single:No element satisfies the condition.");
            return value;
        },
        // Overload:function(defaultValue)
        // Overload:function(defaultValue,predicate)
        SingleOrDefault: function (defaultValue, predicate)
        {
            if (predicate != null) return this.Where(predicate).SingleOrDefault(defaultValue);
            var value;
            var found = false;
            this.ForEach(function (x)
            {
                if (!found)
                {
                    found = true;
                    value = x;
                }
                else throw new Error("Single:sequence contains more than one element.");
            });
            return (!found) ? defaultValue : value;
        },
        Skip: function (count)
        {
            var source = this;
            return new Enumerable(function ()
            {
                var enumerator;
                var index = 0;
                return new IEnumerator(
                    function ()
                    {
                        enumerator = source.GetEnumerator();
                        while (index++ < count && enumerator.MoveNext()) { };
                    },
                    function ()
                    {
                        return (enumerator.MoveNext())
                            ? this.Yield(enumerator.Current())
                            : false;
                    },
                    function () { Utils.Dispose(enumerator); })
            });
        },
        // Overload:function(predicate)
        // Overload:function(predicate)
        SkipWhile: function (predicate)
        {
            predicate = Utils.CreateLambda(predicate);
            var source = this;
            return new Enumerable(function ()
            {
                var enumerator;
                var index = 0;
                var isSkipEnd = false;
                return new IEnumerator(
                    function () { enumerator = source.GetEnumerator(); },
                    function ()
                    {
                        while (!isSkipEnd)
                        {
                            if (enumerator.MoveNext())
                            {
                                if (!predicate(enumerator.Current(), index++))
                                {
                                    isSkipEnd = true;
                                    return this.Yield(enumerator.Current());
                                }
                                continue;
                            }
                            else return false;
                        }
                        return (enumerator.MoveNext())
                            ? this.Yield(enumerator.Current())
                            : false;
                    },
                    function () { Utils.Dispose(enumerator); });
            });
        },
        Take: function (count)
        {
            var source = this;
            return new Enumerable(function ()
            {
                var enumerator;
                var index = 0;
                return new IEnumerator(
                    function () { enumerator = source.GetEnumerator(); },
                    function ()
                    {
                        return (index++ < count && enumerator.MoveNext())
                            ? this.Yield(enumerator.Current())
                            : false;
                    },
                    function () { Utils.Dispose(enumerator); }
                )
            });
        },
        // Overload:function(predicate)
        // Overload:function(predicate)
        TakeWhile: function (predicate)
        {
            predicate = Utils.CreateLambda(predicate);
            var source = this;
            return new Enumerable(function ()
            {
                var enumerator;
                var index = 0;
                return new IEnumerator(
                    function () { enumerator = source.GetEnumerator(); },
                    function ()
                    {
                        return (enumerator.MoveNext() && predicate(enumerator.Current(), index++))
                            ? this.Yield(enumerator.Current())
                            : false;
                    },
                    function () { Utils.Dispose(enumerator); });
            });
        },
        // Overload:function()
        // Overload:function(count)
        TakeExceptLast: function (count)
        {
            if (count == null) count = 1;
            var source = this;
            return new Enumerable(function ()
            {
                if (count <= 0) return source.GetEnumerator(); // do nothing
                var enumerator;
                var q = [];
                return new IEnumerator(
                    function () { enumerator = source.GetEnumerator(); },
                    function ()
                    {
                        while (enumerator.MoveNext())
                        {
                            if (q.length == count)
                            {
                                q.push(enumerator.Current());
                                return this.Yield(q.shift());
                            }
                            q.push(enumerator.Current());
                        }
                        return false;
                    },
                    function () { Utils.Dispose(enumerator); });
            });
        },
        TakeFromLast: function (count)
        {
            if (count <= 0 || count == null) return Enumerable.Empty();
            var source = this;
            return new Enumerable(function ()
            {
                var sourceEnumerator;
                var enumerator;
                var q = [];
                return new IEnumerator(
                    function () { sourceEnumerator = source.GetEnumerator(); },
                    function ()
                    {
                        while (sourceEnumerator.MoveNext())
                        {
                            if (q.length == count) q.shift()
                            q.push(sourceEnumerator.Current());
                        }
                        if (enumerator == null)
                        {
                            enumerator = Enumerable.From(q).GetEnumerator();
                        }
                        return (enumerator.MoveNext())
                            ? this.Yield(enumerator.Current())
                            : false;
                    },
                    function () { Utils.Dispose(enumerator); });
            });
        },
        IndexOf: function (item)
        {
            var found = null;
            this.ForEach(function (x, i)
            {
                if (x === item)
                {
                    found = i;
                    return true;
                }
            });
            return (found !== null) ? found : -1;
        },
        LastIndexOf: function (item)
        {
            var result = -1;
            this.ForEach(function (x, i)
            {
                if (x === item) result = i;
            });
            return result;
        },
        /* Convert Methods */
        ToArray: function ()
        {
            var array = [];
            this.ForEach(function (x) { array.push(x) });
            return array;
        },
        // Overload:function(keySelector)
        // Overload:function(keySelector, elementSelector)
        // Overload:function(keySelector, elementSelector, compareSelector)
        ToLookup: function (keySelector, elementSelector, compareSelector)
        {
            keySelector = Utils.CreateLambda(keySelector);
            elementSelector = Utils.CreateLambda(elementSelector);
            compareSelector = Utils.CreateLambda(compareSelector);
            var dict = new Dictionary(compareSelector);
            this.ForEach(function (x)
            {
                var key = keySelector(x);
                var element = elementSelector(x);
                var array = dict.Get(key);
                if (array !== undefined) array.push(element);
                else dict.Add(key, [element]);
            });
            return new Lookup(dict);
        },
        ToObject: function (keySelector, elementSelector)
        {
            keySelector = Utils.CreateLambda(keySelector);
            elementSelector = Utils.CreateLambda(elementSelector);
            var obj = {};
            this.ForEach(function (x)
            {
                obj[keySelector(x)] = elementSelector(x);
            });
            return obj;
        },
        // Overload:function(keySelector, elementSelector)
        // Overload:function(keySelector, elementSelector, compareSelector)
        ToDictionary: function (keySelector, elementSelector, compareSelector)
        {
            keySelector = Utils.CreateLambda(keySelector);
            elementSelector = Utils.CreateLambda(elementSelector);
            compareSelector = Utils.CreateLambda(compareSelector);
            var dict = new Dictionary(compareSelector);
            this.ForEach(function (x)
            {
                dict.Add(keySelector(x), elementSelector(x));
            });
            return dict;
        },
        // Overload:function()
        // Overload:function(replacer)
        // Overload:function(replacer, space)
        ToJSON: function (replacer, space)
        {
            return JSON.stringify(this.ToArray(), replacer, space);
        },
        // Overload:function()
        // Overload:function(separator)
        // Overload:function(separator,selector)
        ToString: function (separator, selector)
        {
            if (separator == null) separator = "";
            if (selector == null) selector = Functions.Identity;
            return this.Select(selector).ToArray().join(separator);
        },
        /* Action Methods */
        // Overload:function(action)
        // Overload:function(action)
        Do: function (action)
        {
            var source = this;
            action = Utils.CreateLambda(action);
            return new Enumerable(function ()
            {
                var enumerator;
                var index = 0;
                return new IEnumerator(
                    function () { enumerator = source.GetEnumerator(); },
                    function ()
                    {
                        if (enumerator.MoveNext())
                        {
                            action(enumerator.Current(), index++);
                            return this.Yield(enumerator.Current());
                        }
                        return false;
                    },
                    function () { Utils.Dispose(enumerator); });
            });
        },
        // Overload:function(action)
        // Overload:function(action)
        // Overload:function(func)
        // Overload:function(func)
        ForEach: function (action)
        {
            action = Utils.CreateLambda(action);
            var index = 0;
            var enumerator = this.GetEnumerator();
            try
            {
                while (enumerator.MoveNext())
                {
                    if (action(enumerator.Current(), index++) === false) break;
                }
            }
            finally { Utils.Dispose(enumerator); }
        },
        // Overload:function()
        // Overload:function(separator)
        // Overload:function(separator,selector)
        Write: function (separator, selector)
        {
            if (separator == null) separator = "";
            selector = Utils.CreateLambda(selector);
            var isFirst = true;
            this.ForEach(function (item)
            {
                if (isFirst) isFirst = false;
                else document.write(separator);
                document.write(selector(item));
            });
        },
        // Overload:function()
        // Overload:function(selector)
        WriteLine: function (selector)
        {
            selector = Utils.CreateLambda(selector);
            this.ForEach(function (item)
            {
                document.write(selector(item));
                document.write("
");
            });
        },
        Force: function ()
        {
            var enumerator = this.GetEnumerator();
            try { while (enumerator.MoveNext()) { } }
            finally { Utils.Dispose(enumerator); }
        },
        /* Functional Methods */
        Let: function (func)
        {
            func = Utils.CreateLambda(func);
            var source = this;
            return new Enumerable(function ()
            {
                var enumerator;
                return new IEnumerator(
                    function ()
                    {
                        enumerator = Enumerable.From(func(source)).GetEnumerator();
                    },
                    function ()
                    {
                        return (enumerator.MoveNext())
                            ? this.Yield(enumerator.Current())
                            : false;
                    },
                    function () { Utils.Dispose(enumerator); })
            });
        },
        Share: function ()
        {
            var source = this;
            var sharedEnumerator;
            return new Enumerable(function ()
            {
                return new IEnumerator(
                    function ()
                    {
                        if (sharedEnumerator == null)
                        {
                            sharedEnumerator = source.GetEnumerator();
                        }
                    },
                    function ()
                    {
                        return (sharedEnumerator.MoveNext())
                            ? this.Yield(sharedEnumerator.Current())
                            : false;
                    },
                    Functions.Blank
                )
            });
        },
        MemoizeAll: function ()
        {
            var source = this;
            var cache;
            var enumerator;
            return new Enumerable(function ()
            {
                var index = -1;
                return new IEnumerator(
                    function ()
                    {
                        if (enumerator == null)
                        {
                            enumerator = source.GetEnumerator();
                            cache = [];
                        }
                    },
                    function ()
                    {
                        index++;
                        if (cache.length <= index)
                        {
                            return (enumerator.MoveNext())
                                ? this.Yield(cache[index] = enumerator.Current())
                                : false;
                        }
                        return this.Yield(cache[index]);
                    },
                    Functions.Blank
                )
            });
        },
        /* Error Handling Methods */
        Catch: function (handler)
        {
            handler = Utils.CreateLambda(handler);
            var source = this;
            return new Enumerable(function ()
            {
                var enumerator;
                return new IEnumerator(
                    function () { enumerator = source.GetEnumerator(); },
                    function ()
                    {
                        try
                        {
                            return (enumerator.MoveNext())
                               ? this.Yield(enumerator.Current())
                               : false;
                        }
                        catch (e)
                        {
                            handler(e);
                            return false;
                        }
                    },
                    function () { Utils.Dispose(enumerator); });
            });
        },
        Finally: function (finallyAction)
        {
            finallyAction = Utils.CreateLambda(finallyAction);
            var source = this;
            return new Enumerable(function ()
            {
                var enumerator;
                return new IEnumerator(
                    function () { enumerator = source.GetEnumerator(); },
                    function ()
                    {
                        return (enumerator.MoveNext())
                           ? this.Yield(enumerator.Current())
                           : false;
                    },
                    function ()
                    {
                        try { Utils.Dispose(enumerator); }
                        finally { finallyAction(); }
                    });
            });
        },
        /* For Debug Methods */
        // Overload:function()
        // Overload:function(message)
        // Overload:function(message,selector)
        Trace: function (message, selector)
        {
            if (message == null) message = "Trace";
            selector = Utils.CreateLambda(selector);
            return this.Do(function (item)
            {
                console.log(message, ":", selector(item));
            });
        }
    }
    // private
    // static functions
    var Functions =
    {
        Identity: function (x) { return x; },
        True: function () { return true; },
        Blank: function () { }
    }
    // static const
    var Types =
    {
        Boolean: typeof true,
        Number: typeof 0,
        String: typeof "",
        Object: typeof {},
        Undefined: typeof undefined,
        Function: typeof function () { }
    }
    // static utility methods
    var Utils =
    {
        // Create anonymous function from lambda expression string
        CreateLambda: function (expression)
        {
            if (expression == null) return Functions.Identity;
            if (typeof expression == Types.String)
            {
                if (expression == "")
                {
                    return Functions.Identity;
                }
                else if (expression.indexOf("=>") == -1)
                {
                    return new Function("$,$$,$$$,$$$$", "return " + expression);
                }
                else
                {
                    var expr = expression.match(/^[(\s]*([^()]*?)[)\s]*=>(.*)/);
                    return new Function(expr[1], "return " + expr[2]);
                }
            }
            return expression;
        },
        IsIEnumerable: function (obj)
        {
            if (typeof Enumerator != Types.Undefined)
            {
                try
                {
                    new Enumerator(obj);
                    return true;
                }
                catch (e) { }
            }
            return false;
        },
        Compare: function (a, b)
        {
            return (a === b) ? 0
                : (a > b) ? 1
                : -1;
        },
        Dispose: function (obj)
        {
            if (obj != null) obj.Dispose();
        }
    }
    // IEnumerator State
    var State = { Before: 0, Running: 1, After: 2 }
    // name "Enumerator" is conflict JScript's "Enumerator"
    var IEnumerator = function (initialize, tryGetNext, dispose)
    {
        var yielder = new Yielder();
        var state = State.Before;
        this.Current = yielder.Current;
        this.MoveNext = function ()
        {
            try
            {
                switch (state)
                {
                    case State.Before:
                        state = State.Running;
                        initialize(); // fall through
                    case State.Running:
                        if (tryGetNext.apply(yielder))
                        {
                            return true;
                        }
                        else
                        {
                            this.Dispose();
                            return false;
                        }
                    case State.After:
                        return false;
                }
            }
            catch (e)
            {
                this.Dispose();
                throw e;
            }
        }
        this.Dispose = function ()
        {
            if (state != State.Running) return;
            try { dispose(); }
            finally { state = State.After; }
        }
    }
    // for tryGetNext
    var Yielder = function ()
    {
        var current = null;
        this.Current = function () { return current; }
        this.Yield = function (value)
        {
            current = value;
            return true;
        }
    }
    // for OrderBy/ThenBy
    var OrderedEnumerable = function (source, keySelector, descending, parent)
    {
        this.source = source;
        this.keySelector = Utils.CreateLambda(keySelector);
        this.descending = descending;
        this.parent = parent;
    }
    OrderedEnumerable.prototype = new Enumerable();
    OrderedEnumerable.prototype.CreateOrderedEnumerable = function (keySelector, descending)
    {
        return new OrderedEnumerable(this.source, keySelector, descending, this);
    }
    OrderedEnumerable.prototype.ThenBy = function (keySelector)
    {
        return this.CreateOrderedEnumerable(keySelector, false);
    }
    OrderedEnumerable.prototype.ThenByDescending = function (keySelector)
    {
        return this.CreateOrderedEnumerable(keySelector, true);
    }
    OrderedEnumerable.prototype.GetEnumerator = function ()
    {
        var self = this;
        var buffer;
        var indexes;
        var index = 0;
        return new IEnumerator(
            function ()
            {
                buffer = [];
                indexes = [];
                self.source.ForEach(function (item, index)
                {
                    buffer.push(item);
                    indexes.push(index);
                });
                var sortContext = SortContext.Create(self, null);
                sortContext.GenerateKeys(buffer);
                indexes.sort(function (a, b) { return sortContext.Compare(a, b); });
            },
            function ()
            {
                return (index < indexes.length)
                    ? this.Yield(buffer[indexes[index++]])
                    : false;
            },
            Functions.Blank
        )
    }
    var SortContext = function (keySelector, descending, child)
    {
        this.keySelector = keySelector;
        this.descending = descending;
        this.child = child;
        this.keys = null;
    }
    SortContext.Create = function (orderedEnumerable, currentContext)
    {
        var context = new SortContext(orderedEnumerable.keySelector, orderedEnumerable.descending, currentContext);
        if (orderedEnumerable.parent != null) return SortContext.Create(orderedEnumerable.parent, context);
        return context;
    }
    SortContext.prototype.GenerateKeys = function (source)
    {
        var len = source.length;
        var keySelector = this.keySelector;
        var keys = new Array(len);
        for (var i = 0; i < len; i++) keys[i] = keySelector(source[i]);
        this.keys = keys;
        if (this.child != null) this.child.GenerateKeys(source);
    }
    SortContext.prototype.Compare = function (index1, index2)
    {
        var comparison = Utils.Compare(this.keys[index1], this.keys[index2]);
        if (comparison == 0)
        {
            if (this.child != null) return this.child.Compare(index1, index2)
            comparison = Utils.Compare(index1, index2);
        }
        return (this.descending) ? -comparison : comparison;
    }
    // optimize array or arraylike object
    var ArrayEnumerable = function (source)
    {
        this.source = source;
    }
    ArrayEnumerable.prototype = new Enumerable();
    ArrayEnumerable.prototype.Any = function (predicate)
    {
        return (predicate == null)
            ? (this.source.length > 0)
            : Enumerable.prototype.Any.apply(this, arguments);
    }
    ArrayEnumerable.prototype.Count = function (predicate)
    {
        return (predicate == null)
            ? this.source.length
            : Enumerable.prototype.Count.apply(this, arguments);
    }
    ArrayEnumerable.prototype.ElementAt = function (index)
    {
        return (0 <= index && index < this.source.length)
            ? this.source[index]
            : Enumerable.prototype.ElementAt.apply(this, arguments);
    }
    ArrayEnumerable.prototype.ElementAtOrDefault = function (index, defaultValue)
    {
        return (0 <= index && index < this.source.length)
            ? this.source[index]
            : defaultValue;
    }
    ArrayEnumerable.prototype.First = function (predicate)
    {
        return (predicate == null && this.source.length > 0)
            ? this.source[0]
            : Enumerable.prototype.First.apply(this, arguments);
    }
    ArrayEnumerable.prototype.FirstOrDefault = function (defaultValue, predicate)
    {
        if (predicate != null)
        {
            return Enumerable.prototype.FirstOrDefault.apply(this, arguments);
        }
        return this.source.length > 0 ? this.source[0] : defaultValue;
    }
    ArrayEnumerable.prototype.Last = function (predicate)
    {
        return (predicate == null && this.source.length > 0)
            ? this.source[this.source.length - 1]
            : Enumerable.prototype.Last.apply(this, arguments);
    }
    ArrayEnumerable.prototype.LastOrDefault = function (defaultValue, predicate)
    {
        if (predicate != null)
        {
            return Enumerable.prototype.LastOrDefault.apply(this, arguments);
        }
        return this.source.length > 0 ? this.source[this.source.length - 1] : defaultValue;
    }
    ArrayEnumerable.prototype.Skip = function (count)
    {
        var source = this.source;
        return new Enumerable(function ()
        {
            var index;
            return new IEnumerator(
                function () { index = (count < 0) ? 0 : count },
                function ()
                {
                    return (index < source.length)
                        ? this.Yield(source[index++])
                        : false;
                },
                Functions.Blank);
        });
    };
    ArrayEnumerable.prototype.TakeExceptLast = function (count)
    {
        if (count == null) count = 1;
        return this.Take(this.source.length - count);
    }
    ArrayEnumerable.prototype.TakeFromLast = function (count)
    {
        return this.Skip(this.source.length - count);
    }
    ArrayEnumerable.prototype.Reverse = function ()
    {
        var source = this.source;
        return new Enumerable(function ()
        {
            var index;
            return new IEnumerator(
                function ()
                {
                    index = source.length;
                },
                function ()
                {
                    return (index > 0)
                        ? this.Yield(source[--index])
                        : false;
                },
                Functions.Blank)
        });
    }
    ArrayEnumerable.prototype.SequenceEqual = function (second, compareSelector)
    {
        if ((second instanceof ArrayEnumerable || second instanceof Array)
            && compareSelector == null
            && Enumerable.From(second).Count() != this.Count())
        {
            return false;
        }
        return Enumerable.prototype.SequenceEqual.apply(this, arguments);
    }
    ArrayEnumerable.prototype.ToString = function (separator, selector)
    {
        if (selector != null || !(this.source instanceof Array))
        {
            return Enumerable.prototype.ToString.apply(this, arguments);
        }
        if (separator == null) separator = "";
        return this.source.join(separator);
    }
    ArrayEnumerable.prototype.GetEnumerator = function ()
    {
        var source = this.source;
        var index = 0;
        return new IEnumerator(
            Functions.Blank,
            function ()
            {
                return (index < source.length)
                    ? this.Yield(source[index++])
                    : false;
            },
            Functions.Blank);
    }
    // Collections
    var Dictionary = (function ()
    {
        // static utility methods
        var HasOwnProperty = function (target, key)
        {
            return Object.prototype.hasOwnProperty.call(target, key);
        }
        var ComputeHashCode = function (obj)
        {
            if (obj === null) return "null";
            if (obj === undefined) return "undefined";
            return (typeof obj.toString === Types.Function)
                ? obj.toString()
                : Object.prototype.toString.call(obj);
        }
        // LinkedList for Dictionary
        var HashEntry = function (key, value)
        {
            this.Key = key;
            this.Value = value;
            this.Prev = null;
            this.Next = null;
        }
        var EntryList = function ()
        {
            this.First = null;
            this.Last = null;
        }
        EntryList.prototype =
        {
            AddLast: function (entry)
            {
                if (this.Last != null)
                {
                    this.Last.Next = entry;
                    entry.Prev = this.Last;
                    this.Last = entry;
                }
                else this.First = this.Last = entry;
            },
            Replace: function (entry, newEntry)
            {
                if (entry.Prev != null)
                {
                    entry.Prev.Next = newEntry;
                    newEntry.Prev = entry.Prev;
                }
                else this.First = newEntry;
                if (entry.Next != null)
                {
                    entry.Next.Prev = newEntry;
                    newEntry.Next = entry.Next;
                }
                else this.Last = newEntry;
            },
            Remove: function (entry)
            {
                if (entry.Prev != null) entry.Prev.Next = entry.Next;
                else this.First = entry.Next;
                if (entry.Next != null) entry.Next.Prev = entry.Prev;
                else this.Last = entry.Prev;
            }
        }
        // Overload:function()
        // Overload:function(compareSelector)
        var Dictionary = function (compareSelector)
        {
            this.count = 0;
            this.entryList = new EntryList();
            this.buckets = {}; // as Dictionary>
            this.compareSelector = (compareSelector == null) ? Functions.Identity : compareSelector;
        }
        Dictionary.prototype =
        {
            Add: function (key, value)
            {
                var compareKey = this.compareSelector(key);
                var hash = ComputeHashCode(compareKey);
                var entry = new HashEntry(key, value);
                if (HasOwnProperty(this.buckets, hash))
                {
                    var array = this.buckets[hash];
                    for (var i = 0; i < array.length; i++)
                    {
                        if (this.compareSelector(array[i].Key) === compareKey)
                        {
                            this.entryList.Replace(array[i], entry);
                            array[i] = entry;
                            return;
                        }
                    }
                    array.push(entry);
                }
                else
                {
                    this.buckets[hash] = [entry];
                }
                this.count++;
                this.entryList.AddLast(entry);
            },
            Get: function (key)
            {
                var compareKey = this.compareSelector(key);
                var hash = ComputeHashCode(compareKey);
                if (!HasOwnProperty(this.buckets, hash)) return undefined;
                var array = this.buckets[hash];
                for (var i = 0; i < array.length; i++)
                {
                    var entry = array[i];
                    if (this.compareSelector(entry.Key) === compareKey) return entry.Value;
                }
                return undefined;
            },
            Set: function (key, value)
            {
                var compareKey = this.compareSelector(key);
                var hash = ComputeHashCode(compareKey);
                if (HasOwnProperty(this.buckets, hash))
                {
                    var array = this.buckets[hash];
                    for (var i = 0; i < array.length; i++)
                    {
                        if (this.compareSelector(array[i].Key) === compareKey)
                        {
                            var newEntry = new HashEntry(key, value);
                            this.entryList.Replace(array[i], newEntry);
                            array[i] = newEntry;
                            return true;
                        }
                    }
                }
                return false;
            },
            Contains: function (key)
            {
                var compareKey = this.compareSelector(key);
                var hash = ComputeHashCode(compareKey);
                if (!HasOwnProperty(this.buckets, hash)) return false;
                var array = this.buckets[hash];
                for (var i = 0; i < array.length; i++)
                {
                    if (this.compareSelector(array[i].Key) === compareKey) return true;
                }
                return false;
            },
            Clear: function ()
            {
                this.count = 0;
                this.buckets = {};
                this.entryList = new EntryList();
            },
            Remove: function (key)
            {
                var compareKey = this.compareSelector(key);
                var hash = ComputeHashCode(compareKey);
                if (!HasOwnProperty(this.buckets, hash)) return;
                var array = this.buckets[hash];
                for (var i = 0; i < array.length; i++)
                {
                    if (this.compareSelector(array[i].Key) === compareKey)
                    {
                        this.entryList.Remove(array[i]);
                        array.splice(i, 1);
                        if (array.length == 0) delete this.buckets[hash];
                        this.count--;
                        return;
                    }
                }
            },
            Count: function ()
            {
                return this.count;
            },
            ToEnumerable: function ()
            {
                var self = this;
                return new Enumerable(function ()
                {
                    var currentEntry;
                    return new IEnumerator(
                        function () { currentEntry = self.entryList.First },
                        function ()
                        {
                            if (currentEntry != null)
                            {
                                var result = { Key: currentEntry.Key, Value: currentEntry.Value };
                                currentEntry = currentEntry.Next;
                                return this.Yield(result);
                            }
                            return false;
                        },
                        Functions.Blank);
                });
            }
        }
        return Dictionary;
    })();
    // dictionary = Dictionary
    var Lookup = function (dictionary)
    {
        this.Count = function ()
        {
            return dictionary.Count();
        }
        this.Get = function (key)
        {
            return Enumerable.From(dictionary.Get(key));
        }
        this.Contains = function (key)
        {
            return dictionary.Contains(key);
        }
        this.ToEnumerable = function ()
        {
            return dictionary.ToEnumerable().Select(function (kvp)
            {
                return new Grouping(kvp.Key, kvp.Value);
            });
        }
    }
    var Grouping = function (key, elements)
    {
        this.Key = function ()
        {
            return key;
        }
        ArrayEnumerable.call(this, elements);
    }
    Grouping.prototype = new ArrayEnumerable();
    // out to global
    return Enumerable;
})()