<?php
/*********************************************************************************
 * TimeTrex is a Payroll and Time Management program developed by
 * TimeTrex Payroll Services Copyright (C) 2003 - 2011 TimeTrex Payroll Services.
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by
 * the Free Software Foundation with the addition of the following permission
 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
 * WORK IN WHICH THE COPYRIGHT IS OWNED BY TIMETREX, TIMETREX DISCLAIMS THE
 * WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License along
 * with this program; if not, see http://www.gnu.org/licenses or write to the Free
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301 USA.
 *
 * You can contact TimeTrex headquarters at Unit 22 - 2475 Dobbin Rd. Suite
 * #292 Westbank, BC V4T 2E9, Canada or at email address info@timetrex.com.
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public License
 * version 3, these Appropriate Legal Notices must retain the display of the
 * "Powered by TimeTrex" logo. If the display of the logo is not reasonably
 * feasible for technical reasons, the Appropriate Legal Notices must display
 * the words "Powered by TimeTrex".
 ********************************************************************************/
/*
 * $Revision: 2095 $
 * $Id: Sort.class.php 2095 2008-09-01 07:04:25Z ipso $
 * $Date: 2008-09-01 00:04:25 -0700 (Mon, 01 Sep 2008) $
 */

/**
 * @package Core
 */
class PayrollExportReport extends TimesheetSummaryReport {

	function __construct() {
		$this->title = TTi18n::getText('Payroll Export Report');
		$this->file_name = 'payroll_export';

		//Don't call TimesheetSummaryReport __construct(), skip one level lower to the Report class instead.
		Report::__construct();

		return TRUE;
	}

	protected function _checkPermissions( $user_id, $company_id ) {
		if ( $this->getPermissionObject()->Check('report','enabled', $user_id, $company_id )
				AND $this->getPermissionObject()->Check('report','view_payroll_export', $user_id, $company_id ) ) {
			return TRUE;
		}

		return FALSE;
	}

