<?php
/**
 * ###############################################
 *
 * SWIFT Framework
 * _______________________________________________
 *
 * @author		Varun Shoor
 *
 * @package		SWIFT
 * @copyright	Copyright (c) 2001-2012, Kayako
 * @license		http://www.kayako.com/license
 * @link		http://www.kayako.com
 *
 * ###############################################
 */

/**
 * The Report Base class used by Report Renderer and Report Exporter
 *
 * @author Andriy Lesyuk
 */
abstract class SWIFT_ReportBase extends SWIFT_Library
{
	const EXPORT_EXCEL = 'Excel';
	const EXPORT_EXCEL5 = 'Excel5';
//	const EXPORT_PDF = 'PDF';
	const EXPORT_CSV = 'CSV';
	const EXPORT_HTML = 'HTML';

	protected $_backupTimeZone = false;

	protected $KQLParserResult = false;
	protected $Report = false;
	protected $_sqlResult = array();
	protected $_schemaContainer = array();
	protected $_sqlParsedTitles = array();
	protected $_sqlGroupByFields = array();
	protected $_sqlGroupByXFields = array();
	protected $_sqlGroupByMultiFields = array();
	protected $_sqlDistinctValueContainer = array();

	// Matrix Report
	protected $_baseTitleContainer = false;
	protected $_replacementYKey = false;
	protected $_groupFieldList = array();
	protected $_parentTitleIgnoreList = array();
	protected $_dataContainer = array();
	protected $_baseUserFieldList = array();
	protected $_distinctYGroupValuesList = array();
	protected $_baseUserFieldCount = 0;
	protected $_resultsContainerY = array();
	protected $_groupByYCountMap = array();

	protected $_recordCount = 0;

	protected $_rowCount = 0;
	protected $_extraCount = 0;

	// Hidden Fields
	protected $_hiddenFields = array();

	// Custom Fields
	protected $_customFields = array();

	// Original Aliases
	protected $_originalAliasesMap = array();

	// Export formats
	protected $_exportFormatMap = array(
		self::EXPORT_EXCEL => array('Excel2007', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'xlsx'),
		self::EXPORT_EXCEL5 => array('Excel5', 'application/vnd.ms-excel', 'xls'),
//		self::EXPORT_PDF => array('PDF', 'application/pdf', 'pdf'),
		self::EXPORT_CSV => array('CSV', 'text/csv', 'csv'),
		self::EXPORT_HTML => array('HTML', 'text/html', 'html'));

	/**
	 * @var SWIFT_KQL
	 */
	public $KQL = false;

	/**
	 * @var KQL2 Object
	 */
	protected $KQLObject = false;

	/**
	 * Constructor
	 *
	 * @author Varun Shoor
	 * @param SWIFT_KQL2 $_SWIFT_KQL2Object
	 * @param SWIFT_Report $_SWIFT_ReportObject
	 * @param SWIFT_KQLParserResult $_SWIFT_KQLParserResultObject
	 * @return bool "true" on Success, "false" otherwise
	 */
	public function __construct($_SWIFT_KQL2Object, SWIFT_Report $_SWIFT_ReportObject, SWIFT_KQLParserResult $_SWIFT_KQLParserResultObject)
	{
		parent::__construct();

		if (!$_SWIFT_ReportObject instanceof SWIFT_Report || !$_SWIFT_ReportObject->GetIsClassLoaded()
				|| !$_SWIFT_KQLParserResultObject instanceof SWIFT_KQLParserResult || !$_SWIFT_KQLParserResultObject->GetIsClassLoaded()) {
			throw new SWIFT_Exception('Invalid Input Received for Report Rendering/Exporting');
		}

		$this->Load->Library('KQL:KQL');

		$this->_schemaContainer = SWIFT_KQLSchema::GetCombinedSchema();

		$this->KQLObject = $_SWIFT_KQL2Object;
		$this->Report = $_SWIFT_ReportObject;
		$this->KQLParserResult = $_SWIFT_KQLParserResultObject;

		$this->_sqlGroupByFields = $this->KQLParserResult->GetGroupByFields();
		$this->_sqlGroupByXFields = $this->KQLParserResult->GetGroupByXFields();
		$this->_sqlGroupByMultiFields = $this->KQLParserResult->GetMultiGroupByFields();
		$this->_sqlDistinctValueContainer = $this->KQLParserResult->GetDistinctValues();

		return true;
	}

	/**
	 * Destructor
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 */
	public function __destruct()
	{
		parent::__destruct();

		return true;
	}

