function TNR4EventTableControls(eventTableID, cacheObj) {
  this.InnerDocElementID = eventTableID;
  this.InnerCacheObj = cacheObj;

  this.EventSortOrderASC = true;
  this.LocationSortOrderASC = true;
  this.VenueSortOrderASC = true;
  this.DateSortOrderASC = false;

  this.MaxNumOfEvents = 500;

  this.FilterGroups = new Array();
  this.FilterApplicationOrder = new TNR4FilterApplyOrderCache();

  this.BusySorting = false;

  this.SortEventTable = function(sortType) {

    switch (sortType) {
      case 'event':
        if (this.EventSortOrderASC) {
          this.InnerCacheObj.Sort(SortByEventName);
          SetSortArrowUp(sortType);
        }
        else {
          this.InnerCacheObj.SortReverse(SortByEventName);
          SetSortArrowDown(sortType);
        }

        this.EventSortOrderASC = !this.EventSortOrderASC;
        this.LocationSortOrderASC = true;
        this.VenueSortOrderASC = true;
        this.DateSortOrderASC = true;
        break;
      case 'location':
        if (this.LocationSortOrderASC) {
          this.InnerCacheObj.Sort(SortByLocationName);
          SetSortArrowUp(sortType);
        }
        else {
          this.InnerCacheObj.SortReverse(SortByLocationName);
          SetSortArrowDown(sortType);
        }

        this.EventSortOrderASC = true;
        this.LocationSortOrderASC = !this.LocationSortOrderASC;
        this.VenueSortOrderASC = true;
        this.DateSortOrderASC = true;
        break;
      case 'venue':
        if (this.VenueSortOrderASC) {
          this.InnerCacheObj.Sort(SortByVenueName);
          SetSortArrowUp(sortType);
        }
        else {
          this.InnerCacheObj.SortReverse(SortByVenueName);
          SetSortArrowDown(sortType);
        }

        this.EventSortOrderASC = true;
        this.LocationSortOrderASC = true;
        this.VenueSortOrderASC = !this.VenueSortOrderASC;
        this.DateSortOrderASC = true;
        break;
      case 'date':
        if (this.DateSortOrderASC) {
          this.InnerCacheObj.Sort(SortByDateTime);
          SetSortArrowUp(sortType);
        }
        else {
          this.InnerCacheObj.SortReverse(SortByDateTime);
          SetSortArrowDown(sortType);
        }

        this.EventSortOrderASC = true;
        this.LocationSortOrderASC = true;
        this.VenueSortOrderASC = true;
        this.DateSortOrderASC = !this.DateSortOrderASC;
        break;
      default:
        break;
    }


    $('#' + this.InnerDocElementID).html(this.InnerCacheObj.RenderHtmlFromList(this.InnerCacheObj.LastDisplayedListState));
    $('#tn_evt_results_cover').addClass('noShow');
    $('#tn_evt_results_loading_div').addClass('noShow');

  };


  this.ReFilterClick = function(filGroupName, filName) {
    if (!this.BusySorting) {
      this.BusySorting = true;
      if (!$('#' + filName).hasClass('tn_emptyFilter')) {

        var filterGroupOnOff = this.ToggleFilterGroup(filGroupName, filName);

        if (this.FilterApplicationOrder.GetFilterGroupOrder(filGroupName) != -1) {
          this.FilterApplicationOrder.RemoveFilterGroup(filGroupName);
        }
        if (filterGroupOnOff) {
          this.FilterApplicationOrder.AddFilterGroup(filGroupName);
        }

        this.FilterEventTable();
      }
    }
    else {
      return false;
    }
  }

  this.FilterEventTable = function() {
    var filteredEvtList = this.InnerCacheObj.RawInner;
    
    //before beginning to filter, we need to make sure all filters are available (not disabled)
    //so the filter order can be applied correctly (otherwise it will cause issues when
    //unenabling filters
    for (var j = 0; j < this.FilterGroups.length; j++) {
      this.FilterGroups[j].MakeAllFiltersAvailable();
    }
    
    //now applied filters/disabling in the correct order
    if (this.FilterApplicationOrder.FilterListOrder.length > 0) {
      for (var i = 0; i < this.FilterApplicationOrder.FilterListOrder.length; i++) {
        var iterativeUnqVals = null;

        for (var j = 0; j < this.FilterGroups.length; j++) {
          if (this.FilterGroups[j].Name == this.FilterApplicationOrder.FilterListOrder[i] && this.FilterGroups[j].Enabled) {
            //filteredEvtList = this.FilterGroups[j].FilterEventObjs(filteredEvtList);

            var evtListAndUnqValsArr = this.FilterGroups[j].FilterEventObjsWithUniqueVals(filteredEvtList);
            filteredEvtList = evtListAndUnqValsArr[0];
            iterativeUnqVals = evtListAndUnqValsArr[1];

            break;
          }
        }

        //var iterativeUniqueVals = new TNR4UniqueFilterValues(filteredEvtList);
        //iterativeUniqueVals.InitializeValues();

        this.CheckFilterEnable(iterativeUnqVals, this.FilterApplicationOrder.FilterListOrder[i]);
      }
    }
    else {
      var overallUniqueVals = new TNR4UniqueFilterValues(filteredEvtList);
      overallUniqueVals.InitializeValues();

      this.CheckFilterEnable(overallUniqueVals, '');
    }

    $('#' + this.InnerDocElementID).html(this.InnerCacheObj.RenderHtmlFromList(filteredEvtList));
    $('#tn_evt_results_cover').addClass('noShow');
    $('#tn_evt_results_loading_div').addClass('noShow');
    this.BusySorting = false;

    return filteredEvtList;
  }

  this.ToggleFilterGroup = function(inFilGroupName, inFilName) {
  for (var i = 0; i < this.FilterGroups.length; i++) {
    if (this.FilterGroups[i].Name == inFilGroupName) {
        return this.FilterGroups[i].ToggleFilter(inFilName);
      }
    }
  }

  this.DisableFilterGroup = function(inFilGroupName) {
    if (!this.BusySorting) {
      this.BusySorting = true;

      for (var i = 0; i < this.FilterGroups.length; i++) {
        if (this.FilterGroups[i].Name == inFilGroupName && this.FilterGroups[i].Enabled) {
          if (this.FilterApplicationOrder.GetFilterGroupOrder(inFilGroupName) != -1) {
            this.FilterApplicationOrder.RemoveFilterGroup(inFilGroupName);
          }

          this.FilterGroups[i].DisableEverything();
          break;
        }
      }

      this.FilterEventTable();
    }
  }



  function SetSortArrowUp(sortType) {
    RemoveSortArrows();
    $('#' + sortType + '-sort').addClass('sort-up');
  }

  function SetSortArrowDown(sortType) {
    RemoveSortArrows();
    $('#' + sortType + '-sort').addClass('sort-down');
  }

  function RemoveSortArrows() {
    $('#event-sort').removeClass('sort-up');
    $('#event-sort').removeClass('sort-down');
    $('#location-sort').removeClass('sort-up');
    $('#location-sort').removeClass('sort-down');
    $('#venue-sort').removeClass('sort-up');
    $('#venue-sort').removeClass('sort-down');
    $('#date-sort').removeClass('sort-up');
    $('#date-sort').removeClass('sort-down');
  }

  this.MakeHeaderFiltersHtml = function() {
    var retSB = new StringBuilder();
    var evalEvtHandlersStr = '';
    var startDateRange;
    var lastEventDate;
    var endDateRange;

    var queryStartValue = GetQueryStringValue("startDate");
    var queryEndValue = GetQueryStringValue("endDate");

    //Check if startDate is in the query string
    if (queryStartValue && checkDate(queryStartValue)) {
      //set it to the query string date in the url
      startDateRange = new Date(queryStartValue);
    }
    else {
      //if it isn't set the start date to the first event date in the grid
      startDateRange = this.InnerCacheObj.RawInner[0].event_datetime.TN_AddDays(0);
    }


    lastEventDate = this.InnerCacheObj.RawInner[this.InnerCacheObj.RawInner.length - 1].event_datetime.TN_AddDays(0);
    //Check if endDate is in the query string
    if (queryEndValue && checkDate(queryEndValue)) {
      endDateRange = new Date(queryEndValue);
    }
    else {
      //if no query string in url just set the end date to the last displayed date in the grid
      endDateRange = lastEventDate;
    }

    retSB.append('<div class="tn_evt_date_filter">');
    retSB.append('<span style="font-weight: bold;">Search By Date:</span><br />');
    retSB.append('<div class="floLeft">');
    retSB.append('From: ');
    retSB.append('<input class="evt_fil_datepicker" type="text" id="tn_evt_filter_date_begin" value="' + startDateRange.TN_ToDateString() + '" />');
    retSB.append('<img class="datepicker_calendar" src="http://content.ticketnetwork.com/img/structure/phase1/calendar.gif" onclick="OpenStartDate()" />');
    retSB.append('&nbsp;&nbsp;');
    retSB.append('To: ');
    retSB.append('<input class="evt_fil_datepicker" type="text" id="tn_evt_filter_date_end" value="' + endDateRange.TN_ToDateString() + '" onclick="AutoSetEndDate()" />');
    retSB.append('<img class="datepicker_calendar" src="http://content.ticketnetwork.com/img/structure/phase1/calendar.gif" onclick="AutoSetEndDate()" />');
    retSB.append('</div>');
    retSB.append('<div id="tn_evt_date_button" title="Search"></div> ');
    retSB.append('</div>'); //end tn_evt_date_filter

    retSB.append('<div id="tn_evt_start_error" class="tn_evt_error_label" style="display: none;">You must select a start date to filter the grid by date.</div>');

    retSB.append('<sc' + 'ript type="text/javascript">');
    //retSB.append('$.datepicker.setDefaults({showOn: "both", buttonImageOnly: true, buttonImage: "http://content.ticketnetwork.com/img/structure/phase1/calendar.gif" });');
    retSB.append('$("#tn_evt_filter_date_begin").datepicker({ minDate: 0 });');
    retSB.append('$("#tn_evt_filter_date_end").datepicker({ minDate:  new Date($("#tn_evt_filter_date_begin").attr("value")) });');
    retSB.append('</sc' + 'ript>');

    evalEvtHandlersStr += "$('#tn_evt_filter_date_begin').datepicker('option', 'onSelect', function(theDate) { $(this).datepicker('hide', 'fast'); $('#tn_evt_filter_date_end').datepicker('option', 'minDate', new Date(theDate)); $('#tn_evt_error_label').hide(); });\n";
    //evalEvtHandlersStr += "$('#tn_evt_filter_date_end').datepicker('option', 'onSelect', function(theDate) { $(this).datepicker('hide', 'fast'); $('#tn_evt_filter_date_begin').datepicker('option', 'maxDate', new Date(theDate)); });\n";

    retSB.append('<sc' + 'ript type="text/javascript">' + evalEvtHandlersStr + '</sc' + 'ript>');

    return retSB.toString();

  }






  this.MakeFiltersHtml = function() {
    var uniqueFilVals = new TNR4UniqueFilterValues(this.InnerCacheObj.RawInner);
    uniqueFilVals.InitializeValues();

    var containsDateOnWeekdayArr = uniqueFilVals.DayOfWeekValues;

    var retSB = new StringBuilder();

    var evalEvtHandlersStr = '';

    retSB.append('<h1>Filter Tickets</h1><br /><u><a class="visible_link" href="javascript:location.reload(true)">Reset All Filters</a></u>');


    //build home/away filter - if its a sports performer page
    if (uniqueFilVals.AdvantageCount['home'] > 0 || uniqueFilVals.AdvantageCount['away'] > 0) {
      var advantageFilArr = new Array();
      var advantageFilGroupName = "homeAwayFilter"//TNGenerateRandomAlphaNumStrRememberPrior(10);

      if (uniqueFilVals.AdvantageCount['home'] > 0) {
        var homeAdvantageFilName = TNGenerateRandomAlphaNumStrRememberPrior(12);
        var homeAdvantageFilToAdd = new TNR4Filter(function(evtObj) { return evtObj.advantage == 'home'; }, function(uniqueValsObj) { return uniqueValsObj.AdvantageCount['home'] > 0; }, '<li><label id="' + homeAdvantageFilName + '" class="tn_filter_link" for="' + homeAdvantageFilName + 'i"><input id="' + homeAdvantageFilName + 'i" type="checkbox" />&nbsp;Home</label></li>', false, homeAdvantageFilName);
        advantageFilArr.push(homeAdvantageFilToAdd);

        evalEvtHandlersStr += "$('#" + homeAdvantageFilName + "i').change( function() { GridIsLoading(); setTimeout(\"document.TN_EventTable.ReFilterClick('" + advantageFilGroupName + "', '" + homeAdvantageFilName + "')\", 50); } );\n";
      }
      else {
        var emptyHomeAdvantageFilName = TNGenerateRandomAlphaNumStrRememberPrior(12);
        var emptyHomeAdvantageFilToAdd = new TNR4Filter(null, null, '<li><label class="tn_filter_link tn_emptyFilter"><input type="checkbox" disabled="disabled" />&nbsp;Home</label></li>', false, emptyHomeAdvantageFilName);
        advantageFilArr.push(emptyHomeAdvantageFilToAdd);
      }

      if (uniqueFilVals.AdvantageCount['away'] > 0) {
        var awayAdvantageFilName = TNGenerateRandomAlphaNumStrRememberPrior(12);
        var awayAdvantageFilToAdd = new TNR4Filter(function(evtObj) { return evtObj.advantage == 'away'; }, function(uniqueValsObj) { return uniqueValsObj.AdvantageCount['away'] > 0; }, '<li><label id="' + awayAdvantageFilName + '" class="tn_filter_link" for="' + awayAdvantageFilName + 'i"><input id="' + awayAdvantageFilName + 'i" type="checkbox" />&nbsp;Away</label></li>', false, awayAdvantageFilName);
        advantageFilArr.push(awayAdvantageFilToAdd);

        evalEvtHandlersStr += "$('#" + awayAdvantageFilName + "i').change( function() { GridIsLoading(); setTimeout(\"document.TN_EventTable.ReFilterClick('" + advantageFilGroupName + "', '" + awayAdvantageFilName + "')\", 50); } );\n";
      }
      else {
        var emptyAwayAdvantageFilName = TNGenerateRandomAlphaNumStrRememberPrior(12);
        var emptyAwayAdvantageFilToAdd = new TNR4Filter(null, null, '<li><label class="tn_filter_link tn_emptyFilter"><input type="checkbox" disabled="disabled" />&nbsp;Away</label></li>', false, emptyAwayAdvantageFilName);
        advantageFilArr.push(emptyAwayAdvantageFilToAdd);
      }

      var AdvAllBoxName = TNGenerateRandomAlphaNumStrRememberPrior(8);
      var advantageFilGroup = new TNR4FilterGroup(advantageFilArr, '<div id="tn_evt_fil_time_of_day_area" class="tn_evt_fil_collapsible_box"><h3 class="tn_evt_fil_box_toggle"><span class=\"dn-arrow\"></span> Refine by Home/Away </h3><ul class="tn_evt_fil_hideable_section"><li><label class="tn_filter_link"><input id="' + AdvAllBoxName + '" type="checkbox" checked="checked" />&nbsp;All</label></li>', '</ul></div>', false, advantageFilGroupName, false);

      evalEvtHandlersStr += "$('#" + AdvAllBoxName + "').click( function() { GridIsLoading(); setTimeout(\"document.TN_EventTable.DisableFilterGroup('" + advantageFilGroupName + "')\", 50); } );\n";

      advantageFilGroup.AllBoxName = AdvAllBoxName;

      this.FilterGroups.push(advantageFilGroup);
      retSB.append(advantageFilGroup.InnerText());
    }
    //end home/away filter

    //build category filter array
    var catFiltersArr = new Array();
    var catFilterGroupName = "CategoryGroupName"; //TNGenerateRandomAlphaNumStrRememberPrior(10);
    for (var i = 0; i < uniqueFilVals.CategoryValues.length; i++) {
      var curParCatName = ConvertIDToParentCatName(i + 1);

      if (uniqueFilVals.CategoryValues[i]) {

        var catFilName = "category" + (i + 1).toString(); //i+1 will give the actual ID of the category.
        var catFilterToAdd;
        eval('catFilterToAdd = new TNR4Filter( function(evtObj) { return evtObj.category_parent_id == ' + (i + 1) + '; }, function(uniqueValsObj) { return uniqueValsObj.CategoryValues[' + i + ']; }, \'<li><label id="' + catFilName + '" class="tn_filter_link" for="' + catFilName + 'i"><input id="' + catFilName + 'i" type="checkbox" />&nbsp;' + curParCatName + '</label></li>\', false, catFilName );');
        catFiltersArr.push(catFilterToAdd);

        evalEvtHandlersStr += "$('#" + catFilName + "i').change(function() {  GridIsLoading(); setTimeout(\"document.TN_EventTable.ReFilterClick('" + catFilterGroupName + "', '" + catFilName + "')\", 50); });\n";
      }
      else {
        var catEmptyFilName = TNGenerateRandomAlphaNumStrRememberPrior(12);
        var catEmptyFilterToAdd = new TNR4Filter(null, null, '<li><label class="tn_filter_link tn_emptyFilter"><input type="checkbox" disabled="disabled" />&nbsp;' + curParCatName + '</label></li>', false, catEmptyFilName);
        catFiltersArr.push(catEmptyFilterToAdd);
      }
    }
    var catFilGroupAllBoxName = TNGenerateRandomAlphaNumStrRememberPrior(8);
    var catFilGroup = new TNR4FilterGroup(catFiltersArr, '<div id="tn_evt_fil_evt_par_cat_area" class="tn_evt_fil_collapsible_box"><h3 class="tn_evt_fil_box_toggle"><span class=\"dn-arrow\"></span> Refine by Category</h3><ul class="tn_evt_fil_hideable_section"><li><label class="tn_filter_link"><input id="' + catFilGroupAllBoxName + '" type="checkbox" checked="checked" />&nbsp;All</label></li>', '</ul></div>', false, catFilterGroupName, false);

    evalEvtHandlersStr += "$('#" + catFilGroupAllBoxName + "').click( function() { GridIsLoading(); setTimeout(\"document.TN_EventTable.DisableFilterGroup('" + catFilterGroupName + "')\", 50);  } );\n";

    catFilGroup.AllBoxName = catFilGroupAllBoxName;

    this.FilterGroups.push(catFilGroup);
    retSB.append(catFilGroup.InnerText());

    //        //build date range filter
    //        var dateRangeFiltersArr = new Array();
    //        var dateRangeFilName = TNGenerateRandomAlphaNumStrRememberPrior(12);
    //        var dateRangeFilGroupName = TNGenerateRandomAlphaNumStrRememberPrior(10);
    //        var startDateRange = this.InnerCacheObj.RawInner[0].event_datetime.TN_AddDays(0);
    //        var endDateRange = this.InnerCacheObj.RawInner[ this.InnerCacheObj.RawInner.length - 1 ].event_datetime.TN_AddDays(0);
    //        //need to add 1 day to end date time so it will catch events on that day (date is 12:00am, so checking 'less than'
    //        //doesn't work)
    //        var dateRangeFilterToAdd = new TNR4Filter( function(evtObj) { return evtObj.event_datetime >= new Date($("#tn_evt_filter_date_begin").val()) && evtObj.event_datetime <= (new Date($("#tn_evt_filter_date_end").val())).TN_AddDays(1); }, null, '<input class="evt_fil_datepicker" type="text" id="tn_evt_filter_date_begin" value="' + startDateRange.TN_ToDateString() + '" />&nbsp;&nbsp;-&nbsp;&nbsp;<input class="evt_fil_datepicker" type="text" id="tn_evt_filter_date_end" value="' + endDateRange.TN_ToDateString() + '" />', true, dateRangeFilName);
    //        dateRangeFiltersArr.push(dateRangeFilterToAdd);
    //        var dateRangeFilterGroup = new TNR4FilterGroup(dateRangeFiltersArr, '<div id="tn_evt_fil_evt_date_area" class="tn_evt_fil_collapsible_box"><h3 class="tn_evt_fil_box_toggle"><span class=\"dn-arrow\"></span> Refine by Date</h3><div class="tn_evt_fil_hideable_section">', '<script type="text/javascript">$.datepicker.setDefaults({showOn: "both", buttonImageOnly: true, buttonImage: "http://content.ticketnetwork.com/img/structure/phase1/calendar.gif" });$("#tn_evt_filter_date_begin").datepicker({ minDate: new Date($("#tn_evt_filter_date_begin").attr("value")), maxDate: new Date($("#tn_evt_filter_date_end").attr("value")) }); $("#tn_evt_filter_date_end").datepicker({ maxDate: new Date($("#tn_evt_filter_date_end").attr("value")), minDate: new Date($("#tn_evt_filter_date_begin").attr("value")) });</script>', true, dateRangeFilGroupName, true);

    //        evalEvtHandlersStr += "$('#tn_evt_filter_date_begin').datepicker('option', 'onSelect', function(theDate) { GridIsLoading(); $(this).datepicker('hide', 'fast'); $(\"#tn_evt_filter_date_end\").datepicker(\"option\", \"minDate\", new Date(theDate)); setTimeout(\"document.TN_EventTable.FilterEventTable()\", 50); });\n";
    //        evalEvtHandlersStr += "$('#tn_evt_filter_date_end').datepicker('option', 'onSelect', function(theDate) { GridIsLoading(); $(this).datepicker('hide', 'fast'); $(\"#tn_evt_filter_date_begin\").datepicker(\"option\", \"maxDate\", new Date(theDate)); setTimeout(\"document.TN_EventTable.FilterEventTable()\", 50); });\n";
    //        /*evalEvtHandlersStr += "$('#tn_evt_filter_date_end').change( function() {GridIsLoading(); setTimeout(\"document.TN_EventTable.FilterEventTable()\", 50);});\n";
    //        evalEvtHandlersStr += "$('#tn_evt_filter_date_begin').change( function() {GridIsLoading(); setTimeout(\"document.TN_EventTable.FilterEventTable()\", 50);});\n";*/

    //        this.FilterApplicationOrder.AddFilterGroup(dateRangeFilGroupName);

    //        this.FilterGroups.push(dateRangeFilterGroup);
    //        retSB.append(dateRangeFilterGroup.InnerText());
    //end date range filter

    //var dateRangeFilGroupName = TNGenerateRandomAlphaNumStrRememberPrior(10);
    //var dateRangeFilterGroup = new TNR4FilterGroup(dateRangeFiltersArr, '<div id="tn_evt_fil_evt_date_area" class="tn_evt_fil_collapsible_box"><h3 class="tn_evt_fil_box_toggle"><span class=\"dn-arrow\"></span> Refine by Date</h3><div class="tn_evt_fil_hideable_section">', '', true, dateRangeFilGroupName, true);

    //build day of week filter
    var dayOfWeekFiltersArr = new Array();
    var dowFilGroupName = TNGenerateRandomAlphaNumStrRememberPrior(10);
    for (var k = 0; k < containsDateOnWeekdayArr.length; k++) {
      if (containsDateOnWeekdayArr[k]) {
        var dowFilName = TNGenerateRandomAlphaNumStrRememberPrior(12);
        var dowFilterToAdd;
        eval('dowFilterToAdd = new TNR4Filter( function(evtObj) { return evtObj.event_datetime.getUTCDay() == ' + k + '; }, function(uniqueValsObj) { return uniqueValsObj.DayOfWeekValues[' + k + ']; }, \'<li><label id="' + dowFilName + '" class="tn_filter_link" for="' + dowFilName + 'i"><input id="' + dowFilName + 'i" type="checkbox" />&nbsp;' + ConvertIntIndexToDayStr(k) + '</label></li>\', false, \'' + dowFilName + '\');');
        dayOfWeekFiltersArr.push(dowFilterToAdd);

        evalEvtHandlersStr += "$('#" + dowFilName + "i').change( function() {GridIsLoading(); setTimeout(\"document.TN_EventTable.ReFilterClick('" + dowFilGroupName + "', '" + dowFilName + "')\", 50);} );\n";
      }
      else {
        var dowEmptyFilName = TNGenerateRandomAlphaNumStrRememberPrior(12);
        var dowEmptyFilterToAdd = new TNR4Filter(null, null, '<li><label class="tn_filter_link tn_emptyFilter"><input type="checkbox" disabled="disabled" />&nbsp;' + ConvertIntIndexToDayStr(k) + '</label></li>', false, dowEmptyFilName);
        dayOfWeekFiltersArr.push(dowEmptyFilterToAdd);
      }
    }
    var dowAllBoxName = TNGenerateRandomAlphaNumStrRememberPrior(8);
    var dowFilterGroup = new TNR4FilterGroup(dayOfWeekFiltersArr, '<div id="tn_evt_fil_evt_date_area" class="tn_evt_fil_collapsible_box"><h3 class="tn_evt_fil_box_toggle"><span class=\"dn-arrow\"></span> Refine by Day Of Week</h3><div class="tn_evt_fil_hideable_section"><ul><li><label class="tn_filter_link"><input type="checkbox" id="' + dowAllBoxName + '" checked="checked" />&nbsp;All</label></li>', '</ul></div></div>', false, dowFilGroupName, false);

    evalEvtHandlersStr += "$('#" + dowAllBoxName + "').click( function() { GridIsLoading(); setTimeout(\"document.TN_EventTable.DisableFilterGroup('" + dowFilGroupName + "')\", 50); } );\n";

    dowFilterGroup.AllBoxName = dowAllBoxName;

    this.FilterGroups.push(dowFilterGroup);
    retSB.append(dowFilterGroup.InnerText());
    //end day of week filter


    //build time of day filter
    var timeOfDayFilArr = new Array();
    var timeOfDayFilGroupName = TNGenerateRandomAlphaNumStrRememberPrior(10);

    if (uniqueFilVals.TimeOfDayCount['daytime'] > 0) {
      var daytimeTODFilName = TNGenerateRandomAlphaNumStrRememberPrior(12);
      var daytimeTODFilToAdd = new TNR4Filter(function(evtObj) { return evtObj.event_datetime.getUTCHours() < 17; }, function(uniqueValsObj) { return uniqueValsObj.TimeOfDayCount['daytime'] > 0; }, '<li><label id="' + daytimeTODFilName + '" class="tn_filter_link" for="' + daytimeTODFilName + 'i"><input id="' + daytimeTODFilName + 'i" type="checkbox" />&nbsp;Daytime</label></li>', false, daytimeTODFilName);
      timeOfDayFilArr.push(daytimeTODFilToAdd);

      evalEvtHandlersStr += "$('#" + daytimeTODFilName + "i').change( function() { GridIsLoading(); setTimeout(\"document.TN_EventTable.ReFilterClick('" + timeOfDayFilGroupName + "', '" + daytimeTODFilName + "')\", 50); } );\n";
    }
    else {
      var emptyDaytimeTODFilName = TNGenerateRandomAlphaNumStrRememberPrior(12);
      var emptyDaytimeFilToAdd = new TNR4Filter(null, null, '<li><label class="tn_filter_link tn_emptyFilter"><input type="checkbox" disabled="disabled" />&nbsp;Daytime</label></li>', false, emptyDaytimeTODFilName);
      timeOfDayFilArr.push(emptyDaytimeFilToAdd);
    }

    if (uniqueFilVals.TimeOfDayCount['evening'] > 0) {
      var eveningTimeOfDayFilName = TNGenerateRandomAlphaNumStrRememberPrior(12);
      var eveningTODFilToAdd = new TNR4Filter(function(evtObj) { return evtObj.event_datetime.getUTCHours() >= 17; }, function(uniqueValsObj) { return uniqueValsObj.TimeOfDayCount['evening'] > 0; }, '<li><label id="' + eveningTimeOfDayFilName + '" class="tn_filter_link" for="' + eveningTimeOfDayFilName + 'i"><input id="' + eveningTimeOfDayFilName + 'i" type="checkbox" />&nbsp;Evening</label></li>', false, eveningTimeOfDayFilName);
      timeOfDayFilArr.push(eveningTODFilToAdd);

      evalEvtHandlersStr += "$('#" + eveningTimeOfDayFilName + "i').change( function() { GridIsLoading(); setTimeout(\"document.TN_EventTable.ReFilterClick('" + timeOfDayFilGroupName + "', '" + eveningTimeOfDayFilName + "')\", 50); } );\n";
    }
    else {
      var emptyEveningTODFilName = TNGenerateRandomAlphaNumStrRememberPrior(12);
      var emptyEveningFilToAdd = new TNR4Filter(null, null, '<li><label class="tn_filter_link tn_emptyFilter"><input type="checkbox" disabled="disabled" />&nbsp;Evening</label></li>', false, emptyEveningTODFilName);
      timeOfDayFilArr.push(emptyEveningFilToAdd);
    }

    var TODAllBoxName = TNGenerateRandomAlphaNumStrRememberPrior(8);
    var timeOfDayFilGroup = new TNR4FilterGroup(timeOfDayFilArr, '<div id="tn_evt_fil_time_of_day_area" class="tn_evt_fil_collapsible_box"><h3 class="tn_evt_fil_box_toggle"><span class=\"dn-arrow\"></span> Refine by Time of Day</h3><ul class="tn_evt_fil_hideable_section"><li><label class="tn_filter_link"><input id="' + TODAllBoxName + '" type="checkbox" checked="checked" />&nbsp;All</label></li>', '</ul></div>', false, timeOfDayFilGroupName, false);

    evalEvtHandlersStr += "$('#" + TODAllBoxName + "').click( function() { GridIsLoading(); setTimeout(\"document.TN_EventTable.DisableFilterGroup('" + timeOfDayFilGroupName + "')\", 50); } );\n";

    timeOfDayFilGroup.AllBoxName = TODAllBoxName;

    this.FilterGroups.push(timeOfDayFilGroup);
    retSB.append(timeOfDayFilGroup.InnerText());
    //end time of day filter


    //Build Location filter menu for sidebar
    var locNameFiltersArr = new Array();
    var locNameFilGroupName = 'LocationGroupName'; //TNGenerateRandomAlphaNumStrRememberPrior(10);
    for (var r = 0; r < uniqueFilVals.LocationValues.length; r++) {
      //LocationValues is a 2-D array; r, 0 = Location Values (New York, NY); r, 1 = LocationIDs ( 217-35-new_york ).
      var locNameFilName = uniqueFilVals.LocationValues[r][1].replace("'", "");; //TNGenerateRandomAlphaNumStrRememberPrior(12);
      var locValue = uniqueFilVals.LocationValues[r][0];
      var locNameFilterToAdd;
      eval('locNameFilterToAdd = new TNR4Filter( function(evtObj) { if(evtObj.country_id == 217) {return (evtObj.city + \', \' + evtObj.state)  == \'' + locValue.replace("'", "\\'") + '\'; } else { return (evtObj.city + \', \' + evtObj.country)  == \'' + locValue.replace("'", "\\'") + '\'; }}, function(uniqueValsObj) { return (uniqueValsObj.LocationCount[\'' + locValue.replace("'", "\\'") + '\'] != null && uniqueValsObj.LocationCount[\'' + locValue.replace("'", "\\'") + '\'] > 0); }, \'<li><label id="' + locNameFilName + '" class="tn_filter_link" for="' + locNameFilName + 'i"><input id="' + locNameFilName + 'i" type="checkbox" />&nbsp;' + locValue.replace("'", "\\'") + '</label></li>\', false, \'' + locNameFilName + '\');');
      locNameFiltersArr.push(locNameFilterToAdd);

      evalEvtHandlersStr += "$('#" + locNameFilName + "i').change( function() {GridIsLoading(); setTimeout(\"document.TN_EventTable.ReFilterClick('" + locNameFilGroupName + "', '" + locNameFilName + "')\", 50);} );\n";
    }
    var locNameAllBoxName = TNGenerateRandomAlphaNumStrRememberPrior(8);
    var locNameFilterGroup = new TNR4FilterGroup(locNameFiltersArr, '<div id="tn_evt_fil_loc_name_area" class="tn_evt_fil_collapsible_box"><h3 class="tn_evt_fil_box_toggle"><span class=\"dn-arrow\"></span> Refine by Location</h3><ul class="tn_evt_fil_hideable_section"><li><label class="tn_filter_link"><input id="' + locNameAllBoxName + '" type="checkbox" checked="checked" />&nbsp;All</label></li>', '</ul></div>', false, locNameFilGroupName, false);

    evalEvtHandlersStr += "$('#" + locNameAllBoxName + "').click( function() { GridIsLoading(); setTimeout(\"document.TN_EventTable.DisableFilterGroup('" + locNameFilGroupName + "')\", 50); } );\n";

    locNameFilterGroup.AllBoxName = locNameAllBoxName;

    this.FilterGroups.push(locNameFilterGroup);
    retSB.append(locNameFilterGroup.InnerText());

    //end location filter


    /*
    var venNameFiltersArr = new Array();
    var venNameFilGroupName = TNGenerateRandomAlphaNumStrRememberPrior(10);
    for(var l = 0; l < uniqueFilVals.VenueValues.length; l++)
    {
    var venNameFilName = TNGenerateRandomAlphaNumStrRememberPrior(12);
    var venNameFilterToAdd;
    eval( 'venNameFilterToAdd = new TNR4Filter( function(evtObj) { return evtObj.venue_name == \'' + uniqueFilVals.VenueValues[l] + '\'; }, function(uniqueValsObj) { return (uniqueValsObj.VenueCount[\'' + uniqueFilVals.VenueValues[l] + '\'] != null && uniqueValsObj.VenueCount[\'' + uniqueFilVals.VenueValues[l] + '\'] > 0); }, \'<li><label id="' + venNameFilName + '" class="tn_filter_link" for="' + venNameFilName + 'i"><input id="' + venNameFilName + 'i" type="checkbox" />&nbsp;' + uniqueFilVals.VenueValues[l] + '</label></li>\', false, \'' + venNameFilName + '\');' );
    venNameFiltersArr.push(venNameFilterToAdd);

    evalEvtHandlersStr += "$('#" + venNameFilName + "i').change( function() {document.TN_EventTable.ReFilterClick('" + venNameFilGroupName + "', '" + venNameFilName + "');} );\n";
    }
    var venNameAllBoxName = TNGenerateRandomAlphaNumStrRememberPrior(8);
    var venNameFilterGroup = new TNR4FilterGroup(venNameFiltersArr, '<div id="tn_evt_fil_ven_name_area" class="tn_evt_fil_collapsible_box"><h3 class="tn_evt_fil_box_toggle">- Refine by Venue</h3><ul class="tn_evt_fil_hideable_section"><li><label class="tn_filter_link"><input id="' + venNameAllBoxName + '" type="checkbox" checked="checked" />&nbsp;All</label></li>', '</ul></div>', false, venNameFilGroupName, false);

    evalEvtHandlersStr += "$('#" + venNameAllBoxName + "').click( function() { document.TN_EventTable.DisableFilterGroup('" + venNameFilGroupName + "'); } );\n";

    venNameFilterGroup.AllBoxName = venNameAllBoxName;

    this.FilterGroups.push(venNameFilterGroup);
    retSB.append(venNameFilterGroup.InnerText());*/

    evalEvtHandlersStr += '$(function () { if ($.browser.msie) { $("input:radio, input:checkbox").click(function () { this.blur(); this.focus(); }); } });';

    evalEvtHandlersStr += "$('.tn_evt_fil_collapsible_box .tn_evt_fil_box_toggle').click(function() { $(this).siblings('.tn_evt_fil_hideable_section').slideToggle('normal'); $(this).html(  (($(this).html().substring(0, 30) == '<span class=\"up-arrow\"></span>') ? '<span class=\"dn-arrow\"></span>' : '') + (($(this).html().substring(0, 30) == '<span class=\"dn-arrow\"></span>') ? '<span class=\"up-arrow\"></span>' : '') + (($(this).html().substring(0, 28) == '<SPAN class=up-arrow></SPAN>') ? '<span class=\"dn-arrow\"/>' : '') + (($(this).html().substring(0, 28) == '<SPAN class=dn-arrow></SPAN>') ? '<span class=\"up-arrow\"/>' : '') + $(this).html().substring($(this).html().indexOf('Refine')) ); }); SetSelectedCheckbox();";

    retSB.append('<sc' + 'ript type="text/javascript">' + evalEvtHandlersStr + '</sc' + 'ript>');

    return retSB.toString();
  };



  this.CheckFilterEnable = function(inUniquenessState, inFilGroupNameToIgnore) {
    var numFilterGroupsEnabled = 0;

    for (var j = 0; j < this.FilterGroups.length; j++) {
      if (this.FilterGroups[j].Enabled) {
        numFilterGroupsEnabled++;
      }

      if (!this.FilterGroups[j].AlwaysAvailable && (this.FilterGroups[j].Name != inFilGroupNameToIgnore || !this.FilterGroups[j].Enabled)) {
        this.FilterGroups[j].CheckFilterAvailability(inUniquenessState);
      }
    }

    //I don't understand why this is here.  It makes the filters unintuitive, and re-enables filter availabilty
    //at a random number (2), even though clicking on the newly enabled filters won't alter the list at all.
    //REMOVED
    /*if (numFilterGroupsEnabled == 2) {
      for (var k = 0; k < this.FilterGroups.length; k++) {
        if (this.FilterGroups[k].Enabled) {
          this.FilterGroups[k].MakeAllFiltersAvailable();
        }
      }
    }*/
  };
}