	protected function _getOptions( $name, $params = NULL ) {
		$retval = NULL;
		switch( $name ) {
			case 'export_type':
				$retval = array(
								0 => TTi18n::gettext('-- Please Choose --'),
								'adp' 				=> TTi18n::gettext('ADP'),
								'paychex_preview' 	=> TTi18n::gettext('Paychex Preview'),
								'paychex_online' 	=> TTi18n::gettext('Paychex Online Payroll'),
								'ceridian_insync' 	=> TTi18n::gettext('Ceridian Insync'),
								'millenium' 		=> TTi18n::gettext('Millenium'),
								'quickbooks' 		=> TTi18n::gettext('QuickBooks Pro'),
								'surepayroll' 		=> TTi18n::gettext('SurePayroll'),
								'csv' 				=> TTi18n::gettext('Generic Excel/CSV'),
								//'other' 			=> TTi18n::gettext('-- Other --'),
								);
				break;
			case 'export_policy':
				$static_columns = array();

				$columns = array(					'-0010-regular_time' => TTi18n::gettext('Regular Time'),
													);

				$columns = Misc::prependArray( $static_columns, $columns);

				//Get all Overtime policies.
				$otplf = TTnew( 'OverTimePolicyListFactory' );
				$otplf->getByCompanyId( $this->getUserObject()->getCompany() );
				if ( $otplf->getRecordCount() > 0 ) {
					foreach ($otplf as $otp_obj ) {
						$otp_columns['-0020-over_time_policy-'.$otp_obj->getId()] = TTi18n::gettext('Overtime').': '.$otp_obj->getName();
					}

					$columns = array_merge( $columns, $otp_columns);
				}

				//Get all Premium policies.
				$pplf = TTnew( 'PremiumPolicyListFactory' );
				$pplf->getByCompanyId( $this->getUserObject()->getCompany() );
				if ( $pplf->getRecordCount() > 0 ) {
					foreach ($pplf as $pp_obj ) {
						$pp_columns['-0030-premium_policy-'.$pp_obj->getId()] = TTi18n::gettext('Premium').': '.$pp_obj->getName();
					}

					$columns = array_merge( $columns, $pp_columns);
				}


				//Get all Absence Policies.
				$aplf = TTnew( 'AbsencePolicyListFactory' );
				$aplf->getByCompanyId( $this->getUserObject()->getCompany() );
				if ( $aplf->getRecordCount() > 0 ) {
					foreach ($aplf as $ap_obj ) {
						$ap_columns['-0040-absence_policy-'.$ap_obj->getId()] = TTi18n::gettext('Absence').': '.$ap_obj->getName();
					}

					$columns = array_merge( $columns, $ap_columns);
				}

				$retval = $columns;
				break;
			case 'default_hour_codes':
				$export_type = $this->getOptions('export_type');
				$export_policy = Misc::trimSortPrefix( $this->getOptions('export_policy') );

				foreach( $export_type as $type => $name ) {
					switch( strtolower($type) ) {
						case 'paychex_online':
							foreach( $export_policy as $id => $name ) {
								if ( strpos( $id, 'regular') !== FALSE ) {
									$retval[$type]['columns'][$id]['hour_code'] = 'Regular';
								} elseif ( strpos( $id, 'over_time') !== FALSE ) {
									$retval[$type]['columns'][$id]['hour_code'] = 'Overtime';
								} elseif ( strpos( $id, 'absence') !== FALSE ) {
									$retval[$type]['columns'][$id]['hour_code'] = 'Absence';
								}
							}

							break;
						default:
							if ( $type === 0 ) {
								continue;
							}

							foreach( $export_policy as $id => $name ) {
								if ( strpos( $id, 'regular') !== FALSE ) {
									$retval[$type]['columns'][$id]['hour_code'] = 'REG';
								} elseif ( strpos( $id, 'over_time') !== FALSE ) {
									$retval[$type]['columns'][$id]['hour_code'] = 'OT';
								} elseif ( strpos( $id, 'absence') !== FALSE ) {
									$retval[$type]['columns'][$id]['hour_code'] = 'ABS';
								}
							}
						break;
					}
				}
				break;
			case 'hour_column_name':
				$hour_column_name_map = array(
								'adp' 				=> TTi18n::gettext('ADP Hours Code'),
								'paychex_preview' 	=> TTi18n::gettext('Paychex Hours Code'),
								'paychex_online' 	=> TTi18n::gettext('Paychex Hours Code'),
								'ceridian_insync' 	=> TTi18n::gettext('Ceridian Hours Code'),
								'millenium' 		=> TTi18n::gettext('Millenium Hours Code'),
								'quickbooks' 		=> TTi18n::gettext('Quickbooks Payroll Item Name'),
								'surepayroll' 		=> TTi18n::gettext('Payroll Code'),
								'csv' 				=> TTi18n::gettext('Hours Code'),
								);

				if (  isset($params['export_type']) AND isset($hour_column_name_map[$params['export_type']]) ) {
					$retval = $hour_column_name_map[$params['export_type']];
				} else {
					$retval = $hour_column_name_map['csv'];
				}
				break;
			case 'adp_hour_column_options':
				$retval['adp_hour_column_options'][0] = TTi18n::gettext('-- DO NOT EXPORT --');
				$retval['adp_hour_column_options']['regular_time'] = TTi18n::gettext('Regular Time');
				$retval['adp_hour_column_options']['overtime'] = TTi18n::gettext('Overtime');
				for ( $i=3; $i <= 4; $i++ ) {
					$retval['adp_hour_column_options'][$i] = TTi18n::gettext('Hours') .' '. $i;
				}
				break;
			case 'quickbooks_proj_options':
				$retval = array(
								0 => TTi18n::gettext('-- NONE --'),
								'default_branch' => TTi18n::gettext('Default Branch'),
								'default_department' => TTi18n::gettext('Default Department'),
								'group' => TTi18n::gettext('Group'),
								'title' => TTi18n::gettext('Title'),
								);
				break;
			default:
				return parent::_getOptions( $name, $params );
				break;
		}

		return $retval;
	}