	/**
	 * Execute the SQL statement and place in the result
	 *
	 * @author Varun Shoor
	 * @param string $_customSQL (OPTIONAL)
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	protected function ExecuteSQL($_customSQL = false)
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		} else if (!$this->KQLParserResult instanceof SWIFT_KQLParserResult || !$this->KQLParserResult->GetIsClassLoaded()) {
			throw new SWIFT_Exception('Invalid KQL Parser Result Object');
		}

		$this->_rowCount = 0;
		$this->_extraCount = 0;

		$this->_sqlResult = array();

		$_sqlStatementList = $this->KQLParserResult->GetSQL();

		if (!empty($_customSQL)) {
			if (is_array($_customSQL)) {
				$_sqlStatement = $_customSQL[0];
			} else {
				$_sqlStatement = $_customSQL;
			}

//			echo $_sqlStatement . '<br />' . SWIFT_CRLF;
			$this->Database->Query($_sqlStatement);

		} else if (isset($_sqlStatementList[0])) {
//			echo $_sqlStatementList[0] . '<br />' . SWIFT_CRLF;
			$this->Database->Query($_sqlStatementList[0]);

		} else {
			return false;
		}

		while ($this->Database->NextRecord()) {
			$this->_sqlResult[] = $this->Database->Record;
			$this->_rowCount++;
		}

		// Run extra SQLs
		if (($this->_rowCount > 0) &&
			(empty($_customSQL) || (is_array($_customSQL) && (count($_customSQL) > 1)))) {
			if (is_array($_customSQL)) {
				$_extraStatementList = array_slice($_customSQL, 1);
			} else {
				$_extraStatementList = $this->KQLParserResult->GetExtraSQL();
			}

			foreach ($_extraStatementList as $_sql) {
				$this->Database->Query($_sql);

				while ($this->Database->NextRecord()) { // it should be a single row though
					$this->_sqlResult[] = $this->Database->Record;
					$this->_extraCount++;
				}
			}
		}

		return true;
	}

	/**
	 * Process the Array Keys for the SQL Result
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	protected function ProcessSQLResultTitle()
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		if (!isset($this->_sqlResult[0])) {
			return false;
		}

		$this->_sqlParsedTitles = array();

		$_functionList = SWIFT_KQL::GetCombinedFunctionList();

		$_arrayKeys = array_keys($this->_sqlResult[0]);

		$_finalSQLTitles = array(); // array(title, type, fieldpointer, function)

		foreach ($_arrayKeys as $_key => $_val) {
			if (!strstr($_val, '_')) {
				$_functionMatches = array();
				$_functionName = $_columnNameExtended = false;
				if (preg_match('/^(avg|min|max|sum)\((.*)\)$/i', $_val, $_functionMatches)) {
					$_functionName = $_functionMatches[1];
					$_columnNameExtended = $_functionMatches[2];

					$_tableFieldNameContainer = $this->KQL->GetTableAndFieldNameOnText($_columnNameExtended);
					$_tableNameParsed = $_tableFieldNameContainer[0];
					$_columnNameParsed = $_tableFieldNameContainer[1];

					if (isset($this->_schemaContainer[$_tableNameParsed][SWIFT_KQLSchema::SCHEMA_FIELDS][$_columnNameParsed])) {
						$_fieldContainer = $this->_schemaContainer[$_tableNameParsed][SWIFT_KQLSchema::SCHEMA_FIELDS][$_columnNameParsed];
						$_fieldTitle = $this->Language->Get($_tableNameParsed . '_' . $_columnNameParsed);
						if (empty($_fieldTitle)) {
							$_fieldTitle = $_val;
						}

						$_finalSQLTitles[$_val] = array($_fieldTitle, $_fieldContainer[SWIFT_KQLSchema::FIELD_TYPE], $_fieldContainer, false);

						continue;
					}
				}

				if (isset($this->_originalAliasesMap[$_val])) {
					$_finalSQLTitles[$_val] = array($this->_originalAliasesMap[$_val], false, false, false);
				} else {
					$_finalSQLTitles[$_val] = array($_val, false, false, false);
				}

				continue;
			}

			$_keyChunks = explode('_', strtolower($_val));
			$_tableName = $_columnName = '';

			// No chunks? Probably custom
			if (!count($_keyChunks)) {
				$_finalSQLTitles[$_val] = array($_val, false, false, false);

				continue;
			}

			// Is the first chunk the name of a function
			if (in_array($_keyChunks[0], $_functionList) && count($_keyChunks) == 3 && isset($this->_schemaContainer[$_keyChunks[1]]) && isset($this->_schemaContainer[$_keyChunks[1]][SWIFT_KQLSchema::SCHEMA_FIELDS][$_keyChunks[2]])) {
				$_tableName = $_keyChunks[1];
				$_columnName = $_keyChunks[2];

				$_fieldContainer = $this->_schemaContainer[$_keyChunks[1]][SWIFT_KQLSchema::SCHEMA_FIELDS][$_keyChunks[2]];
				$_fieldTitle = $this->Language->Get($_tableName . '_' . $_columnName);
				if (empty($_fieldTitle)) {
					$_fieldTitle = $_columnName;
				}

				$_finalSQLTitles[$_val] = array($_fieldTitle, $_fieldContainer[SWIFT_KQLSchema::FIELD_TYPE], $_fieldContainer, $_keyChunks[0]);

			// Is this a custom field
			} else if (count($_keyChunks) >= 3 && $_keyChunks[1] == 'cf' && isset($this->_customFields[$_keyChunks[2]])) {
				if ($_keyChunks[0] == '') { // Function name
					$_keyChunks[0] = false;
				}

				if (isset($_keyChunks[3])) { // IsSerialized & IsEncrypted field
					$_finalSQLTitles[$_val] = array($_keyChunks[3], SWIFT_KQLSchema::FIELDTYPE_BOOL, array(SWIFT_KQLSchema::FIELD_TYPE => SWIFT_KQLSchema::FIELDTYPE_BOOL), false);
				} else {
					$_fieldContainer = array();
					if ($this->_customFields[$_keyChunks[2]]['type'] == SWIFT_CustomField::TYPE_DATE) {
						$_fieldContainer[SWIFT_KQLSchema::FIELD_TYPE] = SWIFT_KQLSchema::FIELDTYPE_UNIXTIME;
					} else {
						$_fieldContainer[SWIFT_KQLSchema::FIELD_TYPE] = SWIFT_KQLSchema::FIELDTYPE_STRING;
					}

					if (isset($this->_customFields[$_keyChunks[2]]['alias'])) {
						$_fieldTitle = $this->_customFields[$_keyChunks[2]]['alias'];
					} else {
						$_fieldTitle = $this->_customFields[$_keyChunks[2]]['title'];
					}

					$_finalSQLTitles[$_val] = array($_fieldTitle, $_fieldContainer[SWIFT_KQLSchema::FIELD_TYPE], $_fieldContainer, $_keyChunks[0]);
				}

			} else if (count($_keyChunks) == 2 && isset($this->_schemaContainer[$_keyChunks[0]]) && isset($this->_schemaContainer[$_keyChunks[0]][SWIFT_KQLSchema::SCHEMA_FIELDS][$_keyChunks[1]])) {
				$_tableName = $_keyChunks[0];
				$_columnName = $_keyChunks[1];

				$_fieldContainer = $this->_schemaContainer[$_keyChunks[0]][SWIFT_KQLSchema::SCHEMA_FIELDS][$_keyChunks[1]];
				$_fieldTitle = $this->Language->Get($_tableName . '_' . $_columnName);
				if (empty($_fieldTitle)) {
					$_fieldTitle = $_columnName;
				}

				$_finalSQLTitles[$_val] = array($_fieldTitle, $_fieldContainer[SWIFT_KQLSchema::FIELD_TYPE], $_fieldContainer, false);

			} else {
				$_finalSQLTitles[$_val] = array($_val, false, false, false);
			}
		}

		$this->_sqlParsedTitles = $_finalSQLTitles;

		return true;
	}

	/**
	 * Process the Field Values for the SQL Result
	 *
	 * @author Andriy Lesyuk
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	protected function ProcessFieldValues()
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		if (!isset($this->_sqlResult[0])) {
			return false;
		}

		/**
		 * Process Field Values (using FIELD_PROCESSOR)
		 */

		$_processedFieldColumns = array();

		foreach ($this->_sqlResult[0] as $_columnName => $_columnValue) {
			$_columnExpression = $this->KQLObject->Compiler->GetExpressionByColumnName($_columnName);

			if ($_columnExpression[SWIFT_KQL2::EXPRESSION_TYPE] == SWIFT_KQL2::ELEMENT_FIELD) { // TODO: FUNC(table.field) etc
				$_fieldName = $_columnExpression[SWIFT_KQL2::EXPRESSION_DATA];

				if (isset($this->_schemaContainer[$_fieldName[0]]) &&
					isset($this->_schemaContainer[$_fieldName[0]][SWIFT_KQLSchema::SCHEMA_FIELDS][$_fieldName[1]])) {
					$_fieldProperties = $this->_schemaContainer[$_fieldName[0]][SWIFT_KQLSchema::SCHEMA_FIELDS][$_fieldName[1]];

					if (isset($_fieldProperties[SWIFT_KQLSchema::FIELD_PROCESSOR])) {
						$_processedFieldColumns[$_columnName] = $_fieldProperties[SWIFT_KQLSchema::FIELD_PROCESSOR];
					}
				}
			}
		}