function TNR4FilterGroup(inFilList, groupPrepend, groupAppend, inEnable, inName, inAlwaysAvail) {
  this.FilterList = inFilList;
  this.HtmlGroupPrepend = groupPrepend;
  this.HtmlGroupAppend = groupAppend;
  this.Enabled = inEnable;
  this.Name = inName;
  this.AlwaysAvailable = inAlwaysAvail;
  this.AllBoxName = null;

  this.FilterEventObjs = function(evtObjArr) {
    var retList = new Array();

    for (var i = 0; i < evtObjArr.length; i++) {
      for (var j = 0; j < this.FilterList.length; j++) {
        if (this.FilterList[j].Enabled) {
          if (this.FilterList[j].FilFunc(evtObjArr[i])) {
            retList.push(evtObjArr[i]);
            break;
          }
        }
      }
    }

    return retList;
  };

  this.FilterEventObjsWithUniqueVals = function(evtObjArr) {
    var retEvtList = new Array();

    var unqLocVals = new Array();
    var unqLocCount = new Array();

    /*var unqVenVals = new Array();
    var unqVenCount = new Array();*/

    var unqDOWVals = [false, false, false, false, false, false, false];
    var unqDOWCount = [0, 0, 0, 0, 0, 0, 0];

    var unqCatVals = [false, false, false, false];
    var unqCatCount = [0, 0, 0, 0];

    var unqTimeOfDayCount = new Array();
    unqTimeOfDayCount['evening'] = 0;
    unqTimeOfDayCount['daytime'] = 0;

    var unqAdvantageCount = new Array();
    unqAdvantageCount['home'] = 0;
    unqAdvantageCount['away'] = 0;

    for (var i = 0; i < evtObjArr.length; i++) {
      for (var j = 0; j < this.FilterList.length; j++) {
        if (this.FilterList[j].Enabled) {
          if (this.FilterList[j].FilFunc(evtObjArr[i])) {
            retEvtList.push(evtObjArr[i]);

            var LocationName;

            if (evtObjArr[i].country_id == 217)  //The event takes place in the USA
            {
              LocationName = evtObjArr[i].city + ', ' + evtObjArr[i].state;
            }
            else {
              LocationName = evtObjArr[i].city + ', ' + evtObjArr[i].country;
            }

            if (unqLocCount[LocationName]) {
              unqLocCount[LocationName]++;
            }
            else {
              unqLocCount[LocationName] = 1;
              unqLocVals.push(LocationName);
            }
            /*
            if(unqVenCount[evtObjArr[i].venue_name])
            {
            unqVenCount[evtObjArr[i].venue_name]++;
            }
            else
            {
            unqVenCount[evtObjArr[i].venue_name] = 1;
            unqVenVals.push(evtObjArr[i].venue_name);
            }
            */

            if (!unqDOWVals[evtObjArr[i].event_datetime.getUTCDay()]) {
              unqDOWVals[evtObjArr[i].event_datetime.getUTCDay()] = true;
            }
            unqDOWCount[evtObjArr[i].event_datetime.getUTCDay()]++;

            if (!unqCatVals[evtObjArr[i].category_parent_id - 1]) {
              unqCatVals[evtObjArr[i].category_parent_id - 1] = true;
            }
            unqCatCount[evtObjArr[i].category_parent_id - 1]++;

            if (evtObjArr[i].event_datetime.getUTCHours() >= 17) {
              unqTimeOfDayCount['evening']++;
            }
            else {
              unqTimeOfDayCount['daytime']++;
            }

            if (evtObjArr[i].advantage == 'home') {
              unqAdvantageCount['home']++;
            }
            else if (evtObjArr[i].advantage == 'away') {
              unqAdvantageCount['away']++;
            }


            break;
          }
        }
      }
    }


    var retUniqueList = new TNR4UniqueFilterValues(retEvtList);
    retUniqueList.PopulateValues(unqLocVals, unqLocCount, unqDOWVals, unqDOWCount, unqCatVals, unqCatCount, unqTimeOfDayCount, unqAdvantageCount); //unqVenVals, unqVenCount,

    var retArr = new Array();
    retArr.push(retEvtList);
    retArr.push(retUniqueList);

    return retArr;
  }

  this.ToggleFilter = function(inFilName) {
    var numEnabled = 0;
    for (var i = 0; i < this.FilterList.length; i++) {
      if (this.FilterList[i].Name == inFilName) {
        this.FilterList[i].Enabled = !this.FilterList[i].Enabled;
      }
      if (this.FilterList[i].Enabled) {
        numEnabled++;
      }
    }

    //this makes 2-choice filters (home/away, day/eve) toggle
    if (this.FilterList.length == 2) {
      if (inFilName == this.FilterList[0].Name && this.FilterList[0].Enabled == true) {
        this.FilterList[1].Enabled = false;
        $('#' + this.FilterList[1].Name + 'i').attr('checked', false);
      }
      if (inFilName == this.FilterList[1].Name && this.FilterList[1].Enabled == true) {
        this.FilterList[0].Enabled = false;
        $('#' + this.FilterList[0].Name + 'i').attr('checked', false);
      }
    }
    //end toggle-code
    
    this.Enabled = (numEnabled > 0);

    $('#' + this.AllBoxName).attr('checked', !this.Enabled);

    return this.Enabled;
  };

  this.CheckFilterAvailability = function(inUniqueVals) {
    for (var i = 0; i < this.FilterList.length; i++) {
      if (this.FilterList[i].FilAvailCheck != null) {
        if (!this.FilterList[i].FilAvailCheck(inUniqueVals)) {
          if (!this.FilterList[i].Enabled) {
            this.FilterList[i].ToggleGreyOn();
          }
        }
        else {
          this.FilterList[i].ToggleGreyOff();
        }
      }
    }
  };

  this.MakeAllFiltersAvailable = function() {
    for (var i = 0; i < this.FilterList.length; i++) {
      if (this.FilterList[i].FilAvailCheck != null) {
        this.FilterList[i].ToggleGreyOff();
      }
    }
  }

  this.DisableEverything = function() {
    if (this.Enabled) {
      for (var i = 0; i < this.FilterList.length; i++) {
        if (this.FilterList[i].Enabled) {
          this.FilterList[i].Enabled = false;
          $('#' + this.FilterList[i].Name + 'i').attr('checked', false);
        }
      }

      this.Enabled = false;

      $('#' + this.AllBoxName).attr('checked', true);
    }
  }

  this.InnerText = function() {
    var retSB = new StringBuilder(this.HtmlGroupPrepend);

    for (var i = 0; i < inFilList.length; i++) {
      retSB.append(inFilList[i].InnerText);
    }

    retSB.append(this.HtmlGroupAppend);

    return retSB.toString();
  };
}

