		<!-- Row Hover Javascript -->
		var rowClassName;
		function hoverRow(target)
		{
			rowClassName = target.className;
			target.className = 'rowhover';
		}
		function exitRow(target)
		{
			target.className = rowClassName;
		
		}

var ASCENDING = "ascending";
var DESCENDING = "descending";
var NUMBER_SORT_TYPE = "number";
var TEXT_SORT_TYPE = "text";

function setReportTitle(title)
{
    this.reportTitle = title;
}

function setReportSubtitle(title)
{
    this.reportSubtitle = title;
}


var resultsXmlPath;
var recordEntryKeys;

function reportSetPageNumber(page)
{
     this.pageNumber = page;
}

function reportResetPageNumber()
{
    this.setPageNumber(1);
}
/**number of entries per page shown ... doon't provide it and get the default or provided by preferences*/
function reportAssignResultsLimit(limit)
{
       this.resultsLimit = limit;
}

function reportBuildAppendRecordEntryKey(recordEntryKey)
{
    return  '&query.recordEntryKeys=' + recordEntryKey;
}
function reportSetSortByKey(columnKey,sortTypeForKey,swapIfNeeded)
{
    this.sortType = sortTypeForKey;
    
    //same key means swap the sort order
    if(swapIfNeeded && this.sortByColumnKey == columnKey)
    {
        //swap sort order
        if(this.sortOrder == ASCENDING)
        {
            this.sortOrder = DESCENDING;
        }
        else
        {
            this.sortOrder = ASCENDING;
        }
    }
    else
    {
        this.sortByColumnKey = columnKey;
        //numbers are better biggest first.
        if(this.sortType == NUMBER_SORT_TYPE)
        {
            this.sortOrder = DESCENDING;
        }
        else
        {
            this.sortOrder = ASCENDING;
        }
    }
    this.sortByColumnKey = columnKey;
    
}

function reportSetSortOrder(whichSortOrder)
{
    this.sortOrder = whichSortOrder;
    
}

/** loads the query of the given query path and refreshes the resutls*/
function reportBuildQueryPath()
{
   this.queryPath = this.reportUrlBase;
   this.queryPath += '&query.pageNumber=' + this.pageNumber;
   
   var recordEntryKeys   = this.primaryColumns.concat(this.columnSet.getAll());

   if(recordEntryKeys.length > 0)
   {
       var recordEntryPath = "";
       for(var whichKey = 0; whichKey < recordEntryKeys.length; whichKey++)
       {
             recordEntryPath +=  reportBuildAppendRecordEntryKey(appendSelectSuffix(recordEntryKeys[whichKey]));
       }
         this.queryPath += recordEntryPath;
       
   }
   else
   {
       alert("This page won't work because no columns are chosen");
   }

    this.queryPath += '&reportType=' + this.type;   
         
   if(this.resultsLimit != null)
   {
         this.queryPath += '&query.resultsLimit=' + this.resultsLimit;   
   }
          
   if(this.sortByColumnKey != null)
   {
      var key = this.sortByColumnKey;
      if(this.sortOrder  == ASCENDING)
      {
          key = appendAscSuffix(this.sortByColumnKey); 
      }
      else
      {
          key = appendDescSuffix(this.sortByColumnKey);
      }
      this.queryPath  +=  reportBuildAppendRecordEntryKey(key);
   }
//   else... always add the main sorting after the chosen sort
   {
        for(var whichSortBy = 0; this.sortByColumns != null && whichSortBy < this.sortByColumns.length; whichSortBy++)
        {
            var sortColumnKey = this.sortByColumns[whichSortBy];
              this.queryPath  +=  reportBuildAppendRecordEntryKey(sortColumnKey);
        }
   }
   
   //add individual activities
    for(var whichFilter = 0; whichFilter < this.reportFilters.length; whichFilter++)
    {
		var filter = this.reportFilters.filters[whichFilter];
		if (filter.type == "IndividualActivity"){
			this.queryPath += '&query.orConditionGroups=' + filter.value;
		}
    }
   
   //add date range filter to filters
    for(var whichFilter = 0; whichFilter < this.reportFilters.length; whichFilter++)
    {
		var filter = this.reportFilters.filters[whichFilter];
		if (filter.type == "DateFilter"){
			this.queryPath += '&' + filter.value;
		}
    }

	//add keywords
	var keywordlist = "";
    for(var whichFilter = 0; whichFilter < this.reportFilters.length; whichFilter++)
    {
		var filter = this.reportFilters.filters[whichFilter];
		if (filter.type == "Keyword"){
			keywordlist += " " + filter.value;
		}
    }
    if (keywordlist != ""){
   			this.queryPath += '&query.keywords=' + encodeURIComponent(keywordlist);
   			this.queryPath += '&query.keywordRecordEntryKeys=episodeName&query.keywordRecordEntryKeys=episodeComments&query.keywordRecordEntryKeys=activityTypeDescription&query.keywordRecordEntryKeys=eventTypeDescription&query.keywordRecordEntryKeys=locationFullName&query.keywordRecordEntryKeys=username';
   			//OLD QUERY BEFORE 1.8
   			//this.queryPath += '&query.keywordRecordEntryKeys=episodeName&query.keywordRecordEntryKeys=episodeComments&query.keywordRecordEntryKeys=activityTypeDescription&query.keywordRecordEntryKeys=locationFullName&query.keywordRecordEntryKeys=username';
   			
            //provided externally for security reasons.
            var keys = new MBKeywords();
			var queryPathExtraInfo = keys.getQueryPathExtraInfo();
     		this.queryPath += queryPathExtraInfo;
    }

	//add map boundaries
    for(var whichFilter = 0; whichFilter < this.reportFilters.length; whichFilter++)
    {
		var filter = this.reportFilters.filters[whichFilter];
		if (filter.type == "MapBoundary"){
			this.queryPath +=  '&' + filter.buildRequest();
		}
    }

    //add all other filters
    var filterQuery = buildRequest(this.rowConditionGroups,'query.andConditionGroups');
    var filterRequests = new Array();
    for(var whichFilter = 0; whichFilter < this.reportFilters.length; whichFilter++)
    {
        var filter = this.reportFilters.filters[whichFilter];
        if (filter.type != "Keyword" && filter.type != "MapBoundary" && filter.type != "DateFilter" && filter.type != 'IndividualActivity'){
			filterRequests.push(filter.value);
        }
    }
    filterQuery +=  buildRequest(filterRequests,'query.orConditionGroups');
    this.queryPath += '&' +  filterQuery;
    return this.queryPath;
}