		foreach ($_processedFieldColumns as $_columnName => $_fieldProcessor) {
			foreach ($this->_sqlResult as $_index => $_resultContainer) {
				if ($_index >= $this->_rowCount) {
					break;
				}

				$_columnValue = $this->_sqlResult[$_index][$_columnName];
				if ($_columnValue) {
					$this->_sqlResult[$_index][$_columnName] = $this->$_fieldProcessor($_columnValue, $_columnName, $_resultContainer);
				}
			}
		}

		for ($_sequentIndex = 0; isset($this->_sqlResult[$this->_rowCount + $_sequentIndex]); $_sequentIndex++) {
			foreach ($this->_sqlResult[$_sequentIndex] as $_columnName => $_columnValue) {
				$_columnExpression = $this->KQLObject->Compiler->GetExpressionByColumnName($_columnName, $_sequentIndex);

				if ($_columnExpression[SWIFT_KQL2::EXPRESSION_TYPE] == SWIFT_KQL2::ELEMENT_FIELD) { // TODO: FUNC(table.field) etc
					$_fieldName = $_columnExpression[SWIFT_KQL2::EXPRESSION_DATA];

					if (isset($this->_schemaContainer[$_fieldName[0]]) &&
						isset($this->_schemaContainer[$_fieldName[0]][SWIFT_KQLSchema::SCHEMA_FIELDS][$_fieldName[1]])) {
						$_fieldProperties = $this->_schemaContainer[$_fieldName[0]][SWIFT_KQLSchema::SCHEMA_FIELDS][$_fieldName[1]];

						if (isset($_fieldProperties[SWIFT_KQLSchema::FIELD_PROCESSOR])) {
							$this->_sqlResult[$_sequentIndex][$_columnName] = $this->$_fieldProperties[SWIFT_KQLSchema::FIELD_PROCESSOR]($_columnValue, $_columnName, $this->_sqlResult[$_sequentIndex]);
						}
					}
				}
			}
		}

		/**
		 * Process Custom Fields
		 */

		$_customFieldColumns = array();

		// Collect custom fields column names
		foreach ($this->_sqlResult[0] as $_columnName => $_columnValue) {
			$_keyChunks = explode('_', $_columnName);
			if ((count($_keyChunks) == 3) && ($_keyChunks[1] == 'cf')) {
				$_customFieldColumns[$_columnName] = $_keyChunks[2];
			}
		}

		$this->Load->Library('CustomField:CustomFieldManager');

		foreach ($_customFieldColumns as $_columnName => $_fieldID) { // FIXME: Move to a special processor
			foreach ($this->_sqlResult as $_index => $_resultContainer) {
				if ($_index >= $this->_rowCount) {
					break;
				}

				$_columnValue = $this->_sqlResult[$_index][$_columnName];
				if ($_columnValue) {
					$_isSerialized = $this->_sqlResult[$_index][$_columnName . '_isserialized'];
					$_isEncrypted = $this->_sqlResult[$_index][$_columnName . '_isencrypted'];

					$this->_sqlResult[$_index][$_columnName] = SWIFT_KQL::GetParsedCustomFieldValue($_columnValue, $this->_customFields[$_fieldID], ($_isEncrypted == '1'), ($_isSerialized == '1'));
				}
			}
		}

		return true;
	}

	/**
	 * Convert the Column Value Taking into Account Column Type
	 *
	 * @author Andriy Lesyuk
	 * @param string $_columnName
	 * @param string $_columnValue
	 * @param int $_rowIndex
	 * @return mixed The Column Value
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	protected function ConvertColumnValue($_columnName, $_columnValue, $_rowIndex = false)
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
		}

		if (is_null($_columnValue)) {
			return $_columnValue;
		}

		$_columnExpression = $this->KQLObject->Compiler->GetExpressionByColumnName($_columnName, $_rowIndex);

		if (!isset($_columnExpression[SWIFT_KQL2::EXPRESSION_RETURNTYPE])) {
			return $_columnValue;
		}

		switch ($_columnExpression[SWIFT_KQL2::EXPRESSION_RETURNTYPE])
		{
			case SWIFT_KQL2::DATA_BOOLEAN:
				if ($_columnValue == '1') {
					return true;
				} elseif ($_columnValue == '0') {
					return false;
				}
				break;

			case SWIFT_KQL2::DATA_INTEGER:
			case SWIFT_KQL2::DATA_SECONDS:
			case SWIFT_KQL2::DATA_UNIXDATE:
				if (is_numeric($_columnValue)) {
					return floatval($_columnValue);
				}
				break;

			case SWIFT_KQL2::DATA_FLOAT:
				if (is_numeric($_columnValue)) {
					return floatval($_columnValue);
				}
				break;

			case SWIFT_KQL2::DATA_TIME:
				$_secondsValue = SWIFT_Date::StringToSeconds($_columnValue);
				if ($_secondsValue !== false) {
					return $_secondsValue;
				}
				break;

			case SWIFT_KQL2::DATA_DATE:
				if (preg_match('/^([0-9]{4})-([0-9]{2})-([0-9]{2})$/', $_columnValue, $_matches)) {
					return mktime(0, 0, 0, intval($_matches[2]), intval($_matches[3]), intval($_matches[1]));
				}
				break;

			case SWIFT_KQL2::DATA_DATETIME:
				if (preg_match('/^([0-9]{4})-([0-9]{2})-([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2})$/', $_columnValue, $_matches)) {
					return mktime(intval($_matches[4]), intval($_matches[5]), intval($_matches[6]), intval($_matches[2]), intval($_matches[3]), intval($_matches[1]));
				}
				break;

			case SWIFT_KQL2::DATA_STRING:
				return strval($_columnValue);
				break;
		}

		return $_columnValue;
	}

	/**
	 * Sets Hidden Fields
	 *
	 * @author Andriy Lesyuk
	 * @param array The Hidden Fields
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function SetHiddenFields($_hiddenFields)
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$this->_hiddenFields = $_hiddenFields;

		return true;
	}

	/**
	 * Sets Custom Fields Properties
	 *
	 * @author Andriy Lesyuk
	 * @param array The Custom Fields
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function SetCustomFields($_customFields)
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$this->_customFields = $_customFields;

		return true;
	}

	/**
	 * Sets Original Aliases Map
	 *
	 * @author Andriy Lesyuk
	 * @param array The Original Aliases Map
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function SetOriginalAliasMap($_originalMap)
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$this->_originalAliasesMap = $_originalMap;

		return true;
	}

	/**
	 * Build a Count Map
	 *
	 * @author Varun Shoor, Andriy Lesyuk
	 * @return array The Count Map
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	protected function BuildSummaryCountMap()
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_summaryCountMap = array();
		$_rowMapRefList = array();

		$_summaryCountReference = false;
		$_fieldDisplayReferenceName = false;
		$_referenceIsDone = false;

		foreach ($this->_sqlResult as $_index => $_resultContainer) {
			if ($_index == $this->_rowCount) {
				break; // skip extra rows
			}

			foreach ($this->_sqlGroupByFields as $_groupByField) {
				$_fieldName = $_groupByField[0];
				$_fieldReferenceName = $_groupByField[1];
				$_fieldValue = $_resultContainer[$_fieldReferenceName];

				if ($_summaryCountReference === false) {
					$_summaryCountMap = array($_fieldReferenceName => array($_fieldValue => array('count' => 0, 'children' => array())));
					$_summaryCountReference = &$_summaryCountMap;
				}

				if (!isset($_summaryCountReference[$_fieldReferenceName][$_fieldValue])) {
					$_summaryCountReference[$_fieldReferenceName][$_fieldValue] = array('count' => 0, 'children' => array());
				}

				$_summaryCountReference[$_fieldReferenceName][$_fieldValue]['count']++;

				if ($_referenceIsDone === false && $_fieldDisplayReferenceName === false) {
					$_fieldDisplayReferenceName = $_fieldReferenceName;
				} else if ($_referenceIsDone === false) {
					$_fieldDisplayReferenceName .= '_' . $_fieldReferenceName;
				}

				if (!isset($_rowMapRefList[$_fieldDisplayReferenceName])) {
					$_rowMapRefList[$_fieldDisplayReferenceName] = 0;
				}

				$_rowMapRefList[$_fieldDisplayReferenceName]++;

				$_summaryCountReference = &$_summaryCountReference[$_fieldReferenceName][$_fieldValue]['children'];
			}

			// Reset the summary count reference to the first field
			$_summaryCountReference = &$_summaryCountMap;

			// Mark the render reference table as done
			$_referenceIsDone = true;
		}

		return $_summaryCountMap;
	}

	/**
	 * Sort SQL Result
	 *
	 * @author Varun Shoor, Andriy Lesyuk
	 * @return array Sorted SQL Result
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	protected function SortSummarySQLResult()
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_finalSQLResultContainer = array();

		$_resultIndex = 'a';
		foreach ($this->_sqlResult as $_index => $_resultContainer) {
			$_keyGroupText = false;

			foreach ($this->_sqlGroupByFields as $_groupByField) {
				$_fieldName = $_groupByField[0];
				$_fieldReferenceName = $_groupByField[1];
				$_fieldValue = $_resultContainer[$_fieldReferenceName];

				if ($_fieldValue === null) {
					$_fieldValue = '%null%';
				}

				if ($_keyGroupText === false) {
					$_keyGroupText = $_fieldValue;
				} else {
					$_keyGroupText .= $_fieldValue;
				}
			}

			$_finalKey = $_keyGroupText . $_resultIndex;

			$_finalSQLResultContainer[$_finalKey] = $_resultContainer;

			$_resultIndex++;
		}

		/*
		 * BUG FIX - Andriy Lesyuk
		 *
		 * SWIFT-2223 Reports: GROUP BY doesn't sort numeric columns with natsort
		 *
		 */