	function getExportTypeTemplate( $config, $format ) {

		if ( $format == 'payroll_export' ) {
			unset($config['columns'],$config['group'],$config['sort'],$config['sub_total']);
			$config['other']['disable_grand_total'] = TRUE; //Disable grand totals.

			if ( isset($config['form']['export_type']) ) {
				$export_type = $config['form']['export_type'];

				switch( strtolower($export_type) ) {
					case 'adp':
					case 'paychex_preview':
					case 'paychex_online':
					case 'millenium':
					case 'quickbooks':
					case 'ceridian_insync':
						$config['columns'][] = 'employee_number';
						$config['columns'] += Misc::trimSortPrefix( $this->getOptions('dynamic_columns') );

						$config['group'][] = 'employee_number';

						$config['sort'][] = array('employee_number' => 'asc');
						break;
					case 'surepayroll':
						$config['columns'][] = 'pay_period_end_date';
						$config['columns'][] = 'employee_number';
						$config['columns'][] = 'last_name';
						$config['columns'][] = 'first_name';
						$config['columns'] += Misc::trimSortPrefix( $this->getOptions('dynamic_columns') );

						$config['group'][] = 'pay_period_end_date';
						$config['group'][] = 'employee_number';
						$config['group'][] = 'last_name';
						$config['group'][] = 'first_name';

						$config['sort'][] = array('pay_period_end_date' => 'asc', 'employee_number' => 'asc', 'last_name' => 'asc', 'first_name' => 'asc');
						break;
					case 'csv':
						$config['columns'][] = 'full_name';
						$config['columns'][] = 'employee_number';
						$config['columns'][] = 'default_branch';
						$config['columns'][] = 'default_department';
						$config['columns'][] = 'pay_period';
						$config['columns'] += Misc::trimSortPrefix( $this->getOptions('dynamic_columns') );

						$config['group'][] = 'full_name';
						$config['group'][] = 'employee_number';
						$config['group'][] = 'default_branch';
						$config['group'][] = 'default_department';
						$config['group'][] = 'pay_period';

						$config['sort'][] = array('full_name' => 'asc', 'employee_number' => 'asc', 'default_branch' => 'asc', 'default_department' => 'asc', 'pay_period' => 'asc');
						break;
				}
				Debug::Arr($config, 'Export Type Template: '. $export_type, __FILE__, __LINE__, __METHOD__,10);
			} else {
				Debug::Text('No Export Type defined, not modifying config...', __FILE__, __LINE__, __METHOD__,10);
			}
		}

		return $config;
	}

	//Short circuit this function, as no postprocessing is required for exporting the data.
	function _postProcess( $format = NULL ) {
		if ( $format == 'payroll_export' ) {
			return TRUE;
		} else {
			return parent::_postProcess( $format );
		}
	}