/**dummy method used to trick a tags from acting */
function ClickToShow(){}

function loadReport()
{    
	showLoading();
    //async call to get new report
	var getreporthtml = new getReportHtml(this);
	getreporthtml.loadHtml();
}

function getReportXsl() {
	//context path  and topnavContext part of site javascript variables.
    var xslUrl =  "/trail" +  activeReport.xslUrl + "?topnavContext=" + topnavContext;	
    xslUrl +=  "&reportTitle=" + activeReport.reportTitle

	return xslUrl;
}

function clearResults() {
	var resultsTable = document.getElementById('reportContainer');
	resultsTable.innerHTML = "";
}

function showResults()
{
	showLoading();
	activeReport = this;
	if (this.htmlResults){
		var resultsTable = document.getElementById('reportContainer');
		resultsTable.innerHTML =  this.htmlResults;
		ReportRefreshed();
	}
}

    
 var ACTIVITY_TYPE = "activityType";
  var EVENT_TYPE = "eventType";
    var USERNAME = "username";
    var CUSTOMER_ROLE_NAME = "roleName";
    var CUSTOMER_EMAIL_ADDRESS = "customerEmailAddress";
    var CUSTOMER_FIRST_NAME = "customerFirstName";
    var CUSTOMER_LAST_NAME = "customerLastName";

   var BILLING_PROFILE_ID = "billingProfileId";
   var BILLING_PROFILE_NEXT_DATE = "billingProfileCheckUpDate";
   var BILLING_PROFILE_CREATE_DATE = "billingProfileCreateDate";
   var BILLING_PROFILE_MODIFY_DATE = "billingProfileModifiedDate";
   var BILLING_PROFILE_ISSUER_PK = "billingProfileIssuerPk";
     
 var ACTIVITY_TYPE_PK = "activityTypePk";
 var TOTAL_DURATION = "episodeTotalDuration";
 var TOTAL_DISTANCE = "totalDistance";
 var AVERAGE_SPEED = "averageSpeed";
 var TOTAL_ELEVATION_CHANGE= "totalElevationChange";
 var TOTAL_ELEVATION_GAIN = "totalElevationGain";
 var TOTAL_ELEVATION_LOSS= "totalElevationLoss";
var TRACKING_DEVICE_NAME = "trackingDeviceName";
var TRACKING_AGENT_NAME = "trackingAgentName";
var TRACKING_AGENT_VERSION = "trackingAgentVersionIdentifier";
var AVERAGE_PACE = "averagePace";
var LOCATION_NAME = "locationFullName";
var LOCATION_ABSOLUTE_NAME = "locationAbsoluteName";
var REGION_ABSOLUTE_NAME = "locationRegionAbsoluteName";