function TNR4Filter(inFilterFunc, inFilterAvailableFunc, inFilterText, inEnable, inName) {
  this.FilFunc = inFilterFunc;
  this.FilAvailCheck = inFilterAvailableFunc;
  this.InnerText = inFilterText;

  this.Enabled = inEnable;
  this.Name = inName;

  this.ToggleGreyOn = function() {
    if (!$('#' + this.Name).hasClass('tn_emptyFilter')) {
      $('#' + this.Name).addClass('tn_emptyFilter');
      $('#' + this.Name + 'i').attr('disabled', 'disabled');
    }
  };

  this.ToggleGreyOff = function() {
    if ($('#' + this.Name).hasClass('tn_emptyFilter')) {
      $('#' + this.Name).removeClass('tn_emptyFilter');
      $('#' + this.Name + 'i').removeAttr('disabled');
    }
  };
}




function TNR4UniqueFilterValues(rawEvtList) {
  this.RawList = rawEvtList;
  this.Initialized = false;

  this.LocationValues = null;
  this.LocationCount = null;

  /*this.VenueValues = null;
  this.VenueCount = null;    */

  this.DayOfWeekValues = null;
  this.DayOfWeekCount = null;

  this.CategoryValues = null;
  this.CategoryCount = null;

  this.TimeOfDayCount = null;

  this.AdvantageCount = null;

  this.InitializeValues = function() {
    this.LocationValues = new Array();
    this.LocationCount = new Array();

    /*this.VenueValues = new Array();
    this.VenueCount = new Array();*/

    this.DayOfWeekValues = [false, false, false, false, false, false, false];
    this.DayOfWeekCount = [0, 0, 0, 0, 0, 0, 0];

    this.CategoryValues = [false, false, false, false];
    this.CategoryCount = [0, 0, 0, 0];

    var priorLocationValsHash = new Array();
    /*var priorVenueValsHash = new Array();*/
    var priorDateValsHash = new Array();

    this.TimeOfDayCount = new Array();
    this.TimeOfDayCount['evening'] = 0;
    this.TimeOfDayCount['daytime'] = 0;

    this.AdvantageCount = new Array();
    this.AdvantageCount['home'] = 0;
    this.AdvantageCount['away'] = 0;

    if (this.RawList != null) {
      for (var i = 0; i < this.RawList.length; i++) {
        var LocationName; //Will hold either "City, State" or "City, Country"


        if (this.RawList[i].country_id == 217)  //The event takes place in the USA
        {
          LocationName = this.RawList[i].city + ', ' + this.RawList[i].state;
        }
        else {
          LocationName = this.RawList[i].city + ', ' + this.RawList[i].country;
        }

        if (!priorLocationValsHash[LocationName]) {
          //Create a unique ID that will be given to the Label in the filter div in the side bar.  CID-SPID-city_name (e.g. 217-35-new_york) 
          var LocationID = this.RawList[i].country_id + '-' + this.RawList[i].state_province_id + '-' + this.RawList[i].city.toLowerCase().replace(/\s+/g, "_");

          this.LocationValues.push([LocationName, LocationID]);
          this.LocationCount[LocationName] = 1;

          priorLocationValsHash[LocationName] = true;
        }
        else {
          this.LocationCount[LocationName]++;
        }

        /*
        if(!priorVenueValsHash[this.RawList[i].venue_name])
        {
        this.VenueValues.push( this.RawList[i].venue_name );
        this.VenueCount[ this.RawList[i].venue_name ] = 1;

        priorVenueValsHash[this.RawList[i].venue_name] = true;
        }
        else
        {
        this.VenueCount[ this.RawList[i].venue_name ]++;
        }*/

        if (!this.DayOfWeekValues[this.RawList[i].event_datetime.getUTCDay()]) {
          this.DayOfWeekValues[this.RawList[i].event_datetime.getUTCDay()] = true;
        }
        this.DayOfWeekCount[this.RawList[i].event_datetime.getUTCDay()]++;

        if (!this.CategoryValues[this.RawList[i].category_parent_id - 1]) {
          this.CategoryValues[this.RawList[i].category_parent_id - 1] = true;
        }
        this.CategoryCount[this.RawList[i].category_parent_id - 1]++;

        if (this.RawList[i].event_datetime.getUTCHours() >= 17) {
          this.TimeOfDayCount['evening']++;
        }
        else {
          this.TimeOfDayCount['daytime']++;
        }

        if (this.RawList[i].advantage == 'home') {
          this.AdvantageCount['home']++;
        }
        else if (this.RawList[i].advantage == 'away') {
          this.AdvantageCount['away']++;
        }
      }


      /*this.VenueValues.sort();*/
      this.LocationValues.sort();
    }

    this.Initialized = true;
  };

  this.PopulateValues = function(inLocVals, inLocCount, inDOWVals, inDOWCount, inCatVals, inCatCount, inTimeOfDayCount, inAdvCount) //inVenVals, inVenCount, 
  {
    this.LocationValues = inLocVals;
    this.LocationCount = inLocCount;

    /*this.VenueValues = inVenVals;
    this.VenueCount = inVenCount;*/

    this.DayOfWeekValues = inDOWVals;
    this.DayOfWeekCount = inDOWCount;

    this.CategoryValues = inCatVals;
    this.CategoryCount = inCatCount;

    this.TimeOfDayCount = inTimeOfDayCount;

    this.AdvantageCount = inAdvCount;

    this.Initialized = true;
  };
}


