<?php
/*********************************************************************************
 * The contents of this file are subject to the TimeTrex Public License Version
 * 1.1.0 ("License"); You may not use this file except in compliance with the
 * License. You may obtain a copy of the License at http://www.TimeTrex.com/TPL
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * All copies of the Covered Code must include on each user interface screen:
 *    (i) the "Powered by TimeTrex" logo and
 *    (ii) the TimeTrex copyright notice
 * in the same form as they appear in the distribution.  See full license for
 * requirements.
 *
 * The Original Code is: TimeTrex Open Source
 * The Initial Developer of the Original Code is TimeTrex Payroll Services
 * Portions created by TimeTrex are Copyright (C) 2004-2007 TimeTrex Payroll Services;
 * All Rights Reserved.
 *
 ********************************************************************************/
/*
 * $Revision: 2158 $
 * $Id: AddRecurringScheduleShift.php 2158 2008-09-15 23:26:15Z ipso $
 * $Date: 2008-09-15 16:26:15 -0700 (Mon, 15 Sep 2008) $
 */
require_once( dirname(__FILE__) . DIRECTORY_SEPARATOR .'..'. DIRECTORY_SEPARATOR .'includes'. DIRECTORY_SEPARATOR .'global.inc.php');
require_once( dirname(__FILE__) . DIRECTORY_SEPARATOR .'..'. DIRECTORY_SEPARATOR .'includes'. DIRECTORY_SEPARATOR .'CLI.inc.php');

$add_shift_offset = (3600 * 4) ; //Add shifts 4hrs before they start.
$lookup_shift_offset = 3600 * 10; //Lookup shifts that started X hrs before now.

$current_epoch = TTDate::getTime();
//$current_epoch = strtotime('06-Apr-07 6:00 AM');
Debug::text('Current Epoch: '. TTDate::getDate('DATE+TIME', $current_epoch ), __FILE__, __LINE__, __METHOD__, 10);

//Initial Start/End dates need to cover all timezones, we narrow it done further once we change to each users timezone later on.
$initial_start_date = TTDate::getBeginDayEpoch( $current_epoch - $lookup_shift_offset );
$initial_end_date = $current_epoch + 86400;
Debug::text('Initial Start Date: '. TTDate::getDate('DATE+TIME', $initial_start_date ) .' End Date: '. TTDate::getDate('DATE+TIME', $initial_end_date ) , __FILE__, __LINE__, __METHOD__, 10);