var TRACK_START_LATITUDE = "trackStartLatitude";
var TRACK_START_LONGITUDE = "trackStartLongitude";
var TRACK_MIN_LATITUDE = "trackMinLatitude";
var TRACK_MIN_LONGITUDE = "trackMinLongitude";
var TRACK_MAX_LATITUDE = "trackMaxLatitude";
var TRACK_MAX_LONGITUDE = "trackMaxLongitude";

var EPISODE_PK = "episodePk";
var EPISODE_NAME = "episodeName";
var  EPISODE_START_DATE = "episodeStartDate";

var START_YEAR  = "episodeStartYear";
var START_MONTH = "episodeStartMonth";
var START_WEEK_OF_YEAR = "episodeWeekOfYear";
var START_DAY_OF_YEAR = "episodeDayOfYear";
var START_DAY_OF_WEEK = "episodeDayOfWeek";
var START_DAYTIME_RANGE= "episodeDaytimeRange";
var MONTHLY_CHRONOLOGY= "episodeMonthlyChronology";
var DAILY_CHRONOLOGY= "episodeDailyChronology";
var WEEKLY_CHRONOLOGY= "episodeWeeklyChronology";

var OR_INDICATOR = "%7C";//vertical bar |
var AND_INDICATOR = "%2B"; // plus symbol +

function appendSelectSuffix(recordEntryKey)
{
    return recordEntryKey + "-select";
}
function appendAscSuffix(recordEntryKey)
{
    return recordEntryKey + "-asc";
}
function appendDescSuffix(recordEntryKey)
{
    return recordEntryKey + "-desc";
}                
function appendGroupSuffix(recordEntryKey)
{
    return recordEntryKey + "-group";
}
function appendSumSuffix(recordEntryKey)
{
    return recordEntryKey + "-sum";
}
function appendAvgSuffix(recordEntryKey)
{
    return recordEntryKey + "-avg";
}
function appendCountSuffix(recordEntryKey)
{
    return recordEntryKey + "-count";
}
function appendIdSuffix(recordEntryKey)
{
    return recordEntryKey + "-id";
}
  function appendTimeCodedSuffix(recordEntryKey)
{
    return recordEntryKey + "-timeCoded";
}


// =============== REPORT FILTERS ================
function ReportFilters()
{
	this.filters = new Array();
	this.length = 0;
	
	this.getFilters = function() {
		return this.filters;
	}

	this.getNumberOfFilters = function(){
	 	return this.filters.length;
	}
	
	this.setFilters = function(filters) {
		this.filters = filters;
		this.length = filters.length;
	}
	
	this.clearFilters = function() {
		//we cannot clear the hidden and those that shouldn't be deleted
		var newFilterArray = new Array();
		for(var whichFilter = 0; whichFilter < this.filters.length; whichFilter++)
		{
			var filter = this.filters[whichFilter];
			if (filter.hidden == true){
				newFilterArray.push(filter);
			}
			else if (filter.canDelete == false){
				newFilterArray.push(filter);			
			}
		}
		this.filters = newFilterArray;
		this.length = this.filters.length;
	}
	
	this.addFilter = function (filter) {
		if (!this.containsFilter(filter.type,filter.value))
			this.filters.push(filter);
			this.length = this.filters.length;
	}

	this.addFilters = function (filters) {
		for (var f = 0;f<filters.length;f++) {
			this.addFilter(filters[f]);
			this.length = this.filters.length;
		}
	}
	
	this.deleteFilter = function(filterNum) {
		this.filters.splice(filterNum,1);
		this.length = this.filters.length;
	}
	
	/**Search the filters for the type of filter and remove it from the list if
	 * the type matches and no value was given or if the filter matches both the 
	 *  type and value given.
	 */
	this.deleteFilterByType = function(type,value) {
		var newFilterArray = new Array();
		for(var whichFilter = 0; whichFilter < this.filters.length; whichFilter++)
		{
			var filter = this.filters[whichFilter];
			if (filter.type == type && (filter.value == value || value == null)){
				//ignore this node, it was a match
			}
			else {
				newFilterArray.push(filter);
			}
		}
		this.filters = newFilterArray;
		this.length = this.filters.length;
	}
	
   this.isEmpty = function(){
        return this.filters.length == 0;
   }
	this.numberFilters = function(type) {
		var numfound = 0;
		for(var whichFilter = 0; whichFilter < this.filters.length; whichFilter++)
		{
			var filter = this.filters[whichFilter];
			if (filter.type == type){
				numfound++;
			}
		}
		return numfound;
	}
	
	this.containsFilterTypeAndKey = function(type,keyPartOfValue){
		var found = false;
		for(var whichFilter = 0; whichFilter < this.filters.length && !found; whichFilter++)
		{
			var filter = this.filters[whichFilter];
		
			if (filter.type == type && filter.value.indexOf(keyPartOfValue) != -1){
				found = true;
			}
		}
		return found;
	}
	
	this.containsFilterType = function(type,keyPartOfValue){
		return this.containsFilterTypeAndKey(type,"");
	}
	
	this.containsFilter = function(type,value){
		var found = false;
		for(var whichFilter = 0; whichFilter < this.filters.length && !found; whichFilter++)
		{
			var filter = this.filters[whichFilter];
			if (filter.type == type && filter.value == value){
				found = true;
			}
		}
		return found;
	}
	
}