//		ksort($_finalSQLResultContainer, SORT_STRING);

		return $_finalSQLResultContainer;
	}

	/**
	 * Gets Report Filename
	 *
	 * @author Andriy Lesyuk
	 * @return string The Report File Name
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function GetFilename()
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_fileName = $this->Report->GetProperty('title');
		$_fileName = preg_replace('/[^a-z0-9]+/i', '_', $_fileName);
		$_fileName = trim($_fileName, '_');

		if ($_fileName != '') {
			$_fileName .= '_';
		}

		$_fileName .= strftime('%d-%b-%Y_%H-%M');

		return $_fileName;
	}

	/**
	 * Load Up the Data
	 *
	 * @author Varun Shoor, Andriy Lesyuk
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	protected function LoadMatrixData()
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_originalSQLs = $this->KQLParserResult->GetSQL();

		$_finalSQLs = array();
		$_extraSQLs = array();

		// Split into two arrays
		foreach ($_originalSQLs as $_statementKey => $_sqlStatement) {
			if (is_array($_sqlStatement)) {
				$_finalSQLs[] = array($_statementKey, array_shift($_sqlStatement));
				$_extraSQLs[] = array($_statementKey, $_sqlStatement);
			} else {
				$_finalSQLs[] = array($_statementKey, $_sqlStatement);
			}
		}

		// Append extra SQLs to the end
		if (!empty($_extraSQLs)) {
			$_finalSQLs = array_merge($_finalSQLs, $_extraSQLs);
		}

		foreach ($_finalSQLs as $_statementArray) {
			$_statementKey = $_statementArray[0];
			$_sqlStatement = $_statementArray[1];

			if (isset($this->_parentTitleIgnoreList[$_statementKey])) {
				continue;
			}

			// Execute the SQL Statement
			if (!$this->ExecuteSQL($_sqlStatement)) {
				continue;
			}

			if (!count($this->_sqlResult)) {
				$this->_parentTitleIgnoreList[$_statementKey] = $_statementKey;
			}

			// Process Array Keys into Titles
			if (!$this->ProcessSQLResultTitle()) {
				continue;
			}

			// Process Custom Field Values
			if (!$this->ProcessFieldValues()) {
				continue;
			}

			if (isset($this->_dataContainer[$_statementKey])) {
				$this->_dataContainer[$_statementKey]['results'] = array_merge($this->_dataContainer[$_statementKey]['results'], $this->_sqlResult);
			} else {
				$this->_dataContainer[$_statementKey] = array('title' => $this->_sqlParsedTitles, 'results' => $this->_sqlResult);
			}

			if ($this->_baseTitleContainer === false && count($this->_sqlResult)) {
				$this->_baseTitleContainer = $this->_sqlParsedTitles;
			}

			foreach ($this->_sqlParsedTitles as $_titleName => $_titleContainer) {
				if (isset($this->_groupFieldList[$_titleName]) || in_array($_titleName, $this->_baseUserFieldList)) {
					continue;
				}
				if (isset($this->_hiddenFields[$_titleName])) {
					continue;
				}

				$this->_baseUserFieldList[] = $_titleName;
			}

			foreach ($this->_sqlResult as $_resultsContainer) {
				foreach ($this->_sqlGroupByFields as $_groupByField) {
					$_fieldName = $_groupByField[0];
					$_fieldNameReference = $_groupByField[1];

					if (!isset($this->_distinctYGroupValuesList[$_fieldNameReference])) {
						$this->_distinctYGroupValuesList[$_fieldNameReference] = array();
					}

					if ($_resultsContainer[$_fieldNameReference] === null) {
						$_resultsContainer[$_fieldNameReference] = '';
					}

					if (isset($_resultsContainer[$_fieldNameReference]) && !in_array($_resultsContainer[$_fieldNameReference], $this->_distinctYGroupValuesList[$_fieldNameReference])) {
						$this->_distinctYGroupValuesList[$_fieldNameReference][] = $_resultsContainer[$_fieldNameReference];
					}
				}
			}
		}

		$this->_baseUserFieldCount = count($this->_baseUserFieldList);

		// Reset counts
		$this->_rowCount = 0;
		$this->_extraCount = $this->KQLObject->GetTotalRowCount();

		// Resort the distinct values
		foreach ($this->_sqlGroupByFields as $_groupByField) {
			$_fieldName = $_groupByField[0];
			$_fieldNameReference = $_groupByField[1];

			if (isset($this->_distinctYGroupValuesList[$_fieldNameReference])) {
				if ($this->_extraCount > 0) { // Sort only the part of the array
					$_distinctYGroupValuesList = array_slice($this->_distinctYGroupValuesList[$_fieldNameReference], 0, -$this->_extraCount);

					sort($_distinctYGroupValuesList);

					$this->_distinctYGroupValuesList[$_fieldNameReference] = array_merge($_distinctYGroupValuesList,
						array_slice($this->_distinctYGroupValuesList[$_fieldNameReference], $this->_extraCount));
				} else {
					sort($this->_distinctYGroupValuesList[$_fieldNameReference]);
				}
			}
		}

		return true;
	}

	/**
	 * Build the Y Map
	 *
	 * @author Varun Shoor, Andriy Lesyuk
	 * @return array The Y Map
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	protected function BuildMatrixYMap()
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_processedGroupByYMap = array();
		$_processedGroupByYResultsMap = array();

		$this->_replacementYKey = array('fields' => array(), 'key' => '');

		$this->BuildMatrixYGrid($this->_sqlGroupByFields, $_processedGroupByYMap, $_processedGroupByYResultsMap, $this->_replacementYKey);

		// We need to load up the render result container
		foreach ($_processedGroupByYResultsMap as $_value) {
			$this->_resultsContainerY[$_value] = false;
			$this->_groupByYCountMap[$_value] = 0;
		}

		$this->_replacementYKey = $this->_replacementYKey['key'];

		return $_processedGroupByYMap;
	}

	/**
	 * Build the Y Grid
	 *
	 * @author Varun Shoor
	 * @param array $_groupByYFields
	 * @param array $_processedGroupByMap
	 * @param array $_processedGroupByResultsMap
	 * @param string $_replacementYKey
	 * @param array $_nodeReference
	 * @param string $_keyPrefix
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	protected function BuildMatrixYGrid($_groupByYFields, &$_processedGroupByMap, &$_processedGroupByResultsMap, &$_replacementYKey, &$_nodeReference = false, $_keyPrefix = '')
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_fieldName = $_groupByYFields[0][0];
		$_fieldNameReference = $_groupByYFields[0][1];

		$_activeCount = $_childCount = 0;

		$_temporaryKeyList = array();

		if ($_nodeReference === false) {
			$_processedGroupByMap[$_fieldNameReference] = array();

			if (isset($this->_distinctYGroupValuesList[$_fieldNameReference])) {
				foreach ($this->_distinctYGroupValuesList[$_fieldNameReference] as $_distinctValue) {
					$_activeKeyPrefix = $_fieldNameReference . ':' . $_distinctValue;

					$_temporaryKeyList[] = $_activeKeyPrefix;

					$_processedGroupByMap[$_fieldNameReference][$_distinctValue] = array('count' => 0, 'childcount' => 0, 'children' => array(), 'key' => $_activeKeyPrefix);
				}
			}

			$_replacementYKey['key'] = $_fieldNameReference . ':%' . $_fieldNameReference . '%';
			$_replacementYKey['fields'][] = $_fieldNameReference;

			$_nodeReference = &$_processedGroupByMap;
		} else {
			if (!in_array($_fieldNameReference, $_replacementYKey['fields'])) {
				$_replacementYKey['key'] .= '_' . $_fieldNameReference . ':%' . $_fieldNameReference . '%';
				$_replacementYKey['fields'][] = $_fieldNameReference;
			}

			$_nodeReference[$_fieldNameReference] = array();

			foreach ($this->_distinctYGroupValuesList[$_fieldNameReference] as $_distinctValue) {
				$_activeKeyPrefix = $_keyPrefix . '_' . $_fieldNameReference . ':' . $_distinctValue;

				$_temporaryKeyList[] = $_activeKeyPrefix;

				$_nodeReference[$_fieldNameReference][$_distinctValue] = array('count' => 0, 'childcount' => 0, 'children' => array(), 'key' => $_activeKeyPrefix);
			}
		}

		$_childCount = count($_nodeReference[$_fieldNameReference]);

		if ($_nodeReference === false) {
			throw new SWIFT_Exception('Invalid Node Reference');
		}

		$_nextGroupByYFields = array_slice($_groupByYFields, 1);
		$_totalCount = 0;

		if (count($_nextGroupByYFields)) {
			foreach ($_nodeReference[$_fieldNameReference] as $_distinctValue => $_distinctValueContainer) {
				$_returnedCountContainer = $this->BuildMatrixYGrid($_nextGroupByYFields, $_processedGroupByMap, $_processedGroupByResultsMap, $_replacementYKey, $_nodeReference[$_fieldNameReference][$_distinctValue]['children'], $_nodeReference[$_fieldNameReference][$_distinctValue]['key']);

				$_returnedCount = $_returnedCountContainer[0];
				$_returnedChildCount = $_returnedCountContainer[1];

				$_nodeReference[$_fieldNameReference][$_distinctValue]['count'] = $_returnedCount;
				$_totalCount += $_returnedCount;

				$_nodeReference[$_fieldNameReference][$_distinctValue]['childcount'] += $_returnedChildCount;
				$_childCount += $_returnedChildCount;
			}

		// We are at last node
		} else {
			$_processedGroupByResultsMap = array_merge($_processedGroupByResultsMap, $_temporaryKeyList);
		}

		$_finalCount = $_activeCount+$_totalCount;

		return array($_finalCount, $_childCount);
	}

	/**
	 * Builds the X Grid
	 *
	 * @author Varun Shoor
	 * @param array $_groupByXFields
	 * @param array $_processedGroupByMap
	 * @param array $_nodeReference
	 * @param string $_keyPrefix
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	protected function BuildMatrixXGrid($_groupByXFields, &$_processedGroupByMap, &$_nodeReference = false, $_keyPrefix = '')
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_fieldName = $_groupByXFields[0][0];
		$_fieldNameReference = $_groupByXFields[0][1];

		$_activeCount = $_childCount = 0;

		if ($_nodeReference === false) {
			$_processedGroupByMap[$_fieldNameReference] = array();

			if (isset($this->_sqlDistinctValueContainer[$_fieldNameReference])) {
				foreach ($this->_sqlDistinctValueContainer[$_fieldNameReference] as $_distinctValue) {
					if (is_array($_distinctValue)) {
						$_activeKeyPrefix = $_fieldNameReference . ':' . $_distinctValue[0];
						$_distinctValue = $_distinctValue[1];
					} else {
						$_activeKeyPrefix = $_fieldNameReference . ':' . $_distinctValue;
					}

					$_processedGroupByMap[$_fieldNameReference][$_distinctValue] = array('count' => 0, 'childcount' => 0, 'children' => array(), 'key' => $_activeKeyPrefix);

					if (isset($this->_dataContainer[$_activeKeyPrefix])) {
						$_processedGroupByMap[$_fieldNameReference][$_distinctValue]['values'] = &$this->_dataContainer[$_activeKeyPrefix];
						$_processedGroupByMap[$_fieldNameReference][$_distinctValue]['count'] = count($this->_dataContainer[$_activeKeyPrefix]['results']);

						$_activeCount += $_processedGroupByMap[$_fieldNameReference][$_distinctValue]['count'];
					}
				}
			}

			$_nodeReference = &$_processedGroupByMap;
		} else {
			$_nodeReference[$_fieldNameReference] = array();

			foreach ($this->_sqlDistinctValueContainer[$_fieldNameReference] as $_distinctValue) {
				if (is_array($_distinctValue)) {
					$_activeKeyPrefix = $_keyPrefix . '_' . $_fieldNameReference . ':' . $_distinctValue[0];
					$_distinctValue = $_distinctValue[1];
				} else {
					$_activeKeyPrefix = $_keyPrefix . '_' . $_fieldNameReference . ':' . $_distinctValue;
				}

				$_nodeReference[$_fieldNameReference][$_distinctValue] = array('count' => 0, 'childcount' => 0, 'children' => array(), 'key' => $_activeKeyPrefix);

				if (isset($this->_dataContainer[$_activeKeyPrefix])) {
					$_nodeReference[$_fieldNameReference][$_distinctValue]['values'] = &$this->_dataContainer[$_activeKeyPrefix];
					$_nodeReference[$_fieldNameReference][$_distinctValue]['count'] = count($this->_dataContainer[$_activeKeyPrefix]['results']);

					$_activeCount += $_nodeReference[$_fieldNameReference][$_distinctValue]['count'];
				}
			}
		}

		$_childCount = count($_nodeReference[$_fieldNameReference]);

		if ($_nodeReference === false) {
			throw new SWIFT_Exception('Invalid Node Reference');
		}

		$_nextGroupByXFields = array_slice($_groupByXFields, 1);
		$_totalCount = 0;

		if (count($_nextGroupByXFields)) {
			foreach ($_nodeReference[$_fieldNameReference] as $_distinctValue => $_distinctValueContainer) {
				$_returnedCountContainer = $this->BuildMatrixXGrid($_nextGroupByXFields, $_processedGroupByMap, $_nodeReference[$_fieldNameReference][$_distinctValue]['children'], $_nodeReference[$_fieldNameReference][$_distinctValue]['key']);

				$_returnedCount = $_returnedCountContainer[0];
				$_returnedChildCount = $_returnedCountContainer[1];

				$_nodeReference[$_fieldNameReference][$_distinctValue]['count'] = $_returnedCount;
				$_totalCount += $_returnedCount;

				$_nodeReference[$_fieldNameReference][$_distinctValue]['childcount'] += $_returnedChildCount;
				$_childCount += $_returnedChildCount;
			}

		}

		$_finalCount = $_activeCount+$_totalCount;

		return array($_finalCount, $_childCount);
	}

	/**
	 * Cleans up the grid map array
	 *
	 * @author Varun Shoor
	 * @param array $_gridXMap
	 * @param array $_groupByXFields
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	protected function CleanupMatrixXGrid($_groupByXFields, &$_gridXMap)
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_fieldName = $_groupByXFields[0][0];
		$_fieldNameReference = $_groupByXFields[0][1];

		if (!isset($_gridXMap[$_fieldNameReference])) {
			return false;
		}

		foreach ($_gridXMap[$_fieldNameReference] as $_fieldValue => $_valueMap) {
			if ($_valueMap['count'] == 0) {
				unset($_gridXMap[$_fieldNameReference][$_fieldValue]);

				continue;
			}

			if (isset($_gridXMap[$_fieldNameReference][$_fieldValue]['children']) && count($_gridXMap[$_fieldNameReference][$_fieldValue]['children'])) {
				$this->CleanupMatrixXGrid(array_slice($_groupByXFields, 1), $_gridXMap[$_fieldNameReference][$_fieldValue]['children']);
			}
		}

		if (!count($_gridXMap[$_fieldNameReference])) {
			unset($_gridXMap[$_fieldNameReference]);
		}

		return true;
	}

	/**
	 * Recounts up the grid map array
	 *
	 * @author Varun Shoor
	 * @param array $_gridXMap
	 * @param array $_groupByXFields
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	protected function RecountMatrixXGrid($_groupByXFields, &$_gridXMap)
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_fieldName = $_groupByXFields[0][0];
		$_fieldNameReference = $_groupByXFields[0][1];

		if (!isset($_gridXMap[$_fieldNameReference])) {
			return 0;
		}

		$_finalCount = 0;

		/*
		 * BUG FIX - Andriy Lesyuk
		 *
		 * SWIFT-2034 Table heading breakage (invalid colspan)
		 *
		 * Comments: Changed algo for colspan calculation
		 */

		foreach ($_gridXMap[$_fieldNameReference] as $_fieldValue => $_valueMap) {
			if (isset($_gridXMap[$_fieldNameReference][$_fieldValue]['children']) && count($_gridXMap[$_fieldNameReference][$_fieldValue]['children'])) {
				$_returnCount = $this->RecountMatrixXGrid(array_slice($_groupByXFields, 1), $_gridXMap[$_fieldNameReference][$_fieldValue]['children']);

				$_gridXMap[$_fieldNameReference][$_fieldValue]['childcount'] = $_returnCount;

				$_finalCount += $_returnCount;
			} else {
				$_finalCount += 1;
			}
		}

		return $_finalCount;
	}

	/**
	 * Recounts Up the Grid Map Array
	 *
	 * @author Varun Shoor
	 * @param array $_gridYMap
	 * @param array $_groupByYFields
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	protected function RebuildMatrixCountForYGrid(&$_gridYMap, $_groupByYFields)
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_fieldName = $_groupByYFields[0][0];
		$_fieldNameReference = $_groupByYFields[0][1];

		if (!isset($_gridYMap[$_fieldNameReference])) {
			return 0;
		}

		$_finalCount = 0;

		foreach ($_gridYMap[$_fieldNameReference] as $_fieldValue => $_valueMap) {
			$_activeValueCount = 0;

			if (isset($this->_groupByYCountMap[$_valueMap['key']])) {
				$_activeValueCount = $this->_groupByYCountMap[$_valueMap['key']];
			}

			$_finalCount += $_activeValueCount;

			if (isset($_gridYMap[$_fieldNameReference][$_fieldValue]['children']) && count($_gridYMap[$_fieldNameReference][$_fieldValue]['children'])) {
				$_returnCount = $this->RebuildMatrixCountForYGrid($_gridYMap[$_fieldNameReference][$_fieldValue]['children'], array_slice($_groupByYFields, 1));

				$_gridYMap[$_fieldNameReference][$_fieldValue]['count'] = $_activeValueCount + $_returnCount;

				$_finalCount += $_returnCount;
			} else {
				$_gridYMap[$_fieldNameReference][$_fieldValue]['count'] = $_activeValueCount;
			}
		}

		return $_finalCount;
	}

	/**
	 * Cleans up the grid map array
	 *
	 * @author Varun Shoor
	 * @param array $_gridYMap
	 * @param array $_groupByYFields
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	protected function CleanupMatrixYGrid(&$_gridYMap, $_groupByYFields)
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_fieldName = $_groupByYFields[0][0];
		$_fieldNameReference = $_groupByYFields[0][1];

		if (!isset($_gridYMap[$_fieldNameReference])) {
			return false;
		}

		foreach ($_gridYMap[$_fieldNameReference] as $_fieldValue => $_valueMap) {
			if ($_valueMap['count'] == 0) {
				unset($_gridYMap[$_fieldNameReference][$_fieldValue]);

				continue;
			}

			if (isset($_gridYMap[$_fieldNameReference][$_fieldValue]['children']) && count($_gridYMap[$_fieldNameReference][$_fieldValue]['children'])) {
				$this->CleanupMatrixYGrid($_gridYMap[$_fieldNameReference][$_fieldValue]['children'], array_slice($_groupByYFields, 1));
			}
		}

		if (!count($_gridYMap[$_fieldNameReference])) {
			unset($_gridYMap[$_fieldNameReference]);
		}

		return true;
	}

	/**
	 * Recounts up the grid map array
	 *
	 * @author Varun Shoor
	 * @param array $_gridYMap
	 * @param array $_groupByYFields
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	protected function RecountMatrixYGrid(&$_gridYMap, $_groupByYFields)
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$_fieldName = $_groupByYFields[0][0];
		$_fieldNameReference = $_groupByYFields[0][1];

		if (!isset($_gridYMap[$_fieldNameReference])) {
			return 0;
		}

		$_finalCount = 0;

		/*
		 * BUG FIX - Andriy Lesyuk
		 *
		 * SWIFT-1856 Summary table report breakage in example report
		 *
		 * Comments: Changed algo (copied from RecountMatrixXGrid)
		 */

		foreach ($_gridYMap[$_fieldNameReference] as $_fieldValue => $_valueMap) {
			if (isset($_gridYMap[$_fieldNameReference][$_fieldValue]['children']) && count($_gridYMap[$_fieldNameReference][$_fieldValue]['children'])) {
				$_returnCount = $this->RecountMatrixYGrid($_gridYMap[$_fieldNameReference][$_fieldValue]['children'], array_slice($_groupByYFields, 1));

				$_gridYMap[$_fieldNameReference][$_fieldValue]['childcount'] = $_returnCount;

				$_finalCount += $_returnCount;
			} else {
				$_finalCount += 1;
			}
		}

		return $_finalCount;
	}

	/**
	 * Check to see if its a valid export format
	 *
	 * @author Parminder Singh
	 * @param constant $_exportFormat
	 * @return bool "true" on Success, "false" otherwise
	 */
	static public function IsValidExportFormat($_exportFormat)
	{
		return ($_exportFormat == self::EXPORT_EXCEL || $_exportFormat == self::EXPORT_EXCEL5 || $_exportFormat == self::EXPORT_CSV || $_exportFormat == self::EXPORT_HTML);
	}

	/**
	 * Increment the record count
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	protected function IncrementRecordCount()
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		$this->_recordCount++;

		return true;
	}

	/**
	 * Retrieves the record count
	 *
	 * @author Varun Shoor
	 * @return int The Record Count
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function GetRecordCount()
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		return $this->_recordCount;
	}

	/**
	 * Set PDO Session Time Zone to SWIFT Time Zone
	 *
	 * @author Andriy Lesyuk
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function SetSessionTimeZone()
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
		}

		$_mysqlTimeZone = $this->Database->QueryFetch('SELECT @@SESSION.time_zone AS time_zone');
		if ($_mysqlTimeZone && isset($_mysqlTimeZone['time_zone'])) {
			$this->_backupTimeZone = $_mysqlTimeZone['time_zone'];
		}

		$_swiftTimeZone = SWIFT::Get('timezone');

		$_SWIFT_StaffObject = self::GetStaff();
		if ($_SWIFT_StaffObject->GetProperty('timezonephp') != '') {
			$_swiftTimeZone = $_SWIFT_StaffObject->GetProperty('timezonephp');
		}

		if ($_swiftTimeZone) {
			$_timeZoneObject = new DateTimeZone($_swiftTimeZone);
			if ($_timeZoneObject) {

				$_secondsOffset = $_timeZoneObject->getOffset(new DateTime());
				$_newTimeZone = sprintf("%s%02d:%02d", ($_secondsOffset < 0) ? '-' : '+', floor(abs($_secondsOffset) / 3600), floor((abs($_secondsOffset) % 3600) / 60));

				$this->Database->Query("SET SESSION TIME_ZONE = '" . $this->Database->Escape($_newTimeZone) . "'");
			} else {
				$this->_backupTimeZone = false;

				return false;
			}
		} else {
			$this->_backupTimeZone = false;

			return false;
		}

		return true;
	}

	/**
	 * Restore PDO Session Time Zone to the Previous Value
	 *
	 * @author Andriy Lesyuk
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function RestoreSessionTimeZone()
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
		}

		if ($this->_backupTimeZone) {
			$this->Database->Query("SET SESSION TIME_ZONE = '" . $this->Database->Escape($this->_backupTimeZone) . "'");
		}

		return true;
	}

	/**
	 * Retrieve Staff Running the Report
	 *
	 * @author Andriy Lesyuk
	 * @return SWIFT_Staff The Staff Running Report
	 */
	static public function GetStaff()
	{
		if (SWIFT::Get('schedulestaffid')) {
			$_SWIFT_StaffObject = new SWIFT_Staff(new SWIFT_DataID(SWIFT::Get('schedulestaffid')));

			if ($_SWIFT_StaffObject instanceof SWIFT_Staff && $_SWIFT_StaffObject->GetIsClassLoaded()) {
				return $_SWIFT_StaffObject;
			}
		} else {
			$_SWIFT = SWIFT::GetInstance();

			return $_SWIFT->Staff;
		}

		return false;
	}

	/**
	 * Determine the Format of Report
	 *
	 * @author Andriy Lesyuk
	 * @return constant The Report Type
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	protected function GetFormat()
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
		}

		return self::EXPORT_CSV;
	}

	/**
	 * Removes HTML tags from the string
	 *
	 * @author Andriy Lesyuk
	 * @param mixed $_fieldValue
	 * @param string $_columnName
	 * @param array $_results
	 * @return string
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	protected function Field_ProcessHTMLContents($_fieldValue, $_columnName = false, $_results = array())
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
		}

		if (isset($_results[$_columnName . '_ishtml']) && $_results[$_columnName . '_ishtml']) {
			$_fieldValue = SWIFT_TicketPost::GetParsedContents($_fieldValue, 'strip', true, '');
		}

		return $_fieldValue;
	}

	/**
	 * Renders Link in the Report
	 *
	 * @author Andriy Lesyuk
	 * @param mixed $_fieldValue
	 * @param string $_fieldURL
	 * @param array $_additionalInfo
	 * @return mixed String or True
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	protected function WriteFieldURL($_fieldValue, $_fieldURL, $_additionalInfo = array())
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
		}

		switch ($this->GetFormat())
		{
			case self::EXPORT_HTML:
				return '<a href="' . htmlspecialchars($_fieldURL) . '">' . $_fieldValue . '</a>';
				break;

			case self::EXPORT_EXCEL:
			case self::EXPORT_EXCEL5:
				if (isset($_additionalInfo['columnIndex'])) {
					$this->_workSheet->getCellByColumnAndRow($_additionalInfo['columnIndex'], $this->GetRecordCount() + 1)->getHyperlink()->setUrl($_fieldURL);

					return true;
				} else {
					return false;
				}
				break;
		}

		return $_fieldValue;
	}

	/**
	 * Renders Link to the Ticket for the Ticket Mask ID
	 *
	 * @author Andriy Lesyuk
	 * @param mixed $_fieldValue
	 * @param string|bool $_columnName
	 * @param array $_results
	 * @param array $_additionalInfo
	 * @return mixed String or True
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	protected function Field_WriteTicketMaskID($_fieldValue, $_columnName = false, $_results = array(), $_additionalInfo = array())
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
		}
		/**
		 * BUG FIX : Nidhi Gupta <nidhi.gupta@kayako.com>
		 *
		 * SWIFT-4036: Incorrect ticket URL in scheduled report
		 *
		 * Comments: Replaced interfaces with staff.
		 */
		$_baseURL = str_replace(['/cron/', '/console/', '/admin/', '/api/'], '/staff/', SWIFT::Get('basename'));

		if (isset($_results[$_columnName . '_ticketid'])) {
			$_ticketURL = $_baseURL . '/Tickets/Ticket/View/' . $_results[$_columnName . '_ticketid'];
		} else {
			$_ticketURL = $_baseURL . '/Tickets/Ticket/View/' . $_fieldValue;
		}

		return $this->WriteFieldURL($_fieldValue, $_ticketURL, $_additionalInfo);
	}

	/**
	 * Renders Link to the Ticket for the Ticket ID
	 *
	 * @author Andriy Lesyuk
	 * @param mixed $_fieldValue
	 * @param string|bool $_columnName
	 * @param array $_results
	 * @param array $_additionalInfo
	 * @return mixed String or True
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	protected function Field_WriteTicketID($_fieldValue, $_columnName = false, $_results = array(), $_additionalInfo = array())
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
		}
		/**
		 * BUG FIX : Nidhi Gupta <nidhi.gupta@kayako.com>
		 *
		 * SWIFT-4036: Incorrect ticket URL in scheduled report
		 *
		 * Comments: Replaced interfaces with staff.
		 */
		$_baseURL = str_replace(['/cron/', '/console/', '/admin/', '/api/'], '/staff/', SWIFT::Get('basename'));

		$_ticketURL = $_baseURL . '/Tickets/Ticket/View/' . $_fieldValue;

		return $this->WriteFieldURL($_fieldValue, $_ticketURL, $_additionalInfo);
	}

	/**
	 * Renders Link to the Chat for the Chat Mask ID
	 *
	 * @author Andriy Lesyuk
	 * @param mixed $_fieldValue
	 * @param string|bool $_columnName
	 * @param array $_results
	 * @param array $_additionalInfo
	 * @return mixed String or True
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	protected function Field_WriteChatMaskID($_fieldValue, $_columnName = false, $_results = array(), $_additionalInfo = array())
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
		}
		/**
		 * BUG FIX : Nidhi Gupta <nidhi.gupta@kayako.com>
		 *
		 * SWIFT-4036: Incorrect ticket URL in scheduled report
		 *
		 * Comments: Replaced interfaces with staff.
		 */
		$_baseURL = str_replace(['/cron/', '/console/', '/admin/', '/api/'], '/staff/', SWIFT::Get('basename'));

		if (isset($_results[$_columnName . '_chatobjectid'])) {
			$_chatURL = $_baseURL . '/LiveChat/ChatHistory/ViewChat/' . $_results[$_columnName . '_chatobjectid'];

			return $this->WriteFieldURL($_fieldValue, $_chatURL, $_additionalInfo);
		}

		return $_fieldValue;
	}

	/**
	 * Renders Link to the Chat for the Chat ID
	 *
	 * @author Andriy Lesyuk
	 * @param mixed $_fieldValue
	 * @param string|bool $_columnName
	 * @param array $_results
	 * @param array $_additionalInfo
	 * @return mixed String or True
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	protected function Field_WriteChatID($_fieldValue, $_columnName = false, $_results = array(), $_additionalInfo = array())
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
		}
		/**
		 * BUG FIX : Nidhi Gupta <nidhi.gupta@kayako.com>
		 *
		 * SWIFT-4036: Incorrect ticket URL in scheduled report
		 *
		 * Comments: Replaced interfaces with staff.
		 */
		$_baseURL = str_replace(['/cron/', '/console/', '/admin/', '/api/'], '/staff/', SWIFT::Get('basename'));

		$_chatURL = $_baseURL . '/LiveChat/ChatHistory/ViewChat/' . $_fieldValue;

		return $this->WriteFieldURL($_fieldValue, $_chatURL, $_additionalInfo);
	}

	/**
	 * Renders Link to the Message for the Message Mask ID
	 *
	 * @author Andriy Lesyuk
	 * @param mixed $_fieldValue
	 * @param string|bool $_columnName
	 * @param array $_results
	 * @param array $_additionalInfo
	 * @return mixed String or True
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	protected function Field_WriteMessageMaskID($_fieldValue, $_columnName = false, $_results = array(), $_additionalInfo = array())
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
		}
		/**
		 * BUG FIX : Nidhi Gupta <nidhi.gupta@kayako.com>
		 *
		 * SWIFT-4036: Incorrect ticket URL in scheduled report
		 *
		 * Comments: Replaced interfaces with staff.
		 */
		$_baseURL    = str_replace(['/cron/', '/console/', '/admin/', '/api/'], '/staff/', SWIFT::Get('basename'));

		if (isset($_results[$_columnName . '_messageid'])) {
			$_messageURL = $_baseURL . '/LiveChat/Message/ViewMessage/' . $_results[$_columnName . '_messageid'];

			return $this->WriteFieldURL($_fieldValue, $_messageURL, $_additionalInfo);
		}

		return $_fieldValue;
	}

	/**
	 * Renders Link to the Message for the Message ID
	 *
	 * @author Andriy Lesyuk
	 * @param mixed $_fieldValue
	 * @param string|bool $_columnName
	 * @param array $_results
	 * @param array $_additionalInfo
	 * @return mixed String or True
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	protected function Field_WriteMessageID($_fieldValue, $_columnName = false, $_results = array(), $_additionalInfo = array())
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
		}
		/**
		 * BUG FIX : Nidhi Gupta <nidhi.gupta@kayako.com>
		 *
		 * SWIFT-4036: Incorrect ticket URL in scheduled report
		 *
		 * Comments: Replaced interfaces with staff.
		 */
		$_baseURL    = str_replace(['/cron/', '/console/', '/admin/', '/api/'], '/staff/', SWIFT::Get('basename'));

		$_messageURL = $_baseURL . '/LiveChat/Message/ViewMessage/' . $_fieldValue;

		return $this->WriteFieldURL($_fieldValue, $_messageURL, $_additionalInfo);
	}

}