function TNR4FilterApplyOrderCache() {
  this.FilterListOrder = new Array();

  this.AddFilterGroup = function(filGroupName) {
    this.FilterListOrder.push(filGroupName);
  }

  this.RemoveFilterGroup = function(filGroupName) {
    for (var i = 0; i < this.FilterListOrder.length; i++) {
      if (this.FilterListOrder[i] == filGroupName) {
        this.FilterListOrder.splice(i, 1);
        break;
      }
    }
  }

  this.GetFilterGroupOrder = function(filGroupName) {
    for (var i = 0; i < this.FilterListOrder.length; i++) {
      if (this.FilterListOrder[i] == filGroupName) {
        return i;
      }
    }
    return -1;
  }

  this.ClearFilterListOrder = function() {
    this.FilterListOrder = null;
    this.FilterListOrder = new Array();
  }
}


function TNR4EventCache(rawJSONVals) {
  // note this assumes that the JSON outer variable is always called "event" for the event cache
  this.RawInner = rawJSONVals.Event;
  this.LastDisplayedListState = this.RawInner;



  this.Sort = function(sortDelegate) {
    this.LastDisplayedListState.sort(sortDelegate);
  };

  this.SortReverse = function(sortDelegate) {
    this.Sort(sortDelegate);
    this.LastDisplayedListState.reverse();
  };

  this.ToHtml = function() {
    this.LastDisplayedListState = this.RawInner;
    return this.RenderHtmlFromList(this.LastDisplayedListState);
  };


  this.RenderHtmlFromList = function(evtObjArr) {
    //Filtered or Sorted Grid HTML
    this.LastDisplayedListState = evtObjArr;
    var retSB = new StringBuilder();
    retSB.append('<tr');

    if (evtObjArr.length > 0) {
      for (var i = 0; i < evtObjArr.length; i++) {
        retSB.append(' class="');
        retSB.append((i % 2 == 1) ? 'evtRowOdd' : 'evtRowEven');
        retSB.append('">');

        retSB.append('<td class="event"><h2><b><a href="' + evtObjArr[i].event_url + '">');
        retSB.append(evtObjArr[i].event_name);
        retSB.append('</a></b></h2></td>');

        retSB.append('<td class="location">');
        if (evtObjArr[i].country_id == 217)  //If country is in USA display city, state.  Else display city, country.
        {
          var statePP = ToPPUrl(evtObjArr[i].state);
          retSB.append('<a href="/local/usa/' + statePP + '/' + ToPPUrl(evtObjArr[i].city) + '-tickets.aspx">');
          retSB.append(evtObjArr[i].city + '</a>, <a href="/local/usa/' + ToPPUrl(evtObjArr[i].state_long) + '-tickets.aspx">');
          retSB.append(evtObjArr[i].state);
          retSB.append('</a>');
        }
        else {
          retSB.append('<a href="/local/' + ToPPUrl(evtObjArr[i].country) + '/' + ToPPUrl(evtObjArr[i].state) + '/' + ToPPUrl(evtObjArr[i].city) + '-tickets.aspx">');
          retSB.append(evtObjArr[i].city + '</a>, ' + evtObjArr[i].country);
        }
        retSB.append('</td>');

        retSB.append('<td class="venue"><a href="/venues/' + ToPPUrl(evtObjArr[i].venue_name) + '-tickets.aspx?vid=');
        retSB.append(evtObjArr[i].venue_id + '">');
        retSB.append(evtObjArr[i].venue_name);
        retSB.append('</a></td>');

        retSB.append('<td class="date">');
        retSB.append('<b>' + evtObjArr[i].day_month_year + '</b><br />');
        retSB.append(evtObjArr[i].day_of_week_short + ' ');
        if (evtObjArr[i].time_of_day == '3:30AM') {
          retSB.append('[Time TBA]');
        }
        else {
          retSB.append(evtObjArr[i].time_of_day);
        }
        retSB.append('</td>');


        retSB.append('<td class="view_tix">');
        retSB.append('<a class="goButton" href="' + evtObjArr[i].event_url + '">');
        retSB.append('View Tickets');
        retSB.append('</a></td>');

        // end row, start new if there is another one after this
        if (i + 1 < evtObjArr.length) {
          retSB.append('</tr><tr');
        }
      }
    }
    else {
      retSB.append(' class="evtRowOdd" style="height: 50px;"');
      retSB.append('">');

      retSB.append('<td><h2>No results were found that match the filter criteria that have been selected.</h2></td>');
    }

    retSB.append('</tr>');

    if (hasEventPricing) {
      retSB.append('<script type="text/javascript"> ');
      retSB.append('LoadEventGridPricing();');
      retSB.append('</script>');
    }

    return retSB.toString();
  };

  this.SerializeJSON = function() {

  };

}