//=============================== REPORT OBJECT =================================

//Define cloning capabilities
//reference: http://www.codingforums.com/showthread.php?threadid=2902&perpage=15&highlight=copy%20object&pagenumber=1
Object.prototype.copy = function() {
var copy = new this.constructor;
for (prop in this) copy[prop] = this[prop];
return copy;
}

function CopyReport(report){
	var copy = new Report();
	copy.type = report.type;
	copy.primaryColumns = report.primaryColumns;
	copy.columnSet = CopyReportColumnSet(report.columnSet);
	copy.filterQuery = report.filterQuery;
	copy.savedReportPk = report.savedReportPk;
	copy.callerActivitiesOnly = report.callerActivitiesOnly;
	copy.reportUrlBase = report.reportUrlBase;
	copy.pageNumber = report.pageNumber;
	copy.resultsLimit = report.resultsLimit;
	copy.sortOrder = report.sortOrder;
	copy.sortType = report.sortType;
	copy.sortByColumnKey = report.sortByColumnKey;
	copy.reportSubtitle =report.reportSubtitle;
	copy.reportTitle = report.reportTitle;
	copy.xslUrl = report.xslUrl;
	copy.htmlResults = report.htmlResults;
	copy.queryResults = report.queryResults;
	var filters = report.reportFilters.getFilters();
	copy.reportFilters.setFilters(filters.copy());
	copy.rowConditionGroups = report.rowConditionGroups.copy();
	copy.pendingRowConditionGroups = report.pendingRowConditionGroups.copy();
	return copy;
}

function Report(reportType,primaryColumnsArray,reportColumnSet)
{
    this.type = reportType;
    this.primaryColumns = primaryColumnsArray;
    this.columnSet = CopyReportColumnSet(reportColumnSet);
        
    this.filterQuery = null;
    this.savedReportPk = -1;
    
    this.callerActivitiesOnly = isCallerActivitiesOnly();
    this.reportUrlBase = "/trail/network/report/stats/get.mb?query.digestPreferencesUsed=false&query.callerActivitiesOnly=" + this.callerActivitiesOnly;
    //    Page Handling.
    this.pageNumber = 1;
    this.resultsLimit  = null;
    //once the data is loaded, this will identify how many pages are avilable (for sorting mostly).
    
    //alternates ascending/descending 
    this.sortOrder = DESCENDING;
    // the xsl:sort data-type attribute value (text or number)
    this.sortType = 'text';
    
    this.sortByColumnKey = null;
    this.reportSubtitle;
    this.reportTitle = "";
   
   /**the base for the report URL to be mixed with the results.*/

    this.xslUrl = "/report/ReportResultsXsl.jsp";
        
    this.setXslUrl = function(xslUrl)
    {
        this.xslUrl = xslUrl;
    }
    
    //this.selectAllOnThisPage = ReportSelectAllOnThisPage;
    this.setPageNumber = reportSetPageNumber;
    this.getPageNumber = function() { return this.pageNumber;}
    this.resetPageNumber = reportResetPageNumber;
    this.setReportTitle = setReportTitle;
    this.setReportSubtitle = setReportSubtitle;
    this.assignResultsLimit = reportAssignResultsLimit;
    this.setSortByKey =  reportSetSortByKey;
    this.setSortOrder = reportSetSortOrder;
    this.buildQueryPath = reportBuildQueryPath;

    this.load = loadReport;
    this.show = showResults;

    this.reportFilters = new ReportFilters();
    
    this.rowConditionGroups= new Array();
    this.pendingRowConditionGroups = new Array();
    this.addConditionGroup = ReportAddConditionGroup;
    this.addRowConditionGroup = ReportAddRowConditionGroup;
    this.addAndConditionGroup = ReportAddAndConditionGroup;
    
    this.commitRowConditionGroups = function()
    {
        this.rowConditionGroups = this.getAllRowConditionGroups();
        this.pendingRowConditionGroups = new Array();
        this.resetPageNumber();
    }
    
    this.getAllRowConditionGroups = function()
    {
        return this.rowConditionGroups.concat(this.pendingRowConditionGroups);
    }

}