	function _outputPayrollExport( $format = NULL ) {
		$setup_data = $this->getFormConfig();

		Debug::Text('Generating Payroll Export... Format: '. $format, __FILE__, __LINE__, __METHOD__,10);

		if ( isset($setup_data['export_type']) ) {
			Debug::Text('Export Type: '. $setup_data['export_type'], __FILE__, __LINE__, __METHOD__,10);
		} else {
			Debug::Text('No Export Type defined!', __FILE__, __LINE__, __METHOD__,10);
			return FALSE;
		}

		$rows = $this->data;
		Debug::Arr($rows, 'PreData: ', __FILE__, __LINE__, __METHOD__,10);

		$file_name = strtolower(trim($setup_data['export_type'])).'_'.date('Y_m_d').'.txt';
		$mime_type = 'application/text';
		$data = NULL;

		switch( strtolower(trim($setup_data['export_type'])) ) {
			case 'adp': //ADP export format.
				$file_name = 'EPI'. $setup_data['adp']['company_code'] . $setup_data['adp']['batch_id'] .'.csv';

				$export_column_map = array();
				$static_export_column_map = array(
										'company_code' => 'Co Code',
										'batch_id' => 'Batch ID',
										'employee_number' =>  'File #',
										);

				$static_export_data_map = array(
								'company_code' => $setup_data['adp']['company_code'],
								'batch_id' => $setup_data['adp']['batch_id'],
								);

				//
				//Format allows for multiple duplicate columns.
				//ie: Hours 3 Code, Hours 3 Amount, Hours 3 Code, Hours 3 Amount, ...
				//However, we can only have a SINGLE O/T Hours column.
				//We also need to combine hours with the same code together.
				//
				ksort($setup_data['adp']['columns']);
				$setup_data['adp']['columns'] = Misc::trimSortPrefix( $setup_data['adp']['columns'] );

				foreach( $setup_data['adp']['columns'] as $column_id => $column_data ) {
					$column_name = NULL;
					if ( $column_data['hour_column'] == 'regular_time' ) {
						$column_name = 'Reg Hours';
						$export_data_map[$column_id] = trim($setup_data['adp']['columns'][$column_id]['hour_code']);
					} elseif ($column_data['hour_column'] == 'overtime' ) {
						$column_name = 'O/T Hours';
						$export_data_map[$column_id] = trim($setup_data['adp']['columns'][$column_id]['hour_code']);
					} elseif ( $column_data['hour_column'] >= 3 ) {
						$column_name = 'Hours '. $column_data['hour_column'] .' Amount';
						$export_column_map[$setup_data['adp']['columns'][$column_id]['hour_code'].'_code'] = 'Hours '. $column_data['hour_column'] .' Code';
						$export_data_map[$column_id] = trim($setup_data['adp']['columns'][$column_id]['hour_code']);
					}

					if ( $column_name != '' ) {
						$export_column_map[trim($setup_data['adp']['columns'][$column_id]['hour_code'])] = $column_name;
					}
				}
				$export_column_map = Misc::prependArray( $static_export_column_map, $export_column_map);

				//
				//Combine time from all columns with the same hours code.
				//
				$i=0;
				foreach($rows as $row) {
					foreach ( $static_export_column_map as $column_id => $column_name ) {
						if ( isset($static_export_data_map[$column_id]) ) {
							//Copy over static config values like company code/batch_id.
							$tmp_rows[$i][$column_id] = $static_export_data_map[$column_id];
						} elseif( isset($row[$column_id]) ) {
							if ( isset($static_export_column_map[$column_id]) ) {
								//Copy over employee_number. (File #)
								$tmp_rows[$i][$column_id] = $row[$column_id];
							}
						}
					}

					foreach ( $export_data_map as $column_id => $column_name ) {
						if ( !isset($tmp_rows[$i][$column_name]) ) {
							$tmp_rows[$i][$column_name] = 0;
						}

						if ( isset($row[$column_id]) ) {
							$tmp_rows[$i][$column_name] += $row[$column_id];
						}
						$tmp_rows[$i][$column_name.'_code']  = $column_name;
					}

					$i++;
				}

				//Convert time from seconds to hours.
				$convert_unit_columns = array_keys($static_export_column_map);

				foreach( $tmp_rows as $row => $data ) {
					foreach( $data as $column_id => $column_data ) {
						//var_dump($column_id,$column_data);
						if ( is_int($column_data) AND !in_array( $column_id, $convert_unit_columns ) ) {
							$tmp_rows[$row][$column_id] = TTDate::getTimeUnit( $column_data, 20 );
						}
					}
				}
				unset($row, $data, $column_id, $column_data);

				$data = Misc::Array2CSV( $tmp_rows, $export_column_map, FALSE );

				break;
			case 'paychex_preview': //Paychex Preview export format.
				//Add an advanced PayChex Previous format that supports rates perhaps?
				if ( !isset($setup_data['paychex_preview']['client_number']) ) {
					$setup_data['paychex_preview']['client_number'] = '0000';
				}

				$file_name = $setup_data['paychex_preview']['client_number'] .'_TA.txt';

				ksort($setup_data['paychex_preview']['columns']);
				$setup_data['paychex_preview']['columns'] = Misc::trimSortPrefix( $setup_data['paychex_preview']['columns'] );

				$data = NULL;
				foreach($rows as $row) {
					foreach( $setup_data['paychex_preview']['columns'] as $column_id => $column_data ) {
						if ( isset( $row[$column_id] ) AND trim($column_data['hour_code']) != '' ) {
							$data .= str_pad($row['employee_number'], 6, ' ', STR_PAD_LEFT);
							$data .= str_pad('E'. str_pad( $column_data['hour_code'], 2, 0, STR_PAD_LEFT) , 47, ' ', STR_PAD_LEFT);
							$data .= str_pad( str_pad( TTDate::getTimeUnit( $row[$column_id], 20 ), 8, 0, STR_PAD_LEFT) , 17, ' ', STR_PAD_LEFT)."\n";
						}
					}
				}
				break;
			case 'paychex_online': //Paychex Online Payroll CSV
				ksort($setup_data['paychex_online']['columns']);
				$setup_data['paychex_online']['columns'] = Misc::trimSortPrefix( $setup_data['paychex_online']['columns'] );

				$earnings = array();
				//Find all the hours codes
				foreach( $setup_data['paychex_online']['columns'] as $column_id => $column_data ) {
					$hour_code = $column_data['hour_code'];
					$earnings[] = $hour_code;
				}

				$export_column_map['employee_number'] = '';
				foreach($earnings as $key => $value) {
					$export_column_map[$value] = '';
				}

				$i=0;
				foreach($rows as $row) {
					if ( $i == 0 ) {
						//Include header.
						$tmp_row['employee_number'] = 'Employee Number';
						foreach($earnings as $key => $value) {
							$tmp_row[$value] = $value . ' Hours';
						}
						$tmp_rows[] = $tmp_row;
						unset($tmp_row);
					}

					//Combine all hours from the same code together.
					foreach( $setup_data['paychex_online']['columns'] as $column_id => $column_data ) {
						$hour_code = trim($column_data['hour_code']);
						if ( isset( $row[$column_id] ) AND $hour_code != '' ) {
							if ( !isset($tmp_hour_codes[$hour_code]) ) {
								$tmp_hour_codes[$hour_code] = 0;
							}
							$tmp_hour_codes[$hour_code] = bcadd( $tmp_hour_codes[$column_data['hour_code']], $row[$column_id] ); //Use seconds for math here.
						}
					}

					if ( isset($tmp_hour_codes) ) {
						$tmp_row['employee_number'] = $row['employee_number'];
						foreach($tmp_hour_codes as $hour_code => $hours ) {
							$tmp_row[$hour_code] = TTDate::getTimeUnit($hours, 20);
						}
						$tmp_rows[] = $tmp_row;
						unset($tmp_hour_codes, $hour_code, $hours, $tmp_row);
					}

					$i++;
				}

				if ( isset( $tmp_rows) ) {
					$data = Misc::Array2CSV( $tmp_rows, $export_column_map, FALSE, FALSE );
				}
				unset($tmp_rows, $export_column_map, $column_id, $column_data, $rows, $row);
				break;
			case 'millenium': //Millenium export format. Also used by Qqest.
				ksort($setup_data['millenium']['columns']);
				$setup_data['millenium']['columns'] = Misc::trimSortPrefix( $setup_data['millenium']['columns'] );

				$export_column_map = array('employee_number' => '', 'transaction_code' => '', 'hour_code' => '', 'hours' => '');
				foreach($rows as $row) {
					foreach( $setup_data['millenium']['columns'] as $column_id => $column_data ) {
						if ( isset( $row[$column_id] ) AND trim($column_data['hour_code']) != '' ) {
							$tmp_rows[] = array(
												'employee_number' => $row['employee_number'],
												'transaction_code' => 'E',
												'hour_code' => trim($column_data['hour_code']),
												'hours' => TTDate::getTimeUnit( $row[$column_id], 20 )
												);
						}
					}
				}

				if ( isset( $tmp_rows) ) {
					$data = Misc::Array2CSV( $tmp_rows, $export_column_map, FALSE, FALSE );
				}
				unset($tmp_rows, $export_column_map, $column_id, $column_data, $rows, $row);
				break;

			case 'ceridian_insync': //Ceridian InSync export format.
				ksort($setup_data['ceridian_insync']['columns']);
				$setup_data['ceridian_insync']['columns'] = Misc::trimSortPrefix( $setup_data['ceridian_insync']['columns'] );

				$export_column_map = array(	'employee_number' => '', 'import_type_id' => '', 'employee_number_b' => '', 'check_type' => '',
											'hour_code' => '', 'value' => '', 'distribution' => '', 'rate' => '', 'premium' => '', 'day' => '', 'pay_period' => '');
				foreach($rows as $row) {
					foreach( $setup_data['ceridian_insync']['columns'] as $column_id => $column_data ) {
						if ( isset( $row[$column_id] ) AND trim($column_data['hour_code']) != '' ) {
							$tmp_rows[] = array(
												'employee_number' => $row['employee_number'],
												'import_type_id' => 'COSTING',
												'employee_number_b' => str_pad( $row['employee_number'], 9, '0', STR_PAD_LEFT),
												'check_type' => 'REG',
												'hour_code' => trim($column_data['hour_code']),
												'value' => TTDate::getTimeUnit( $row[$column_id], 20 ),
												'distribution' => NULL,
												'rate' => ( isset($row[$column_id.'_hourly_rate']) ) ? $row[$column_id.'_hourly_rate'] : NULL,
												'premium' => NULL,
												'day' => NULL,
												'pay_period' => NULL,
												);
						}
					}
				}

				if ( isset( $tmp_rows) ) {
					$data = Misc::Array2CSV( $tmp_rows, $export_column_map, FALSE, FALSE );
				}
				unset($tmp_rows, $export_column_map, $column_id, $column_data, $rows, $row);

				break;
			case 'quickbooks': //Quickbooks Pro export format.
				$file_name = 'payroll_export.iif';

				ksort($setup_data['quickbooks']['columns']);
				$setup_data['quickbooks']['columns'] = Misc::trimSortPrefix( $setup_data['quickbooks']['columns'] );

				//
				// Quickbooks header
				//
				/*
					Company Create Time can be found by first running an Timer Activity export in QuickBooks and viewing the output.

					PITEM field needs to be populated, as that is the PAYROLL ITEM in quickbooks. It can be the same as the ITEM field.
					PROJ could be mapped to the default department/branch?
				*/
				$data =  "!TIMERHDR\tVER\tREL\tCOMPANYNAME\tIMPORTEDBEFORE\tFROMTIMER\tCOMPANYCREATETIME\n";
				$data .= "TIMERHDR\t8\t0\t". trim($setup_data['quickbooks']['company_name']) ."\tN\tY\t". trim($setup_data['quickbooks']['company_created_date']) ."\n";
				$data .= "!TIMEACT\tDATE\tJOB\tEMP\tITEM\tPITEM\tDURATION\tPROJ\tNOTE\tXFERTOPAYROLL\tBILLINGSTATUS\n";

				foreach($rows as $row) {
					foreach( $setup_data['quickbooks']['columns'] as $column_id => $column_data ) {
						if ( isset( $row[$column_id] ) AND trim($column_data['hour_code']) != '' ) {
							//Make sure employee name is in format: LastName, FirstName MiddleInitial
							$tmp_employee_name = $row['last_name'].', '. $row['first_name'];
							if ( isset($row['middle_name']) AND strlen($row['middle_name']) > 0 ) {
								$tmp_employee_name .= ' '.substr(trim($row['middle_name']),0,1);
							}

							$proj = NULL;
							if ( isset($row[$setup_data['quickbooks']['proj']]) ) {
								$proj = $row[$setup_data['quickbooks']['proj']];
							}

							$data .= "TIMEACT\t". date('n/j/y', $row['pay_period_end_date'])."\t\t". $tmp_employee_name ."\t". trim($column_data['hour_code']) ."\t". trim($column_data['hour_code']) ."\t".  TTDate::getTimeUnit( $row[$column_id], 10 ) ."\t". $proj ."\t\tY\t0\n";
							unset($tmp_employee_name);
						}
					}
				}

				break;
			case 'surepayroll': //SurePayroll Export format.
				ksort($setup_data['surepayroll']['columns']);
				$setup_data['surepayroll']['columns'] = Misc::trimSortPrefix( $setup_data['surepayroll']['columns'] );

				//
				//header
				//
				$data = 'TC'."\n";
				$data .= '00001'."\n";

				$export_column_map = array(	'pay_period_end_date' => 'Entry Date',
											'employee_number' => 'Employee Number',
											'last_name' => 'Last Name',
											'first_name' => 'First Name',
											'hour_code' => 'Payroll Code',
											'value' => 'Hours' );

				foreach($rows as $row) {
					foreach( $setup_data['surepayroll']['columns'] as $column_id => $column_data ) {

						if ( isset( $row[$column_id] ) AND trim($column_data['hour_code']) != '' ) {
							//Debug::Arr($column_data,'Output2', __FILE__, __LINE__, __METHOD__,10);
							$tmp_rows[] = array(
												'pay_period_end_date' => date('m/d/Y', $row['pay_period_end_date']),
												'employee_number' => $row['employee_number'],
												'last_name' => $row['last_name'],
												'first_name' => $row['first_name'],
												'hour_code' => trim($column_data['hour_code']),
												'value' => TTDate::getTimeUnit( $row[$column_id], 20 ),
												);
						}
					}
				}

				if ( isset( $tmp_rows) ) {
					$data .= Misc::Array2CSV( $tmp_rows, $export_column_map, FALSE, FALSE );
					$data = str_replace('"','', $data);
				}
				unset($tmp_rows, $export_column_map, $column_id, $column_data, $rows, $row);
				break;

			case 'csv': //Generic CSV
				ksort($setup_data['csv']['columns']);
				$setup_data['csv']['columns'] = Misc::trimSortPrefix( $setup_data['csv']['columns'] );

				$export_column_map = array('employee' => '', 'employee_number' => '', 'default_branch' => '', 'default_department' => '', 'pay_period' => '', 'hour_code' => '', 'hours' => '');

				$i=0;
				foreach($rows as $row) {
					if ( $i == 0 ) {
						//Include header.
						$tmp_rows[] = array(
											'employee' => 'Employee',
											'employee_number' => 'Employee Number',
											'default_branch' => 'Default Branch',
											'default_department' => 'Default Department',
											'pay_period' => 'Pay Period',
											'hour_code' => 'Hours Code',
											'hours' => 'Hours',
											);
					}

					//Combine all hours from the same code together.
					foreach( $setup_data['csv']['columns'] as $column_id => $column_data ) {
						$hour_code = trim($column_data['hour_code']);
						if ( isset( $row[$column_id] ) AND $hour_code != '' ) {
							if ( !isset($tmp_hour_codes[$hour_code]) ) {
								$tmp_hour_codes[$hour_code] = 0;
							}
							$tmp_hour_codes[$hour_code] = bcadd( $tmp_hour_codes[$column_data['hour_code']], $row[$column_id] ); //Use seconds for math here.
						}
					}

					if ( isset($tmp_hour_codes) ) {
						foreach($tmp_hour_codes as $hour_code => $hours ) {
							$tmp_rows[] = array(
												'employee' => $row['full_name'],
												'employee_number' => $row['employee_number'],
												'default_branch' => $row['default_branch'],
												'default_department' => $row['default_department'],
												'pay_period' => $row['pay_period']['display'],
												'hour_code' => $hour_code,
												'hours' => TTDate::getTimeUnit($hours, 20 ),
												);
						}
						unset($tmp_hour_codes, $hour_code, $hours);
					}

					$i++;
				}

				if ( isset( $tmp_rows) ) {
					$data = Misc::Array2CSV( $tmp_rows, $export_column_map, FALSE, FALSE );
				}
				unset($tmp_rows, $export_column_map, $column_id, $column_data, $rows, $row);
				break;
		}

		Debug::Arr($data, 'Export Data: ', __FILE__, __LINE__, __METHOD__,10);
		return array( 'file_name' => $file_name, 'mime_type' => $mime_type, 'data' => $data );
	}

	function _output( $format = NULL ) {
		//Get Form Config data, which can use for the export config.
		if ( $format == 'payroll_export' ) {
			return $this->_outputPayrollExport( $format );
		} else {
			return parent::_output( $format );
		}
	}
}
?>