function SortByDateTime(eventObjA, eventObjB) {
  return eventObjA.event_datetime.getTime() - eventObjB.event_datetime.getTime();
}

function SortByEventName(eventObjA, eventObjB) {
  if (eventObjA.event_name == eventObjB.event_name) {
    // if equivalent name, do it by date
    return SortByDateTime(eventObjA, eventObjB);
  }
  else {
    var evtNameSampleArr = [eventObjA.event_name, eventObjB.event_name].sort();

    if (evtNameSampleArr[0] == eventObjA.event_name) {
      return -1;
    }
    else {
      return 1;
    }
  }
}

function SortByVenueName(eventObjA, eventObjB) {
  if (eventObjA.venue_name == eventObjB.venue_name) {
    return SortByDateTime(eventObjA, eventObjB);
  }
  else {
    var venueSampleArr = [eventObjA.venue_name, eventObjB.venue_name].sort();

    if (venueSampleArr[0] == eventObjA.venue_name) {
      return -1;
    }
    else {
      return 1;
    }
  }
}

function SortByLocationName(eventObjA, eventObjB) {
  //Sorting by city name
  if (eventObjA.city == eventObjB.city) {
    return SortByDateTime(eventObjA, eventObjB);
  }
  else {
    var citySampleArr = [eventObjA.city, eventObjB.city].sort();

    if (citySampleArr[0] == eventObjA.city) {
      return -1;
    }
    else {
      return 1;
    }
  }
}