$clf = new CompanyListFactory();
$clf->getAll();
if ( $clf->getRecordCount() > 0 ) {
	foreach ( $clf as $c_obj ) {
		if ( $c_obj->getStatus() != 30 ) {

			$rsclf = new RecurringScheduleControlListFactory();
			$rsclf->getByCompanyIdAndStartDateAndEndDate( $c_obj->getId(), $initial_start_date, $initial_end_date );
			if ( $rsclf->getRecordCount() > 0 ) {

				Debug::text('Recurring Schedule Control List Record Count: '. $rsclf->getRecordCount() , __FILE__, __LINE__, __METHOD__, 10);

				foreach( $rsclf as $rsc_obj ) {
					$rsclf->StartTransaction();

					Debug::text('Recurring Schedule ID: '. $rsc_obj->getID() , __FILE__, __LINE__, __METHOD__, 10);
					//Debug::Arr($rsc_obj->getUser(), 'Users assigned to Schedule', __FILE__, __LINE__, __METHOD__, 10);

					$user_ids = $rsc_obj->getUser();
					$total_user_ids = count($user_ids);

					if ( is_array($user_ids) AND $total_user_ids > 0 ) {
						$i=0;
						foreach( $user_ids as $user_id ) {
							Debug::text('aaI: '. $i .'/'. $total_user_ids .' User ID: '. $user_id, __FILE__, __LINE__, __METHOD__, 10);

							//Get User object.
							$ulf = new UserListFactory();
							$ulf->getById( $user_id );
							if ( $ulf->getRecordCount() > 0 ) {
								$user_obj = $ulf->getCurrent();
								$user_obj_prefs = $user_obj->getUserPreferenceObject();
								if ( is_object( $user_obj_prefs ) ) {
									$user_obj_prefs->setTimeZonePreferences();
								} else {
									//Use system timezone.
									TTDate::setTimeZone();
								}
								Debug::text('User Name: '. $user_obj->getUserName(), __FILE__, __LINE__, __METHOD__, 10);
							} else {
								Debug::text('Skipping User...'. $user_id, __FILE__, __LINE__, __METHOD__, 10);
								continue; //Skip user.
							}

							Debug::text('Current Epoch: '. TTDate::getDate('DATE+TIME', $current_epoch ), __FILE__, __LINE__, __METHOD__, 10);
							$start_date = TTDate::getBeginDayEpoch( $current_epoch - $lookup_shift_offset );
							$end_date = $current_epoch + $add_shift_offset;
							Debug::text('Start Date: '. TTDate::getDate('DATE+TIME', $start_date ) .' End Date: '. TTDate::getDate('DATE+TIME', $end_date ) , __FILE__, __LINE__, __METHOD__, 10);

							//Set the timezone before getting the recurring schedule shifts
							//so we prevent timezone issues and DST issues from arising.
							$recurring_schedule_days = $rsc_obj->getShiftsByStartDateAndEndDate( $start_date, $end_date );
							//Debug::Arr($recurring_schedule_days, 'Recurring Schedule Shifts', __FILE__, __LINE__, __METHOD__, 10);

							if ( $recurring_schedule_days !== FALSE ) {
								foreach( $recurring_schedule_days as $date_stamp => $recurring_schedule_shifts ) {
									Debug::text('Recurring Schedule Shift Date Stamp: '. $date_stamp , __FILE__, __LINE__, __METHOD__, 10);
									foreach($recurring_schedule_shifts as $recurring_schedule_shift ) {

										$recurring_schedule_shift_start_time = TTDate::strtotime( $recurring_schedule_shift['start_time'] );
										$recurring_schedule_shift_end_time = TTDate::strtotime( $recurring_schedule_shift['end_time'] );

										Debug::text('(After User TimeZone)Recurring Schedule Shift Start Time: '. TTDate::getDate('DATE+TIME', $recurring_schedule_shift_start_time ) .' End Time: '. TTDate::getDate('DATE+TIME', $recurring_schedule_shift_end_time ), __FILE__, __LINE__, __METHOD__, 10);
										//Make sure punch pairs fall within limits

										if ( $recurring_schedule_shift_start_time < $current_epoch + $add_shift_offset ) {
											Debug::text('Recurring Schedule Shift Start Time falls within Limits: '. TTDate::getDate('DATE+TIME', $recurring_schedule_shift_start_time ), __FILE__, __LINE__, __METHOD__, 10);

											$status_id = 10; //Working

											//Is this a holiday?
											$hlf = new HolidayListFactory();
											$hlf->getByPolicyGroupUserIdAndDate( $user_id, TTDate::getBeginDayEpoch( $recurring_schedule_shift_start_time ) );
											if ( $hlf->getRecordCount() > 0 ) {
												$h_obj = $hlf->getCurrent();

												Debug::text('Found Holiday! Name: '. $h_obj->getName(), __FILE__, __LINE__, __METHOD__, 10);

												if ( $h_obj->isEligible( $user_id ) ) {
													Debug::text('User is Eligible...', __FILE__, __LINE__, __METHOD__, 10);

													//Get Holiday Policy info
													$status_id = $h_obj->getHolidayPolicyObject()->getDefaultScheduleStatus();
													$absence_policy_id = $h_obj->getHolidayPolicyObject()->getAbsencePolicyID();
													Debug::text('Default Schedule Status: '. $status_id, __FILE__, __LINE__, __METHOD__, 10);
												} else {
													Debug::text('User is NOT Eligible...', __FILE__, __LINE__, __METHOD__, 10);
												}
											} else {
												Debug::text('No Holidays on this day: ', __FILE__, __LINE__, __METHOD__, 10);
											}
											unset($hlf, $h_obj);

											//Debug::text('Schedule Status ID: '. $status_id, __FILE__, __LINE__, __METHOD__, 10);

											$profiler->startTimer( "Add Schedule");

											//Make sure we not already added this schedule shift.
											//And that no schedule shifts overlap this one.
											//Use the isValid() function for this
											$sf = new ScheduleFactory();
											$sf->findUserDate( $user_id, $recurring_schedule_shift_start_time );
											$sf->setStatus( $status_id ); //Working
											$sf->setStartTime( $recurring_schedule_shift_start_time );
											$sf->setEndTime( $recurring_schedule_shift_end_time );
											$sf->setSchedulePolicyID( $recurring_schedule_shift['schedule_policy_id'] );

											if ( isset($absence_policy_id) AND $absence_policy_id != '' ) {
												$sf->setAbsencePolicyID( $absence_policy_id );
											}
											unset($absence_policy_id);

											if ( $recurring_schedule_shift['branch_id'] == -1 ) {
												$sf->setBranch( $user_obj->getDefaultBranch() );
											} else {
												$sf->setBranch( $recurring_schedule_shift['branch_id'] );
											}

											Debug::text('Department ID: '. $recurring_schedule_shift['department_id'] .' Default Department ID: '. $user_obj->getDefaultDepartment(), __FILE__, __LINE__, __METHOD__, 10);
											if ( $recurring_schedule_shift['department_id'] == -1 ) {
												$sf->setDepartment( $user_obj->getDefaultDepartment() );
											} else {
												$sf->setDepartment( $recurring_schedule_shift['department_id'] );
											}

											if ( isset($recurring_schedule_shift['job_id']) ) {
												$sf->setJob( $recurring_schedule_shift['job_id'] );
											}

											if ( isset($recurring_schedule_shift['job_item_id']) ) {
												$sf->setJobItem( $recurring_schedule_shift['job_item_id'] );
											}

											if ( $sf->isValid() ) {

												//Recalculate if its a absence schedule, so the holiday
												//policy takes effect.
												//Always re-calculate, this way it automatically applies dock time and holiday time.
												//Recalculate at the end of the day in a cronjob.
												//Part of the reason is that if they have a dock policy, it will show up as
												//docking them time during the entire day.
												//$sf->setEnableReCalculateDay(FALSE);

												//Only for holidays do we calculate the day right away.
												//So they don't have to wait 24hrs to see stat time.
												if ( $status_id == 20
														AND $rsc_obj->getAutoFill() == FALSE ) {
													$sf->setEnableReCalculateDay(TRUE);
												} else {
													$sf->setEnableReCalculateDay(FALSE); //Don't need to re-calc right now?
												}

												$profiler->startTimer( "Add Punch");

												Debug::text('Schedule Checks out, saving: '. TTDate::getDate('DATE+TIME', $recurring_schedule_shift_start_time ), __FILE__, __LINE__, __METHOD__, 10);
												if ( $sf->Save() == TRUE
														AND $rsc_obj->getAutoFill() == TRUE
														AND $status_id == 10 ) { //Make sure they are working for Auto-fill to kickin.
													Debug::text('Schedule has AutoFill enabled!', __FILE__, __LINE__, __METHOD__, 10);

													//Could wrap this in its own transaction
													//But the entire RSC obj is already wrapped, so without sub-trans
													//Its not going to help.
													$pcf = new PunchControlFactory();
													$pcf->findUserDate( $user_id, $recurring_schedule_shift_start_time );

													if ( $recurring_schedule_shift['branch_id'] == -1 ) {
														$pcf->setBranch( $user_obj->getDefaultBranch() );
													} else {
														$pcf->setBranch( $recurring_schedule_shift['branch_id'] );
													}

													if ( $recurring_schedule_shift['department_id'] == -1 ) {
														$pcf->setDepartment( $user_obj->getDefaultDepartment() );
													} else {
														$pcf->setDepartment( $recurring_schedule_shift['department_id'] );
													}

													if ( isset($recurring_schedule_shift['job_id']) ) {
														$pcf->setJob( $recurring_schedule_shift['job_id'] );
													}

													if ( isset($recurring_schedule_shift['job_item_id']) ) {
														$pcf->setJobItem( $recurring_schedule_shift['job_item_id'] );
													}

													if ( $pcf->isValid() ) {
														$punch_control_id = $pcf->Save();

														//Debug::Text(' Punch Control ID: '. $punch_control_id, __FILE__, __LINE__, __METHOD__,10);
														Debug::Text(' AutoFill Punch In: '. TTDate::getDate('DATE+TIME', $recurring_schedule_shift_start_time ), __FILE__, __LINE__, __METHOD__,10);
														$pf = new PunchFactory();
														$pf->setPunchControlID( $punch_control_id );
														$pf->setType( 10 ); //Normal
														$pf->setStatus( 10 ); //In
														$pf->setTimeStamp( $recurring_schedule_shift_start_time, TRUE );
														$pf->setActualTimeStamp( $recurring_schedule_shift_start_time );
														$pf->setOriginalTimeStamp( $pf->getTimeStamp() );
														//Won't save this punch if it overlaps already signed in punch.
														if ( $pf->isValid() ) {
															$pf->Save();
														}

														Debug::Text(' AutoFill Punch Out: '. TTDate::getDate('DATE+TIME', $recurring_schedule_shift_end_time ), __FILE__, __LINE__, __METHOD__,10);
														$pf = new PunchFactory();
														$pf->setPunchControlID( $punch_control_id );
														$pf->setType( 10 ); //Normal
														$pf->setStatus( 20 ); //Out
														$pf->setTimeStamp( $recurring_schedule_shift_end_time, TRUE );
														$pf->setActualTimeStamp( $recurring_schedule_shift_end_time );
														$pf->setOriginalTimeStamp( $pf->getTimeStamp() );
														//Won't save this punch if it overlaps already signed in punch.
														if ( $pf->isValid() ) {
															$pf->setEnableCalcTotalTime( TRUE );
															$pf->setEnableCalcSystemTotalTime( TRUE );
															$pf->setEnableCalcWeeklySystemTotalTime( TRUE );
															$pf->setEnableCalcUserDateTotal( TRUE );
															$pf->setEnableCalcException( TRUE );

															$pf->Save();
														}
													}
												}
												$profiler->stopTimer( "Add Punch");
											} else {
												Debug::text('Bad or conflicting Schedule: '. TTDate::getDate('DATE+TIME', $recurring_schedule_shift_start_time ), __FILE__, __LINE__, __METHOD__, 10);
											}

											$profiler->stopTimer( "Add Schedule");

										} else {
											Debug::text('Recurring Schedule Shift Start Time DOES NOT fall within Limits: '. TTDate::getDate('DATE+TIME', $recurring_schedule_shift_start_time ), __FILE__, __LINE__, __METHOD__, 10);
										}
									}
								}
							} else {
								Debug::text('No Recurring Schedule Days To Add!'. $user_id, __FILE__, __LINE__, __METHOD__, 10);
							}

							//Set timezone back to default before we loop to the next user.
							//Without this the next start/end date will be in the last users timezone
							//and cause schedules to be included.
							TTDate::setTimeZone( $config_vars['other']['system_timezone'] );

							unset($ulf, $user_obj, $sf, $pf, $pcf);

							$i++;
						}
					}
					//$rsclf->FailTransaction();
					$rsclf->CommitTransaction();
				}
			}
		} else {
			Debug::text('Company is not ACTIVE: '. $c_obj->getId(), __FILE__, __LINE__, __METHOD__, 10);
		}
	}
}
//$profiler->printTimers(TRUE);
Debug::writeToLog();
Debug::Display();
?>