function getReportHtml(report) {
	this.loaded = false;
	
	this.responseSuccess = function(o)
	{
		this.loaded = true;
		activeReport.htmlResults = o.responseText;
		activeReport.show();
		statusMessage.showMessage("Data Loaded");
		statusMessage.hideMessage(1000);
	}
	
	this.responseFailure = function(o)
	{
	   statusMessage.showMessage("Error Loading Report");
	}
	
	this.callback =
	{
	   success : this.responseSuccess,
	   failure : this.responseFailure
	};
			
	this.loadHtml = function()
	{
		statusMessage.showMessage("Loading Data");
		activeReport.buildQueryPath();
		var contextPath = "/trail";
		var xmlurl = activeReport.queryPath.replace(contextPath,"");
		var xslurl = getReportXsl(activeReport).replace(contextPath,"");
		var url = "/trail/transformer/transformer.jsp?xmldoc=" + encodeURIComponent(xmlurl) + "&xsldoc=" + encodeURIComponent(xslurl);
		//debug
		//window.open(url);
		YAHOO.util.Connect.asyncRequest('GET',url,this.callback);
	}
}  

// =============== FILTER ================
var FILTER_OPERATOR_EQUALS = "=";

//used to build custom report filter requests.
function ReportFilter(type,displayName,value)
{
	this.type = type;
    this.displayName = displayName;
    this.value = value;
    this.buildRequest = function()
    {
       return this.value;
    }
        
    this.hidden = false;
    this.canDelete = true;
    this.toString = function()
    {
        return this.request;
    }
    this.getValueParts = function()
    {
    	return new ReportFilterValueParts(this.value);
    }
    this.request = this.buildRequest();
}

/**Useful object to parse the valueString in the ReportFilter object*/
function ReportFilterValueParts(valueString)
{
	var parts = valueString.split("=");
	/** the name part of the name=vlaue pair*/
	this.name = parts[0];
	/** the value part of the name=value pair*/
	this.value = parts[1];
}
var FILTER_TYPE_LISTINGS_ROW = 'listings';
var FILTER_TYPE_REPORT_ROW = 'report';
var FILTER_TYPE_CUSTOM = 'custom';

function buildRequest(valueArray,paramName)
{
       var queryPath = "";
       for(var whichValue = 0; whichValue< valueArray.length; whichValue++)
       {
           var value = valueArray[whichValue];
           if(value !=null)
           {
                 queryPath  += '&';
                 queryPath  += paramName;
                 queryPath  += '=';
                 queryPath  += value;
             }
       }
         return queryPath;
     }

/* Given a condition array that represents the limits of a single row will be changed into a condition group ready for the server.
   Each element of the array may only contain a single condition...i.e.  ['activityTypePk=78','episodeName=Some Trail']
   
*/
function ReportAddConditionGroup(conditionRequest,conditionGroupArray,isRemoval)
{
        var conditionRequest = conditionRequest;

        var count = 0;
        //now search the array to see if it has already been added..remove all for now...minimizes duplicates and removes if needed
        for(var whichGroup = 0 ; whichGroup< conditionGroupArray.length; whichGroup++)
        {
            var group = conditionGroupArray[whichGroup];
            
            if(group == conditionRequest)
            {
                conditionGroupArray[whichGroup] = null;
            }
            else if(group != null)
            {
                count++;
            }
        }         
        if(!isRemoval)
        {
            conditionGroupArray[conditionGroupArray.length] = conditionRequest;
            count++;
        }
        
        document.getElementById('selectCountDisplayElement').innerHTML = count;
}

    
function ReportAddAndConditionGroup(conditionRequest,isRemoval)
{
     this.addConditionGroup(conditionRequest,this.andConditionGroups,isRemoval);   
}
function ReportAddRowConditionGroup(conditionRequest,isRemoval)
{
     this.addConditionGroup (conditionRequest,this.pendingRowConditionGroups,isRemoval);   
     if(isRemoval)
     {
         this.addConditionGroup (conditionRequest,this.rowConditionGroups,isRemoval);   
     }
}                