function AutoSetEndDate() {
  var dateToBe = $('#tn_evt_filter_date_begin').attr('value');
  if (checkDate(dateToBe)) {
    dateToBe = new Date(dateToBe);
    dateToBe.setMonth(dateToBe.getMonth() + 2);
    $('#tn_evt_filter_date_end').datepicker('setDate', dateToBe);
  }
  $('#tn_evt_filter_date_end').datepicker('show');

}

function OpenStartDate() {
  $('#tn_evt_filter_date_begin').datepicker('show');
}

function SetSelectedCheckbox()  //The call to this exists in the this.MakeFiltersHTML function.  This will only get fired once on load.
{
  var objURL = GetQueryStringObj();

  if (objURL) {
    //We want to take the CountryID (CID), State_Province_ID(SPID), and City Name
    //and see if a matching item exists in the filtered list.  if it does, set that item to checked.
    if (objURL["cid"] && objURL["spid"] && objURL["cityName"]) {
      //Create the string that is the ID of the filter label.
      var filterObjName = objURL["cid"] + '-' + objURL["spid"] + '-' + objURL["cityName"].toLowerCase().replace(/[\s\+]+/g, "_"); // + 'i';

      //Fire the checkbox check event.
      //"LocationGroupName" is the hardcoded ID of the name of the group.  Set in this.MakeFiltersHtml
      document.TN_EventTable.ReFilterClick('LocationGroupName', filterObjName);
      //Add "i" to the end of the object name to make it the CheckBox object.
      $('#' + filterObjName + 'i').attr('checked', true);
    }

    if (objURL["catid"]) {
      var filterCatName = "category" + objURL["catid"];

      document.TN_EventTable.ReFilterClick('CategoryGroupName', filterCatName);
      $('#' + filterCatName + 'i').attr('checked', true);
    }
  }
}

function SearchGridByDate() {

  var redirLoc = "";

  var objURL = GetQueryStringObj();

  if (objURL) {
    redirLoc = location.pathname + "?";

    for (var key in objURL) {
      if (key == "startDate") {
        if ($('#tn_evt_filter_date_begin').val() != '') {
          redirLoc += key + "=";
          redirLoc += escape($('#tn_evt_filter_date_begin').val()) + "&";
        }
      }
      else if (key == "endDate") {
        if ($('#tn_evt_filter_date_end').val() != '') {
          redirLoc += key + "=";
          redirLoc += escape($('#tn_evt_filter_date_end').val()) + "&";
        }
      }
      else if (key == "page") {
        //do nothing to get rid of this query
      }
      else {
        redirLoc += key + "=";
        redirLoc += objURL[key] + "&";
      }
    }

    if (!objURL["startDate"]) {
      if ($('#tn_evt_filter_date_begin').val() != '') {
        redirLoc += "startDate=" + escape($('#tn_evt_filter_date_begin').val()) + "&";
      }
    }
    if (!objURL["endDate"]) {
      if ($('#tn_evt_filter_date_end').val() != '') {
        redirLoc += "endDate=" + escape($('#tn_evt_filter_date_end').val());
      }
    }
  }
  else {
    redirLoc = location.pathname + "?startDate=" + escape($('#tn_evt_filter_date_begin').val()) + "&endDate=" + escape($('#tn_evt_filter_date_end').val());
  }


  if ($('#tn_evt_filter_date_begin').val() != null && $('#tn_evt_filter_date_begin').val() != '') {
    try {
      pageTracker._trackEvent('Date Range Search/Filter', 'filter date range', location.pathname);
    }
    catch (e) {
    }
    location.href = redirLoc;
  }
  else {
    $('#tn_evt_start_error').show();
  }
}

