static function calcExceptions($user_date_id, $enable_premature_exceptions = FALSE, $enable_future_exceptions = TRUE)
 {
     global $profiler;
     $profiler->startTimer("ExceptionPolicy::calcExceptions()");
     if ($user_date_id == '') {
         return FALSE;
     }
     Debug::text(' User Date ID: ' . $user_date_id . ' PreMature: ' . (int) $enable_premature_exceptions, __FILE__, __LINE__, __METHOD__, 10);
     $current_epoch = TTDate::getTime();
     //Get user date info
     $udlf = TTnew('UserDateListFactory');
     $udlf->getById($user_date_id);
     if ($udlf->getRecordCount() > 0) {
         $user_date_obj = $udlf->getCurrent();
         if ($enable_future_exceptions == FALSE and $user_date_obj->getDateStamp() > TTDate::getEndDayEpoch($current_epoch)) {
             return FALSE;
         }
     } else {
         return FALSE;
     }
     //16hrs... If punches are older then this time, its no longer premature.
     //This should actually be the PayPeriod Schedule maximum shift time.
     if (is_object($user_date_obj->getPayPeriodObject()) and is_object($user_date_obj->getPayPeriodObject()->getPayPeriodScheduleObject())) {
         self::$premature_delay = $user_date_obj->getPayPeriodObject()->getPayPeriodScheduleObject()->getMaximumShiftTime();
         Debug::text(' Setting preMature Exception delay to maximum shift time: ' . self::$premature_delay, __FILE__, __LINE__, __METHOD__, 10);
     } else {
         self::$premature_delay = 57600;
     }
     //Get list of existing exceptions, so we can determine if we need to delete any. We can't delete them all blindly and re-create them
     //as this will send duplicate email notifications for every single punch.
     $existing_exceptions = array();
     $elf = TTnew('ExceptionListFactory');
     $elf->getByUserDateID($user_date_id);
     if ($elf->getRecordCount() > 0) {
         foreach ($elf as $e_obj) {
             $existing_exceptions[] = array('id' => $e_obj->getId(), 'user_date_id' => $e_obj->getUserDateID(), 'exception_policy_id' => $e_obj->getExceptionPolicyID(), 'type_id' => $e_obj->getType(), 'punch_id' => $e_obj->getPunchID(), 'punch_control_id' => $e_obj->getPunchControlID());
         }
     }
     unset($elf, $e_obj);
     //Get all Punches on this date for this user.
     $plf = TTnew('PunchListFactory');
     $plf->getByUserDateId($user_date_id);
     if ($plf->getRecordCount() > 0) {
         Debug::text(' Found Punches: ' . $plf->getRecordCount(), __FILE__, __LINE__, __METHOD__, 10);
     }
     $slf = TTnew('ScheduleListFactory');
     $slf->getByUserDateIdAndStatusId($user_date_id, 10);
     if ($slf->getRecordCount() > 0) {
         Debug::text(' Found Schedule: ' . $slf->getRecordCount(), __FILE__, __LINE__, __METHOD__, 10);
     }
     $schedule_id_cache = NULL;
     //Cache schedule IDs so we don't need to do a lookup for every exception.
     $current_exceptions = array();
     //Array holding current exception data.
     //Get all active exceptions.
     $eplf = TTnew('ExceptionPolicyListFactory');
     $eplf->getByPolicyGroupUserIdAndActive($user_date_obj->getUser(), TRUE);
     if ($eplf->getRecordCount() > 0) {
         Debug::text(' Found Active Exceptions: ' . $eplf->getRecordCount(), __FILE__, __LINE__, __METHOD__, 10);
         foreach ($eplf as $ep_obj) {
             //Debug::text(' Found Exception Type: '. $ep_obj->getType() .' ID: '. $ep_obj->getID() .' Control ID: '. $ep_obj->getExceptionPolicyControl(), __FILE__, __LINE__, __METHOD__,10);
             if ($enable_premature_exceptions == TRUE and self::isPreMature($ep_obj->getType()) == TRUE) {
                 //Debug::text(' Premature Exception: '. $ep_obj->getType() , __FILE__, __LINE__, __METHOD__,10);
                 $type_id = 5;
                 //Pre-Mature
             } else {
                 //Debug::text(' NOT Premature Exception: '. $ep_obj->getType() , __FILE__, __LINE__, __METHOD__,10);
                 $type_id = 50;
                 //Active
             }
             switch (strtolower($ep_obj->getType())) {
                 case 's1':
                     //Unscheduled Absence... Anytime they are scheduled and have not punched in.
                     //Ignore these exceptions if the schedule is after today (not including today),
                     //so if a supervisors schedules an employee two days in advance they don't get a unscheduled
                     //absence appearing right away.
                     //Since we now trigger In Late/Out Late exceptions immediately after schedule time, only trigger this exception after
                     //the schedule end time has passed.
                     //**We also need to handle shifts that start at 11:00PM on one day, end at 8:00AM the next day, and they are assigned to the day where
                     //the most time is worked (ie: the next day).
                     //Handle split shifts too...
                     //- This has a side affect that if the schedule policy start/stop time is set to 0, it will trigger both a UnScheduled Absence
                     //  and a Not Scheduled exception for the same schedule/punch.
                     //Loop through all schedules, then find punches to match.
                     if ($slf->getRecordCount() > 0) {
                         foreach ($slf as $s_obj) {
                             if ($s_obj->getStatus() == 10 and $current_epoch >= $s_obj->getEndTime()) {
                                 $add_exception = TRUE;
                                 //Debug::text(' Found Schedule: Start Time: '. TTDate::getDate('DATE+TIME', $s_obj->getStartTime() ), __FILE__, __LINE__, __METHOD__,10);
                                 //Find punches that fall within this schedule time including start/stop window.
                                 if (TTDate::doesRangeSpanMidnight($s_obj->getStartTime(), $s_obj->getEndTime()) and is_object($user_date_obj) and is_object($user_date_obj->getPayPeriodObject()) and is_object($user_date_obj->getPayPeriodObject()->getPayPeriodScheduleObject())) {
                                     //Get punches from both days.
                                     $plf_tmp = TTnew('PunchListFactory');
                                     $plf_tmp->getShiftPunchesByUserIDAndEpoch($user_date_obj->getUser(), $s_obj->getStartTime(), 0, $user_date_obj->getPayPeriodObject()->getPayPeriodScheduleObject()->getMaximumShiftTime());
                                     Debug::text(' Schedule spans midnight... Found rows from expanded search: ' . $plf_tmp->getRecordCount(), __FILE__, __LINE__, __METHOD__, 10);
                                     if ($plf_tmp->getRecordCount() > 0) {
                                         foreach ($plf_tmp as $p_obj_tmp) {
                                             if ($s_obj->inSchedule($p_obj_tmp->getTimeStamp())) {
                                                 Debug::text(' aFound punch for schedule...', __FILE__, __LINE__, __METHOD__, 10);
                                                 $add_exception = FALSE;
                                                 break;
                                             }
                                         }
                                     }
                                     unset($plf_tmp, $p_obj_tmp);
                                 } else {
                                     //Get punches from just this day.
                                     foreach ($plf as $p_obj) {
                                         if ($s_obj->inSchedule($p_obj->getTimeStamp())) {
                                             //Debug::text(' bFound punch for schedule...', __FILE__, __LINE__, __METHOD__,10);
                                             $add_exception = FALSE;
                                             break;
                                         }
                                     }
                                 }
                                 if ($add_exception == TRUE) {
                                     //Debug::text(' Adding S1 exception...', __FILE__, __LINE__, __METHOD__,10);
                                     $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => FALSE, 'punch_control_id' => FALSE, 'schedule_obj' => $s_obj);
                                 }
                             }
                         }
                     }
                     unset($s_obj, $add_exception);
                     break;
                 case 's2':
                     //Not Scheduled
                     //**We also need to handle shifts that start at 11:00PM on one day, end at 8:00AM the next day, and they are assigned to the day where
                     //the most time is worked (ie: the next day).
                     //Handle split shifts too...
                     if ($plf->getRecordCount() > 1) {
                         //Make sure at least two punche exist.
                         //Loop through each punch, find out if they are scheduled, and if they are in early
                         $prev_punch_time_stamp = FALSE;
                         foreach ($plf as $p_obj) {
                             //Ignore punches that have the exact same timestamp, as they are likely transfer punches.
                             if ($prev_punch_time_stamp != $p_obj->getTimeStamp() and $p_obj->getType() == 10 and $p_obj->getStatus() == 10) {
                                 //Normal In
                                 if (!isset($scheduled_id_cache[$p_obj->getID()])) {
                                     $scheduled_id_cache[$p_obj->getID()] = $p_obj->findScheduleID(NULL, $user_date_obj->getUser());
                                 }
                                 //Check if no schedule exists, or an absent schedule exists. If they work when not scheduled (no schedule) or schedule absent, both should trigger this.
                                 if ($p_obj->setScheduleID($scheduled_id_cache[$p_obj->getID()]) == FALSE or is_object($p_obj->getScheduleObject()) and $p_obj->getScheduleObject()->getStatus() == 20) {
                                     //Debug::text(' Worked when wasnt scheduled', __FILE__, __LINE__, __METHOD__,10);
                                     $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => $p_obj->getID(), 'punch_control_id' => FALSE);
                                 } else {
                                     Debug::text('    Schedule Found', __FILE__, __LINE__, __METHOD__, 10);
                                 }
                             }
                             $prev_punch_time_stamp = $p_obj->getTimeStamp();
                         }
                     }
                     unset($scheduled_id_cache, $prev_punch_time_stamp, $p_obj);
                     break;
                 case 's3':
                     //In Early
                     if ($plf->getRecordCount() > 0) {
                         //Loop through each punch, find out if they are scheduled, and if they are in early
                         $prev_punch_time_stamp = FALSE;
                         foreach ($plf as $p_obj) {
                             //Ignore punches that have the exact same timestamp, as they are likely transfer punches.
                             if ($prev_punch_time_stamp != $p_obj->getTimeStamp() and $p_obj->getType() == 10 and $p_obj->getStatus() == 10) {
                                 //Normal In
                                 if (!isset($scheduled_id_cache[$p_obj->getID()])) {
                                     $scheduled_id_cache[$p_obj->getID()] = $p_obj->findScheduleID(NULL, $user_date_obj->getUser());
                                 }
                                 if ($p_obj->setScheduleID($scheduled_id_cache[$p_obj->getID()]) == TRUE) {
                                     if ($p_obj->getTimeStamp() < $p_obj->getScheduleObject()->getStartTime()) {
                                         if (TTDate::inWindow($p_obj->getTimeStamp(), $p_obj->getScheduleObject()->getStartTime(), $ep_obj->getGrace()) == TRUE) {
                                             Debug::text('    Within Grace time, IGNORE EXCEPTION: ', __FILE__, __LINE__, __METHOD__, 10);
                                         } elseif (TTDate::inWindow($p_obj->getTimeStamp(), $p_obj->getScheduleObject()->getStartTime(), $ep_obj->getWatchWindow()) == TRUE) {
                                             Debug::text('    NOT Within Grace time, SET EXCEPTION: ', __FILE__, __LINE__, __METHOD__, 10);
                                             $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => $p_obj->getID(), 'punch_control_id' => FALSE, 'punch_obj' => $p_obj, 'schedule_obj' => $p_obj->getScheduleObject());
                                         }
                                     }
                                 } else {
                                     Debug::text('    NO Schedule Found', __FILE__, __LINE__, __METHOD__, 10);
                                 }
                             }
                             $prev_punch_time_stamp = $p_obj->getTimeStamp();
                         }
                     }
                     break;
                 case 's4':
                     //In Late
                     if ($plf->getRecordCount() > 0) {
                         $prev_punch_time_stamp = FALSE;
                         foreach ($plf as $p_obj) {
                             Debug::text('    In Late. Punch: ' . TTDate::getDate('DATE+TIME', $p_obj->getTimeStamp()), __FILE__, __LINE__, __METHOD__, 10);
                             //Ignore punches that have the exact same timestamp and/or punches with the transfer flag, as they are likely transfer punches.
                             if ($prev_punch_time_stamp != $p_obj->getTimeStamp() and $p_obj->getTransfer() == FALSE and $p_obj->getType() == 10 and $p_obj->getStatus() == 10) {
                                 //Normal In
                                 if (!isset($scheduled_id_cache[$p_obj->getID()])) {
                                     $scheduled_id_cache[$p_obj->getID()] = $p_obj->findScheduleID(NULL, $user_date_obj->getUser());
                                 }
                                 if ($p_obj->setScheduleID($scheduled_id_cache[$p_obj->getID()]) == TRUE) {
                                     if ($p_obj->getTimeStamp() > $p_obj->getScheduleObject()->getStartTime()) {
                                         if (TTDate::inWindow($p_obj->getTimeStamp(), $p_obj->getScheduleObject()->getStartTime(), $ep_obj->getGrace()) == TRUE) {
                                             Debug::text('    Within Grace time, IGNORE EXCEPTION: ', __FILE__, __LINE__, __METHOD__, 10);
                                         } elseif (TTDate::inWindow($p_obj->getTimeStamp(), $p_obj->getScheduleObject()->getStartTime(), $ep_obj->getWatchWindow()) == TRUE) {
                                             Debug::text('    NOT Within Grace time, SET EXCEPTION: ', __FILE__, __LINE__, __METHOD__, 10);
                                             $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => $p_obj->getID(), 'punch_control_id' => FALSE, 'punch_obj' => $p_obj, 'schedule_obj' => $p_obj->getScheduleObject());
                                         }
                                     }
                                 } else {
                                     Debug::text('    NO Schedule Found', __FILE__, __LINE__, __METHOD__, 10);
                                 }
                             }
                             $prev_punch_time_stamp = $p_obj->getTimeStamp();
                         }
                     }
                     unset($scheduled_id_cache);
                     //Late Starting their shift, with no punch yet, trigger exception if:
                     //  - Schedule is found
                     //	- Current time is after schedule start time and before schedule end time.
                     // 	- Current time is after exception grace time
                     //Make sure we take into account split shifts.
                     Debug::text('    Checking Late Starting Shift exception... Current time: ' . TTDate::getDate('DATE+TIME', $current_epoch), __FILE__, __LINE__, __METHOD__, 10);
                     if ($slf->getRecordCount() > 0) {
                         foreach ($slf as $s_obj) {
                             if ($s_obj->getStatus() == 10 and ($current_epoch >= $s_obj->getStartTime() and $current_epoch <= $s_obj->getEndTime())) {
                                 if (TTDate::inWindow($current_epoch, $s_obj->getStartTime(), $ep_obj->getGrace()) == TRUE) {
                                     Debug::text('    Within Grace time, IGNORE EXCEPTION: ', __FILE__, __LINE__, __METHOD__, 10);
                                 } else {
                                     //See if we can find a punch within the schedule time, if so assume we already created the exception above.
                                     //Make sure we take into account the schedule policy start/stop window.
                                     //However in the case where a single schedule shift and just one punch exists, if an employee comes in really
                                     //early (1AM) before the schedule start/stop window it will trigger an In Late exception.
                                     //This could still be correct though if they only come in for an hour, then come in late for their shift later.
                                     //Schedule start/stop time needs to be correct.
                                     //Also need to take into account shifts that span midnight, ie: 10:30PM to 6:00AM, as its important the schedules/punches match up properly.
                                     $add_exception = TRUE;
                                     Debug::text(' Found Schedule: Start Time: ' . TTDate::getDate('DATE+TIME', $s_obj->getStartTime()), __FILE__, __LINE__, __METHOD__, 10);
                                     //Find punches that fall within this schedule time including start/stop window.
                                     if (TTDate::doesRangeSpanMidnight($s_obj->getStartTime(), $s_obj->getEndTime()) and is_object($user_date_obj) and is_object($user_date_obj->getPayPeriodObject()) and is_object($user_date_obj->getPayPeriodObject()->getPayPeriodScheduleObject())) {
                                         //Get punches from both days.
                                         $plf_tmp = TTnew('PunchListFactory');
                                         $plf_tmp->getShiftPunchesByUserIDAndEpoch($user_date_obj->getUser(), $s_obj->getStartTime(), 0, $user_date_obj->getPayPeriodObject()->getPayPeriodScheduleObject()->getMaximumShiftTime());
                                         Debug::text(' Schedule spans midnight... Found rows from expanded search: ' . $plf_tmp->getRecordCount(), __FILE__, __LINE__, __METHOD__, 10);
                                         if ($plf_tmp->getRecordCount() > 0) {
                                             foreach ($plf_tmp as $p_obj_tmp) {
                                                 if ($s_obj->inSchedule($p_obj_tmp->getTimeStamp())) {
                                                     Debug::text('    Found punch for this schedule, skipping schedule...', __FILE__, __LINE__, __METHOD__, 10);
                                                     $add_exception = FALSE;
                                                     continue 2;
                                                     //Skip to next schedule without creating exception.
                                                 }
                                             }
                                         }
                                         unset($plf_tmp, $p_obj_tmp);
                                     } else {
                                         //Get punches from just this day.
                                         foreach ($plf as $p_obj) {
                                             if ($s_obj->inSchedule($p_obj->getTimeStamp())) {
                                                 Debug::text(' bFound punch for schedule...', __FILE__, __LINE__, __METHOD__, 10);
                                                 $add_exception = FALSE;
                                                 break;
                                             }
                                         }
                                     }
                                     if ($add_exception == TRUE) {
                                         Debug::text('    NOT Within Grace time, SET EXCEPTION: ', __FILE__, __LINE__, __METHOD__, 10);
                                         $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => FALSE, 'punch_control_id' => FALSE, 'schedule_obj' => $s_obj);
                                     }
                                 }
                             }
                         }
                     } else {
                         Debug::text('    NO Schedule Found', __FILE__, __LINE__, __METHOD__, 10);
                     }
                     break;
                 case 's5':
                     //Out Early
                     if ($plf->getRecordCount() > 0) {
                         //Loop through each punch, find out if they are scheduled, and if they are in early
                         $prev_punch_time_stamp = FALSE;
                         $total_punches = $plf->getRecordCount();
                         $x = 1;
                         foreach ($plf as $p_obj) {
                             //Ignore punches that have the exact same timestamp and/or punches with the transfer flag, as they are likely transfer punches.
                             //For Out Early, we have to wait until we are at the last punch, or there is a subsequent punch
                             // to see if it matches the exact same time (transfer)
                             //Therefore we need a two step confirmation before this exception can be triggered. Current punch, then next punch if it exists.
                             if ($p_obj->getTransfer() == FALSE and $p_obj->getType() == 10 and $p_obj->getStatus() == 20) {
                                 //Normal Out
                                 if (!isset($scheduled_id_cache[$p_obj->getID()])) {
                                     $scheduled_id_cache[$p_obj->getID()] = $p_obj->findScheduleID(NULL, $user_date_obj->getUser());
                                 }
                                 if ($p_obj->setScheduleID($scheduled_id_cache[$p_obj->getID()]) == TRUE) {
                                     if ($p_obj->getTimeStamp() < $p_obj->getScheduleObject()->getEndTime()) {
                                         if (TTDate::inWindow($p_obj->getTimeStamp(), $p_obj->getScheduleObject()->getEndTime(), $ep_obj->getGrace()) == TRUE) {
                                             Debug::text('    Within Grace time, IGNORE EXCEPTION: ', __FILE__, __LINE__, __METHOD__, 10);
                                         } elseif (TTDate::inWindow($p_obj->getTimeStamp(), $p_obj->getScheduleObject()->getEndTime(), $ep_obj->getWatchWindow()) == TRUE) {
                                             Debug::text('    NOT Within Grace time, SET EXCEPTION: ', __FILE__, __LINE__, __METHOD__, 10);
                                             $tmp_exception = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => $p_obj->getID(), 'punch_control_id' => FALSE, 'punch_obj' => $p_obj, 'schedule_obj' => $p_obj->getScheduleObject());
                                             if ($x == $total_punches) {
                                                 //Trigger exception if we're the last punch.
                                                 $current_exceptions[] = $tmp_exception;
                                             } else {
                                                 //Save exception to be triggered if the next punch doesn't match the same time.
                                             }
                                         }
                                     }
                                 } else {
                                     Debug::text('    NO Schedule Found', __FILE__, __LINE__, __METHOD__, 10);
                                 }
                             } elseif ($p_obj->getType() == 10 and $p_obj->getStatus() == 10) {
                                 //Normal In
                                 //This comes after an OUT punch, so we need to check if there are two punches
                                 //in a row with the same timestamp, if so ignore the exception.
                                 if (isset($tmp_exception) and $p_obj->getTimeStamp() == $prev_punch_time_stamp) {
                                     unset($tmp_exception);
                                 } elseif (isset($tmp_exception)) {
                                     $current_exceptions[] = $tmp_exception;
                                     //Set exception.
                                 }
                             }
                             $prev_punch_time_stamp = $p_obj->getTimeStamp();
                             $x++;
                         }
                     }
                     unset($tmp_exception, $x, $prev_punch_time_stamp);
                     break;
                 case 's6':
                     //Out Late
                     if ($plf->getRecordCount() > 0) {
                         $prev_punch_time_stamp = FALSE;
                         foreach ($plf as $p_obj) {
                             $punch_pairs[$p_obj->getPunchControlID()][] = array('status_id' => $p_obj->getStatus(), 'punch_control_id' => $p_obj->getPunchControlID(), 'time_stamp' => $p_obj->getTimeStamp());
                             if ($prev_punch_time_stamp != $p_obj->getTimeStamp() and $p_obj->getType() == 10 and $p_obj->getStatus() == 20) {
                                 //Normal Out
                                 if (!isset($scheduled_id_cache[$p_obj->getID()])) {
                                     $scheduled_id_cache[$p_obj->getID()] = $p_obj->findScheduleID(NULL, $user_date_obj->getUser());
                                 }
                                 if ($p_obj->setScheduleID($scheduled_id_cache[$p_obj->getID()]) == TRUE) {
                                     if ($p_obj->getTimeStamp() > $p_obj->getScheduleObject()->getEndTime()) {
                                         if (TTDate::inWindow($p_obj->getTimeStamp(), $p_obj->getScheduleObject()->getEndTime(), $ep_obj->getGrace()) == TRUE) {
                                             Debug::text('    Within Grace time, IGNORE EXCEPTION: ', __FILE__, __LINE__, __METHOD__, 10);
                                         } elseif (TTDate::inWindow($p_obj->getTimeStamp(), $p_obj->getScheduleObject()->getEndTime(), $ep_obj->getWatchWindow()) == TRUE) {
                                             Debug::text('    NOT Within Grace time, SET EXCEPTION: ', __FILE__, __LINE__, __METHOD__, 10);
                                             $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => $p_obj->getID(), 'punch_control_id' => FALSE, 'punch_obj' => $p_obj, 'schedule_obj' => $p_obj->getScheduleObject());
                                         }
                                     }
                                 } else {
                                     Debug::text('    NO Schedule Found', __FILE__, __LINE__, __METHOD__, 10);
                                 }
                             }
                             $prev_punch_time_stamp = $p_obj->getTimeStamp();
                         }
                         //Trigger exception if no out punch and we have passed schedule out time.
                         //  - Schedule is found
                         //	- Make sure the user is missing an OUT punch.
                         //	- Current time is after schedule end time
                         // 	- Current time is after exception grace time
                         //  - Current time is before schedule end time + maximum shift time.
                         if (isset($punch_pairs) and $slf->getRecordCount() > 0) {
                             foreach ($punch_pairs as $punch_control_id => $punch_pair) {
                                 if (count($punch_pair) != 2) {
                                     Debug::text('aFound Missing Punch: ', __FILE__, __LINE__, __METHOD__, 10);
                                     if ($punch_pair[0]['status_id'] == 10) {
                                         //Missing Out Punch
                                         Debug::text('bFound Missing Out Punch: ', __FILE__, __LINE__, __METHOD__, 10);
                                         foreach ($slf as $s_obj) {
                                             Debug::text('Punch: ' . TTDate::getDate('DATE+TIME', $punch_pair[0]['time_stamp']) . ' Schedule Start Time: ' . TTDate::getDate('DATE+TIME', $s_obj->getStartTime()) . ' End Time: ' . TTDate::getDate('DATE+TIME', $s_obj->getEndTime()), __FILE__, __LINE__, __METHOD__, 10);
                                             //Because this is just an IN punch, make sure the IN punch is before the schedule end time
                                             //So we can eliminate split shift schedules.
                                             if ($punch_pair[0]['time_stamp'] <= $s_obj->getEndTime() and $current_epoch >= $s_obj->getEndTime() and $current_epoch <= $s_obj->getEndTime() + self::$premature_delay) {
                                                 if (TTDate::inWindow($current_epoch, $s_obj->getEndTime(), $ep_obj->getGrace()) == TRUE) {
                                                     Debug::text('    Within Grace time, IGNORE EXCEPTION: ', __FILE__, __LINE__, __METHOD__, 10);
                                                 } else {
                                                     Debug::text('    NOT Within Grace time, SET EXCEPTION: ', __FILE__, __LINE__, __METHOD__, 10);
                                                     $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => FALSE, 'punch_control_id' => $punch_pair[0]['punch_control_id'], 'schedule_obj' => $s_obj);
                                                 }
                                             }
                                         }
                                     }
                                 } else {
                                     Debug::text('No Missing Punches...', __FILE__, __LINE__, __METHOD__, 10);
                                 }
                             }
                         }
                         unset($punch_pairs, $punch_pair);
                     }
                     break;
                 case 'm1':
                     //Missing In Punch
                     if ($plf->getRecordCount() > 0) {
                         foreach ($plf as $p_obj) {
                             //Debug::text(' Punch: Status: '. $p_obj->getStatus() .' Punch Control ID: '. $p_obj->getPunchControlID() .' Punch ID: '. $p_obj->getId() .' TimeStamp: '. $p_obj->getTimeStamp(), __FILE__, __LINE__, __METHOD__,10);
                             if ($type_id == 5 and $p_obj->getTimeStamp() < $current_epoch - self::$premature_delay) {
                                 $type_id = 50;
                             }
                             $punch_pairs[$p_obj->getPunchControlID()][] = array('status_id' => $p_obj->getStatus(), 'punch_control_id' => $p_obj->getPunchControlID(), 'punch_id' => $p_obj->getId());
                         }
                         if (isset($punch_pairs)) {
                             foreach ($punch_pairs as $punch_control_id => $punch_pair) {
                                 //Debug::Arr($punch_pair, 'Punch Pair for Control ID:'. $punch_control_id, __FILE__, __LINE__, __METHOD__,10);
                                 if (count($punch_pair) != 2) {
                                     Debug::text('a1Found Missing Punch: ', __FILE__, __LINE__, __METHOD__, 10);
                                     if ($punch_pair[0]['status_id'] == 20) {
                                         //Missing In Punch
                                         Debug::text('b1Found Missing In Punch: ', __FILE__, __LINE__, __METHOD__, 10);
                                         $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => FALSE, 'punch_control_id' => $punch_pair[0]['punch_control_id']);
                                     }
                                 } else {
                                     Debug::text('No Missing Punches...', __FILE__, __LINE__, __METHOD__, 10);
                                 }
                             }
                         }
                         unset($punch_pairs, $punch_pair);
                     }
                     break;
                 case 'm2':
                     //Missing Out Punch
                     if ($plf->getRecordCount() > 0) {
                         foreach ($plf as $p_obj) {
                             Debug::text(' Punch: Status: ' . $p_obj->getStatus() . ' Punch Control ID: ' . $p_obj->getPunchControlID() . ' Punch ID: ' . $p_obj->getId() . ' TimeStamp: ' . $p_obj->getTimeStamp(), __FILE__, __LINE__, __METHOD__, 10);
                             //This causes the exception to trigger if the first punch pair is more than the Maximum Shift time away from the current punch,
                             //ie: In: 1:00AM, Out: 2:00AM, In 3:00PM (Maximum Shift Time less than 12hrs). The missing punch exception will be triggered immediately upon the 3:00PM punch.
                             //if ( $type_id == 5 AND $p_obj->getTimeStamp() < ($current_epoch-self::$premature_delay) ) {
                             //	$type_id = 50;
                             //}
                             $punch_pairs[$p_obj->getPunchControlID()][] = array('status_id' => $p_obj->getStatus(), 'punch_control_id' => $p_obj->getPunchControlID(), 'time_stamp' => $p_obj->getTimeStamp());
                         }
                         if (isset($punch_pairs)) {
                             foreach ($punch_pairs as $punch_control_id => $punch_pair) {
                                 if (count($punch_pair) != 2) {
                                     Debug::text('a2Found Missing Punch: ', __FILE__, __LINE__, __METHOD__, 10);
                                     if ($punch_pair[0]['status_id'] == 10) {
                                         //Missing Out Punch
                                         Debug::text('b2Found Missing Out Punch: ', __FILE__, __LINE__, __METHOD__, 10);
                                         //Make sure we are at least MaximumShift Time from the matching In punch before trigging this exception.
                                         //Even when an supervisor is entering punches for today, make missing out punch pre-mature if the maximum shift time isn't exceeded.
                                         //This will prevent timesheet recalculations from having missing punches for everyone today.
                                         //if ( $type_id == 5 AND $punch_pair[0]['time_stamp'] < ($current_epoch-self::$premature_delay) ) {
                                         if ($punch_pair[0]['time_stamp'] < $current_epoch - self::$premature_delay) {
                                             $type_id = 50;
                                         } else {
                                             $type_id = 5;
                                         }
                                         $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => FALSE, 'punch_control_id' => $punch_pair[0]['punch_control_id']);
                                     }
                                 } else {
                                     Debug::text('No Missing Punches...', __FILE__, __LINE__, __METHOD__, 10);
                                 }
                             }
                         }
                         unset($punch_pairs, $punch_pair);
                     }
                     break;
                 case 'm3':
                     //Missing Lunch In/Out punch
                     if ($plf->getRecordCount() > 0) {
                         //We need to account for cases where they may punch IN from lunch first, then Out.
                         //As well as just a Lunch In punch and nothing else.
                         foreach ($plf as $p_obj) {
                             if ($type_id == 5 and $p_obj->getTimeStamp() < $current_epoch - self::$premature_delay) {
                                 $type_id = 50;
                             }
                             $punches[] = $p_obj;
                         }
                         if (isset($punches) and is_array($punches)) {
                             foreach ($punches as $key => $p_obj) {
                                 if ($p_obj->getType() == 20) {
                                     //Lunch
                                     Debug::text(' Punch: Status: ' . $p_obj->getStatus() . ' Punch Control ID: ' . $p_obj->getPunchControlID() . ' TimeStamp: ' . $p_obj->getTimeStamp(), __FILE__, __LINE__, __METHOD__, 10);
                                     if ($p_obj->getStatus() == 10) {
                                         //Make sure previous punch is Lunch/Out
                                         if (!isset($punches[$key - 1]) or isset($punches[$key - 1]) and is_object($punches[$key - 1]) and ($punches[$key - 1]->getType() != 20 or $punches[$key - 1]->getStatus() != 20)) {
                                             //Invalid punch
                                             $invalid_punches[] = array('punch_id' => $p_obj->getId());
                                         }
                                     } else {
                                         //Make sure next punch is Lunch/In
                                         if (!isset($punches[$key + 1]) or isset($punches[$key + 1]) and is_object($punches[$key + 1]) and ($punches[$key + 1]->getType() != 20 or $punches[$key + 1]->getStatus() != 10)) {
                                             //Invalid punch
                                             $invalid_punches[] = array('punch_id' => $p_obj->getId());
                                         }
                                     }
                                 }
                             }
                             unset($punches, $key, $p_obj);
                             if (isset($invalid_punches) and count($invalid_punches) > 0) {
                                 foreach ($invalid_punches as $invalid_punch_arr) {
                                     Debug::text('Found Missing Lunch In/Out Punch: ', __FILE__, __LINE__, __METHOD__, 10);
                                     $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => $invalid_punch_arr['punch_id'], 'punch_control_id' => FALSE);
                                 }
                                 unset($invalid_punch_arr);
                             } else {
                                 Debug::text('Lunch Punches match up.', __FILE__, __LINE__, __METHOD__, 10);
                             }
                             unset($invalid_punches);
                         }
                     }
                     break;
                 case 'm4':
                     //Missing Break In/Out punch
                     if ($plf->getRecordCount() > 0) {
                         //We need to account for cases where they may punch IN from break first, then Out.
                         //As well as just a break In punch and nothing else.
                         foreach ($plf as $p_obj) {
                             if ($type_id == 5 and $p_obj->getTimeStamp() < $current_epoch - self::$premature_delay) {
                                 $type_id = 50;
                             }
                             $punches[] = $p_obj;
                         }
                         if (isset($punches) and is_array($punches)) {
                             foreach ($punches as $key => $p_obj) {
                                 if ($p_obj->getType() == 30) {
                                     //Break
                                     Debug::text(' Punch: Status: ' . $p_obj->getStatus() . ' Type: ' . $p_obj->getType() . ' Punch Control ID: ' . $p_obj->getPunchControlID() . ' TimeStamp: ' . $p_obj->getTimeStamp(), __FILE__, __LINE__, __METHOD__, 10);
                                     if ($p_obj->getStatus() == 10) {
                                         //Make sure previous punch is Break/Out
                                         if (!isset($punches[$key - 1]) or isset($punches[$key - 1]) and is_object($punches[$key - 1]) and ($punches[$key - 1]->getType() != 30 or $punches[$key - 1]->getStatus() != 20)) {
                                             //Invalid punch
                                             $invalid_punches[] = array('punch_id' => $p_obj->getId());
                                         }
                                     } else {
                                         //Make sure next punch is Break/In
                                         if (!isset($punches[$key + 1]) or isset($punches[$key + 1]) and is_object($punches[$key + 1]) and ($punches[$key + 1]->getType() != 30 or $punches[$key + 1]->getStatus() != 10)) {
                                             //Invalid punch
                                             $invalid_punches[] = array('punch_id' => $p_obj->getId());
                                         }
                                     }
                                 }
                             }
                             unset($punches, $key, $p_obj);
                             if (isset($invalid_punches) and count($invalid_punches) > 0) {
                                 foreach ($invalid_punches as $invalid_punch_arr) {
                                     Debug::text('Found Missing Break In/Out Punch: ', __FILE__, __LINE__, __METHOD__, 10);
                                     $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => $invalid_punch_arr['punch_id'], 'punch_control_id' => FALSE);
                                 }
                                 unset($invalid_punch_arr);
                             } else {
                                 Debug::text('Lunch Punches match up.', __FILE__, __LINE__, __METHOD__, 10);
                             }
                             unset($invalid_punches);
                         }
                     }
                     break;
                 case 'c1':
                     //Missed Check-in
                     //Use grace period and make sure the employee punches within that period of time (usually a transfer punch, but break/lunch should work too)
                     if ($plf->getRecordCount() > 0 and $ep_obj->getGrace() > 0) {
                         $prev_punch_time_stamp = FALSE;
                         $prev_punch_obj = FALSE;
                         $x = 1;
                         foreach ($plf as $p_obj) {
                             Debug::text('   Missed Check-In Punch: ' . TTDate::getDate('DATE+TIME', $p_obj->getTimeStamp()) . ' Delay: ' . self::$premature_delay . ' Current Epoch: ' . $current_epoch, __FILE__, __LINE__, __METHOD__, 10);
                             //Handle punch pairs below. Only trigger on OUT punches.
                             if (is_object($prev_punch_obj) and $prev_punch_obj->getStatus() == 10 and $p_obj->getStatus() == 20 and $p_obj->getTimeStamp() - $prev_punch_time_stamp > $ep_obj->getGrace()) {
                                 //Only check OUT punches when paired.
                                 Debug::text('   Triggering excepetion as employee missed check-in within: ' . ($p_obj->getTimeStamp() - $prev_punch_time_stamp), __FILE__, __LINE__, __METHOD__, 10);
                                 $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => $p_obj->getID(), 'punch_control_id' => FALSE, 'punch_obj' => $p_obj, 'schedule_obj' => $p_obj->getScheduleObject());
                             } elseif ($prev_punch_time_stamp !== FALSE) {
                                 Debug::text('   Employee Checked-In within: ' . ($p_obj->getTimeStamp() - $prev_punch_time_stamp), __FILE__, __LINE__, __METHOD__, 10);
                             }
                             //Handle cases where there is a IN punch but no OUT punch yet.
                             //However ignore cases where there is a OUT punch but no IN punch.
                             if ($x == $plf->getRecordCount() and $p_obj->getStatus() == 10 and $current_epoch - $p_obj->getTimeStamp() > $ep_obj->getGrace() and $p_obj->getTimeStamp() > $current_epoch - self::$premature_delay) {
                                 Debug::text('   Triggering excepetion as employee hasnt checked in yet, within: ' . ($current_epoch - $prev_punch_time_stamp), __FILE__, __LINE__, __METHOD__, 10);
                                 $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => FALSE, 'punch_control_id' => $p_obj->getPunchControlID(), 'punch_obj' => $p_obj, 'schedule_obj' => $p_obj->getScheduleObject());
                             }
                             $prev_punch_time_stamp = $p_obj->getTimeStamp();
                             $prev_punch_obj = $p_obj;
                             $x++;
                         }
                     }
                     unset($prev_punch_obj, $prev_punch_time_stamp, $x);
                     break;
                 case 'd1':
                     //No Branch or Department
                     $add_exception = FALSE;
                     foreach ($plf as $p_obj) {
                         //In punches only
                         if ($p_obj->getStatus() == 10 and is_object($p_obj->getPunchControlObject())) {
                             //If no Tasks are setup, ignore checking them.
                             if ($p_obj->getPunchControlObject()->getBranch() == '' or $p_obj->getPunchControlObject()->getBranch() == 0 or $p_obj->getPunchControlObject()->getBranch() == FALSE) {
                                 $add_exception = TRUE;
                             }
                             if ($p_obj->getPunchControlObject()->getDepartment() == '' or $p_obj->getPunchControlObject()->getDepartment() == 0 or $p_obj->getPunchControlObject()->getDepartment() == FALSE) {
                                 //Make sure at least one task exists before triggering exception.
                                 $dlf = TTNew('DepartmentListFactory');
                                 $dlf->getByCompanyID($user_date_obj->getUserObject()->getCompany(), 1);
                                 //Limit to just 1 record.
                                 if ($dlf->getRecordCount() > 0) {
                                     $add_exception = TRUE;
                                 }
                             }
                             if ($add_exception === TRUE) {
                                 $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => $p_obj->getId(), 'punch_control_id' => $p_obj->getPunchControlId());
                             }
                         }
                     }
                     break;
                 case 's7':
                     //Over Scheduled Hours
                     if ($plf->getRecordCount() > 0) {
                         //FIXME: Assign this exception to the last punch of the day, so it can be related back to a punch branch/department?
                         //This ONLY takes in to account WORKED hours, not paid absence hours.
                         //FIXME: Do we want to trigger this before their last out punch?
                         $schedule_total_time = 0;
                         if ($slf->getRecordCount() > 0) {
                             //Check for schedule policy
                             foreach ($slf as $s_obj) {
                                 Debug::text(' Schedule Total Time: ' . $s_obj->getTotalTime(), __FILE__, __LINE__, __METHOD__, 10);
                                 $schedule_total_time += $s_obj->getTotalTime();
                             }
                             $daily_total_time = 0;
                             if ($schedule_total_time > 0) {
                                 //Get daily total time.
                                 $udtlf = TTnew('UserDateTotalListFactory');
                                 //Take into account auto-deduct/add meal policies, but not paid absences.
                                 //$udtlf->getByUserDateIdAndStatusAndType( $user_date_id, 10, 10 );
                                 $udtlf->getByUserDateId($user_date_id);
                                 if ($udtlf->getRecordCount() > 0) {
                                     foreach ($udtlf as $udt_obj) {
                                         if ($udt_obj->getTimeCategory() == 'worked_time') {
                                             $daily_total_time += $udt_obj->getTotalTime();
                                         }
                                     }
                                 }
                                 Debug::text(' Daily Total Time: ' . $daily_total_time . ' Schedule Total Time: ' . $schedule_total_time, __FILE__, __LINE__, __METHOD__, 10);
                                 if ($daily_total_time > 0 and $daily_total_time > $schedule_total_time + $ep_obj->getGrace()) {
                                     Debug::text(' Worked Over Scheduled Hours', __FILE__, __LINE__, __METHOD__, 10);
                                     $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => FALSE, 'punch_control_id' => FALSE);
                                 } else {
                                     Debug::text(' DID NOT Work Over Scheduled Hours', __FILE__, __LINE__, __METHOD__, 10);
                                 }
                             }
                         } else {
                             Debug::text(' Not Scheduled', __FILE__, __LINE__, __METHOD__, 10);
                         }
                     }
                     break;
                 case 's8':
                     //Under Scheduled Hours
                     if ($plf->getRecordCount() > 0) {
                         //FIXME: Assign this exception to the last punch of the day, so it can be related back to a punch branch/department?
                         //This ONLY takes in to account WORKED hours, not paid absence hours.
                         $schedule_total_time = 0;
                         if ($slf->getRecordCount() > 0) {
                             //Check for schedule policy
                             foreach ($slf as $s_obj) {
                                 Debug::text(' Schedule Total Time: ' . $s_obj->getTotalTime(), __FILE__, __LINE__, __METHOD__, 10);
                                 $schedule_total_time += $s_obj->getTotalTime();
                             }
                             $daily_total_time = 0;
                             if ($schedule_total_time > 0) {
                                 //Get daily total time.
                                 $udtlf = TTnew('UserDateTotalListFactory');
                                 //Take into account auto-deduct/add meal policies
                                 //$udtlf->getByUserDateIdAndStatusAndType( $user_date_id, 10, 10 );
                                 $udtlf->getByUserDateId($user_date_id);
                                 if ($udtlf->getRecordCount() > 0) {
                                     foreach ($udtlf as $udt_obj) {
                                         if ($udt_obj->getTimeCategory() == 'worked_time') {
                                             $daily_total_time += $udt_obj->getTotalTime();
                                         }
                                     }
                                 }
                                 Debug::text(' Daily Total Time: ' . $daily_total_time . ' Schedule Total Time: ' . $schedule_total_time, __FILE__, __LINE__, __METHOD__, 10);
                                 if ($daily_total_time < $schedule_total_time - $ep_obj->getGrace()) {
                                     Debug::text(' Worked Under Scheduled Hours', __FILE__, __LINE__, __METHOD__, 10);
                                     if ($type_id == 5 and $user_date_obj->getDateStamp() < TTDate::getBeginDayEpoch($current_epoch - self::$premature_delay)) {
                                         $type_id = 50;
                                     }
                                     $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => FALSE, 'punch_control_id' => FALSE);
                                 } else {
                                     Debug::text(' DID NOT Work Under Scheduled Hours', __FILE__, __LINE__, __METHOD__, 10);
                                 }
                             }
                         } else {
                             Debug::text(' Not Scheduled', __FILE__, __LINE__, __METHOD__, 10);
                         }
                     }
                     break;
                 case 'o1':
                     //Over Daily Time.
                     if ($plf->getRecordCount() > 0) {
                         //FIXME: Assign this exception to the last punch of the day, so it can be related back to a punch branch/department?
                         //This ONLY takes in to account WORKED hours, not paid absence hours.
                         //FIXME: Do we want to trigger this before their last out punch?
                         $daily_total_time = 0;
                         //Get daily total time.
                         $udtlf = TTnew('UserDateTotalListFactory');
                         //Take into account auto-deduct/add meal policies
                         //$udtlf->getByUserDateIdAndStatusAndType( $user_date_id, 10, 10 );
                         $udtlf->getByUserDateId($user_date_id);
                         if ($udtlf->getRecordCount() > 0) {
                             foreach ($udtlf as $udt_obj) {
                                 if ($udt_obj->getTimeCategory() == 'worked_time') {
                                     $daily_total_time += $udt_obj->getTotalTime();
                                 }
                             }
                         }
                         Debug::text(' Daily Total Time: ' . $daily_total_time . ' Watch Window: ' . $ep_obj->getWatchWindow() . ' User Date ID: ' . $user_date_id, __FILE__, __LINE__, __METHOD__, 10);
                         if ($daily_total_time > 0 and $daily_total_time > $ep_obj->getWatchWindow()) {
                             Debug::text(' Worked Over Daily Hours', __FILE__, __LINE__, __METHOD__, 10);
                             $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => FALSE, 'punch_control_id' => FALSE);
                         } else {
                             Debug::text(' DID NOT Work Over Scheduled Hours', __FILE__, __LINE__, __METHOD__, 10);
                         }
                     }
                     break;
                 case 'o2':
                     //Over Weekly Time.
                 //Over Weekly Time.
                 case 's9':
                     //Over Weekly Scheduled Time.
                     if ($plf->getRecordCount() > 0) {
                         //FIXME: Assign this exception to the last punch of the day, so it can be related back to a punch branch/department?
                         //Get Pay Period Schedule info
                         //FIXME: Do we want to trigger this before their last out punch?
                         if (is_object($user_date_obj->getPayPeriodObject()) and is_object($user_date_obj->getPayPeriodObject()->getPayPeriodScheduleObject())) {
                             $start_week_day_id = $user_date_obj->getPayPeriodObject()->getPayPeriodScheduleObject()->getStartWeekDay();
                         } else {
                             $start_week_day_id = 0;
                         }
                         Debug::text('Start Week Day ID: ' . $start_week_day_id, __FILE__, __LINE__, __METHOD__, 10);
                         $weekly_scheduled_total_time = 0;
                         //Currently we only consider committed scheduled shifts. We may need to change this to take into account
                         //recurring scheduled shifts that haven't been committed yet as well.
                         //In either case though we should take into account the entires week worth of scheduled time even if we are only partially through
                         //the week, that way we won't be triggering s9 exceptions on a Wed and a Fri or something, it will only occur on the last days of the week.
                         if (strtolower($ep_obj->getType()) == 's9') {
                             $tmp_slf = TTnew('ScheduleListFactory');
                             $tmp_slf->getByUserIdAndStartDateAndEndDate($user_date_obj->getUser(), TTDate::getBeginWeekEpoch($user_date_obj->getDateStamp(), $start_week_day_id), TTDate::getEndWeekEpoch($user_date_obj->getDateStamp(), $start_week_day_id));
                             if ($tmp_slf->getRecordCount() > 0) {
                                 foreach ($tmp_slf as $s_obj) {
                                     if ($s_obj->getStatus() == 10) {
                                         //Only working shifts.
                                         $weekly_scheduled_total_time += $s_obj->getTotalTime();
                                     }
                                 }
                             }
                             unset($tmp_slf, $s_obj);
                         }
                         //This ONLY takes in to account WORKED hours, not paid absence hours.
                         $weekly_total_time = 0;
                         //Get daily total time.
                         $udtlf = TTnew('UserDateTotalListFactory');
                         $weekly_total_time = $udtlf->getWorkedTimeSumByUserIDAndStartDateAndEndDate($user_date_obj->getUser(), TTDate::getBeginWeekEpoch($user_date_obj->getDateStamp(), $start_week_day_id), $user_date_obj->getDateStamp());
                         Debug::text(' Weekly Total Time: ' . $weekly_total_time . ' Weekly Scheduled Total Time: ' . $weekly_scheduled_total_time . ' Watch Window: ' . $ep_obj->getWatchWindow() . ' Grace: ' . $ep_obj->getGrace() . ' User Date ID: ' . $user_date_id, __FILE__, __LINE__, __METHOD__, 10);
                         //Don't trigger either of these exceptions unless both the worked and scheduled time is greater than 0. If they aren't scheduled at all
                         //it should trigger a Unscheduled Absence exception instead of a over weekly scheduled time exception.
                         if (strtolower($ep_obj->getType()) == 'o2' and $weekly_total_time > 0 and $weekly_total_time > $ep_obj->getWatchWindow() or strtolower($ep_obj->getType()) == 's9' and $weekly_scheduled_total_time > 0 and $weekly_total_time > 0 and $weekly_total_time > $weekly_scheduled_total_time + $ep_obj->getGrace()) {
                             Debug::text(' Worked Over Weekly Hours', __FILE__, __LINE__, __METHOD__, 10);
                             $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => FALSE, 'punch_control_id' => FALSE);
                         } else {
                             Debug::text(' DID NOT Work Over Scheduled Hours', __FILE__, __LINE__, __METHOD__, 10);
                         }
                     }
                     break;
                 case 'l1':
                     //Long Lunch
                 //Long Lunch
                 case 'l2':
                     //Short Lunch
                     if ($plf->getRecordCount() > 0) {
                         //Get all lunch punches.
                         $pair = 0;
                         $x = 0;
                         $out_for_lunch = FALSE;
                         foreach ($plf as $p_obj) {
                             if ($p_obj->getStatus() == 20 and $p_obj->getType() == 20) {
                                 $lunch_out_timestamp = $p_obj->getTimeStamp();
                                 $lunch_punch_arr[$pair]['punch_id'] = $p_obj->getId();
                                 $out_for_lunch = TRUE;
                             } elseif ($out_for_lunch == TRUE and $p_obj->getStatus() == 10 and $p_obj->getType() == 20) {
                                 $lunch_punch_arr[$pair][20] = $lunch_out_timestamp;
                                 $lunch_punch_arr[$pair][10] = $p_obj->getTimeStamp();
                                 $out_for_lunch = FALSE;
                                 $pair++;
                                 unset($lunch_out_timestamp);
                             } else {
                                 $out_for_lunch = FALSE;
                             }
                         }
                         if (isset($lunch_punch_arr)) {
                             //Debug::Arr($lunch_punch_arr, 'Lunch Punch Array: ', __FILE__, __LINE__, __METHOD__,10);
                             foreach ($lunch_punch_arr as $pair => $time_stamp_arr) {
                                 if (isset($time_stamp_arr[10]) and isset($time_stamp_arr[20])) {
                                     $lunch_total_time = bcsub($time_stamp_arr[10], $time_stamp_arr[20]);
                                     Debug::text(' Lunch Total Time: ' . $lunch_total_time, __FILE__, __LINE__, __METHOD__, 10);
                                     if (!isset($scheduled_id_cache[$p_obj->getID()])) {
                                         $scheduled_id_cache[$p_obj->getID()] = $p_obj->findScheduleID(NULL, $user_date_obj->getUser());
                                     }
                                     //Check to see if they have a schedule policy
                                     if ($p_obj->setScheduleID($scheduled_id_cache[$p_obj->getID()]) == TRUE and is_object($p_obj->getScheduleObject()) == TRUE and is_object($p_obj->getScheduleObject()->getSchedulePolicyObject()) == TRUE) {
                                         $mp_obj = $p_obj->getScheduleObject()->getSchedulePolicyObject()->getMealPolicyObject();
                                     } else {
                                         $mplf = TTnew('MealPolicyListFactory');
                                         $mplf->getByPolicyGroupUserId($user_date_obj->getUserObject()->getId());
                                         if ($mplf->getRecordCount() > 0) {
                                             Debug::text('Found Meal Policy to apply.', __FILE__, __LINE__, __METHOD__, 10);
                                             $mp_obj = $mplf->getCurrent();
                                         }
                                     }
                                     if (isset($mp_obj) and is_object($mp_obj)) {
                                         $meal_policy_lunch_time = $mp_obj->getAmount();
                                         Debug::text('Meal Policy Time: ' . $meal_policy_lunch_time, __FILE__, __LINE__, __METHOD__, 10);
                                         $add_exception = FALSE;
                                         if (strtolower($ep_obj->getType()) == 'l1' and $meal_policy_lunch_time > 0 and $lunch_total_time > 0 and $lunch_total_time > $meal_policy_lunch_time + $ep_obj->getGrace()) {
                                             $add_exception = TRUE;
                                         } elseif (strtolower($ep_obj->getType()) == 'l2' and $meal_policy_lunch_time > 0 and $lunch_total_time > 0 and $lunch_total_time < $meal_policy_lunch_time - $ep_obj->getGrace()) {
                                             $add_exception = TRUE;
                                         }
                                         if ($add_exception == TRUE) {
                                             Debug::text('Adding Exception!', __FILE__, __LINE__, __METHOD__, 10);
                                             if (isset($time_stamp_arr['punch_id'])) {
                                                 $punch_id = $time_stamp_arr['punch_id'];
                                             } else {
                                                 $punch_id = FALSE;
                                             }
                                             $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => $punch_id, 'punch_control_id' => FALSE);
                                             unset($punch_id);
                                         } else {
                                             Debug::text('Not Adding Exception!', __FILE__, __LINE__, __METHOD__, 10);
                                         }
                                     }
                                 } else {
                                     Debug::text(' Lunch Punches not paired... Skipping!', __FILE__, __LINE__, __METHOD__, 10);
                                 }
                             }
                         } else {
                             Debug::text(' No Lunch Punches found, or none are paired.', __FILE__, __LINE__, __METHOD__, 10);
                         }
                     }
                     break;
                 case 'l3':
                     //No Lunch
                     if ($plf->getRecordCount() > 0) {
                         //If they are scheduled or not, we can check for a meal policy and base our
                         //decision off that. We don't want a No Lunch exception on a 3hr short shift though.
                         //Also ignore this exception if the lunch is auto-deduct.
                         //**Try to assign this exception to a specific punch control id, so we can do searches based on punch branch.
                         //Find meal policy
                         //Use scheduled meal policy first.
                         $meal_policy_obj = NULL;
                         if ($slf->getRecordCount() > 0) {
                             Debug::text('Schedule Found...', __FILE__, __LINE__, __METHOD__, 10);
                             foreach ($slf as $s_obj) {
                                 if ($s_obj->getSchedulePolicyObject() !== FALSE and $s_obj->getSchedulePolicyObject()->getMealPolicyObject() !== FALSE and $s_obj->getSchedulePolicyObject()->getMealPolicyObject()->getType() != 10) {
                                     Debug::text('Found Schedule Meal Policy... Trigger Time: ' . $s_obj->getSchedulePolicyObject()->getMealPolicyObject()->getTriggerTime(), __FILE__, __LINE__, __METHOD__, 10);
                                     $meal_policy_obj = $s_obj->getSchedulePolicyObject()->getMealPolicyObject();
                                 } else {
                                     Debug::text('Schedule Meal Policy does not exist, or is auto-deduct?', __FILE__, __LINE__, __METHOD__, 10);
                                 }
                             }
                         } else {
                             Debug::text('No Schedule Found...', __FILE__, __LINE__, __METHOD__, 10);
                             //Check if they have a meal policy, with no schedule.
                             $mplf = TTnew('MealPolicyListFactory');
                             $mplf->getByPolicyGroupUserId($user_date_obj->getUser());
                             if ($mplf->getRecordCount() > 0) {
                                 foreach ($mplf as $mp_obj) {
                                     if ($mp_obj->getType() != 10) {
                                         Debug::text('Found UnScheduled meal Policy... Trigger Time: ' . $mp_obj->getTriggerTime(), __FILE__, __LINE__, __METHOD__, 10);
                                         $meal_policy_obj = $mp_obj;
                                     }
                                 }
                                 unset($mplf, $mp_obj);
                             } else {
                                 //There is no  meal policy or schedule policy with a meal policy assigned to it
                                 //With out this we could still apply No meal exceptions, but they will happen even on
                                 //a 2minute shift.
                                 Debug::text('No Lunch policy, applying No meal exception.', __FILE__, __LINE__, __METHOD__, 10);
                                 $meal_policy_obj = TRUE;
                             }
                         }
                         if (is_object($meal_policy_obj) or $meal_policy_obj === TRUE) {
                             $punch_control_id = FALSE;
                             $daily_total_time = 0;
                             $udtlf = TTnew('UserDateTotalListFactory');
                             $udtlf->getByUserDateIdAndStatus($user_date_id, 20);
                             if ($udtlf->getRecordCount() > 0) {
                                 foreach ($udtlf as $udt_obj) {
                                     $daily_total_time += $udt_obj->getTotalTime();
                                     $punch_control_total_time[$udt_obj->getPunchControlID()] = $udt_obj->getTotalTime();
                                 }
                             }
                             Debug::text('Day Total Time: ' . $daily_total_time, __FILE__, __LINE__, __METHOD__, 10);
                             //Debug::Arr($punch_control_total_time, 'Punch Control Total Time: ', __FILE__, __LINE__, __METHOD__,10);
                             if ($daily_total_time > 0 and ($meal_policy_obj === TRUE or $daily_total_time > $meal_policy_obj->getTriggerTime())) {
                                 //Check for meal punch.
                                 $meal_punch = FALSE;
                                 $tmp_punch_total_time = 0;
                                 $tmp_punch_control_ids = array();
                                 foreach ($plf as $p_obj) {
                                     if ($p_obj->getType() == 20) {
                                         //20 = Lunch
                                         Debug::text('Found meal Punch: ' . $p_obj->getTimeStamp(), __FILE__, __LINE__, __METHOD__, 10);
                                         $meal_punch = TRUE;
                                         break;
                                     }
                                     if (isset($punch_control_total_time[$p_obj->getPunchControlID()]) and !isset($tmp_punch_control_ids[$p_obj->getPunchControlID()])) {
                                         $tmp_punch_total_time += $punch_control_total_time[$p_obj->getPunchControlID()];
                                         if ($punch_control_id === FALSE and ($meal_policy_obj === TRUE or $tmp_punch_total_time > $meal_policy_obj->getTriggerTime())) {
                                             Debug::text('Found punch control for exception: ' . $p_obj->getPunchControlID() . ' Total Time: ' . $tmp_punch_total_time, __FILE__, __LINE__, __METHOD__, 10);
                                             $punch_control_id = $p_obj->getPunchControlID();
                                             //Don't meal the loop here, as we have to continue on and check for other meals.
                                         }
                                     }
                                     $tmp_punch_control_ids[$p_obj->getPunchControlID()] = TRUE;
                                 }
                                 unset($tmp_punch_total_time, $tmp_punch_control_ids);
                                 if ($meal_punch == FALSE) {
                                     Debug::text('Triggering No Lunch exception!', __FILE__, __LINE__, __METHOD__, 10);
                                     $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => FALSE, 'punch_control_id' => $punch_control_id);
                                 }
                             }
                         }
                     }
                     break;
                 case 'b1':
                     //Long Break
                 //Long Break
                 case 'b2':
                     //Short Break
                     if ($plf->getRecordCount() > 0) {
                         //Get all break punches.
                         $pair = 0;
                         $x = 0;
                         $out_for_break = FALSE;
                         foreach ($plf as $p_obj) {
                             if ($p_obj->getStatus() == 20 and $p_obj->getType() == 30) {
                                 $break_out_timestamp = $p_obj->getTimeStamp();
                                 $break_punch_arr[$pair]['punch_id'] = $p_obj->getId();
                                 $out_for_break = TRUE;
                             } elseif ($out_for_break == TRUE and $p_obj->getStatus() == 10 and $p_obj->getType() == 30) {
                                 $break_punch_arr[$pair][20] = $break_out_timestamp;
                                 $break_punch_arr[$pair][10] = $p_obj->getTimeStamp();
                                 $out_for_break = FALSE;
                                 $pair++;
                                 unset($break_out_timestamp);
                             } else {
                                 $out_for_break = FALSE;
                             }
                         }
                         unset($pair);
                         if (isset($break_punch_arr)) {
                             //Debug::Arr($break_punch_arr, 'Break Punch Array: ', __FILE__, __LINE__, __METHOD__,10);
                             foreach ($break_punch_arr as $pair => $time_stamp_arr) {
                                 if (isset($time_stamp_arr[10]) and isset($time_stamp_arr[20])) {
                                     $break_total_time = bcsub($time_stamp_arr[10], $time_stamp_arr[20]);
                                     Debug::text(' Break Total Time: ' . $break_total_time, __FILE__, __LINE__, __METHOD__, 10);
                                     if (!isset($scheduled_id_cache[$p_obj->getID()])) {
                                         $scheduled_id_cache[$p_obj->getID()] = $p_obj->findScheduleID(NULL, $user_date_obj->getUser());
                                     }
                                     //Check to see if they have a schedule policy
                                     $bplf = TTnew('BreakPolicyListFactory');
                                     if ($p_obj->setScheduleID($scheduled_id_cache[$p_obj->getID()]) == TRUE and is_object($p_obj->getScheduleObject()) == TRUE and is_object($p_obj->getScheduleObject()->getSchedulePolicyObject()) == TRUE) {
                                         $break_policy_ids = $p_obj->getScheduleObject()->getSchedulePolicyObject()->getBreakPolicy();
                                         $bplf->getByIdAndCompanyId($break_policy_ids, $user_date_obj->getUserObject()->getCompany());
                                     } else {
                                         $bplf->getByPolicyGroupUserId($user_date_obj->getUser());
                                     }
                                     unset($break_policy_ids);
                                     if ($bplf->getRecordCount() > 0) {
                                         Debug::text('Found Break Policy(ies) to apply: ' . $bplf->getRecordCount() . ' Pair: ' . $pair, __FILE__, __LINE__, __METHOD__, 10);
                                         foreach ($bplf as $bp_obj) {
                                             $bp_objs[] = $bp_obj;
                                         }
                                         unset($bplf, $bp_obj);
                                         if (isset($bp_objs[$pair]) and is_object($bp_objs[$pair])) {
                                             $bp_obj = $bp_objs[$pair];
                                             $break_policy_break_time = $bp_obj->getAmount();
                                             Debug::text('Break Policy Time: ' . $break_policy_break_time . ' ID: ' . $bp_obj->getID(), __FILE__, __LINE__, __METHOD__, 10);
                                             $add_exception = FALSE;
                                             if (strtolower($ep_obj->getType()) == 'b1' and $break_policy_break_time > 0 and $break_total_time > 0 and $break_total_time > $break_policy_break_time + $ep_obj->getGrace()) {
                                                 $add_exception = TRUE;
                                             } elseif (strtolower($ep_obj->getType()) == 'b2' and $break_policy_break_time > 0 and $break_total_time > 0 and $break_total_time < $break_policy_break_time - $ep_obj->getGrace()) {
                                                 $add_exception = TRUE;
                                             }
                                             if ($add_exception == TRUE) {
                                                 Debug::text('Adding Exception! ' . $ep_obj->getType(), __FILE__, __LINE__, __METHOD__, 10);
                                                 if (isset($time_stamp_arr['punch_id'])) {
                                                     $punch_id = $time_stamp_arr['punch_id'];
                                                 } else {
                                                     $punch_id = FALSE;
                                                 }
                                                 $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => $punch_id, 'punch_control_id' => FALSE);
                                                 unset($punch_id);
                                             } else {
                                                 Debug::text('Not Adding Exception!', __FILE__, __LINE__, __METHOD__, 10);
                                             }
                                             unset($bp_obj);
                                         }
                                         unset($bp_objs);
                                     }
                                 } else {
                                     Debug::text(' Break Punches not paired... Skipping!', __FILE__, __LINE__, __METHOD__, 10);
                                 }
                             }
                         } else {
                             Debug::text(' No Break Punches found, or none are paired.', __FILE__, __LINE__, __METHOD__, 10);
                         }
                     }
                     break;
                 case 'b3':
                     //Too Many Breaks
                 //Too Many Breaks
                 case 'b4':
                     //Too Few Breaks
                     if ($plf->getRecordCount() > 0) {
                         //Get all break punches.
                         $pair = 0;
                         $x = 0;
                         $out_for_break = FALSE;
                         foreach ($plf as $p_obj) {
                             if ($p_obj->getStatus() == 20 and $p_obj->getType() == 30) {
                                 $break_out_timestamp = $p_obj->getTimeStamp();
                                 $break_punch_arr[$pair]['punch_id'] = $p_obj->getId();
                                 $out_for_break = TRUE;
                             } elseif ($out_for_break == TRUE and $p_obj->getStatus() == 10 and $p_obj->getType() == 30) {
                                 $break_punch_arr[$pair][20] = $break_out_timestamp;
                                 $break_punch_arr[$pair][10] = $p_obj->getTimeStamp();
                                 $out_for_break = FALSE;
                                 $pair++;
                                 unset($break_out_timestamp);
                             } else {
                                 $out_for_break = FALSE;
                             }
                         }
                         unset($pair);
                         //Get daily total time.
                         $daily_total_time = 0;
                         $udtlf = TTnew('UserDateTotalListFactory');
                         //$udtlf->getByUserDateIdAndStatusAndType( $user_date_id, 10, 10 );
                         $udtlf->getByUserDateId($user_date_id);
                         if ($udtlf->getRecordCount() > 0) {
                             foreach ($udtlf as $udt_obj) {
                                 if ($udt_obj->getTimeCategory() == 'worked_time') {
                                     $daily_total_time += $udt_obj->getTotalTime();
                                 }
                             }
                         }
                         Debug::text(' Daily Total Time: ' . $daily_total_time . ' User Date ID: ' . $user_date_id, __FILE__, __LINE__, __METHOD__, 10);
                         //Make sure we take into account how long they have currently worked, so we don't
                         //say too few breaks for 3hr shift that they employee took one break on.
                         //Trigger this exception if the employee doesn't take a break at all?
                         if (isset($break_punch_arr)) {
                             $total_breaks = count($break_punch_arr);
                             //Debug::Arr($break_punch_arr, 'Break Punch Array: ', __FILE__, __LINE__, __METHOD__,10);
                             foreach ($break_punch_arr as $pair => $time_stamp_arr) {
                                 if (isset($time_stamp_arr[10]) and isset($time_stamp_arr[20])) {
                                     $break_total_time = bcsub($time_stamp_arr[10], $time_stamp_arr[20]);
                                     Debug::text(' Break Total Time: ' . $break_total_time, __FILE__, __LINE__, __METHOD__, 10);
                                     if (!isset($scheduled_id_cache[$p_obj->getID()])) {
                                         $scheduled_id_cache[$p_obj->getID()] = $p_obj->findScheduleID(NULL, $user_date_obj->getUser());
                                     }
                                     //Check to see if they have a schedule policy
                                     $bplf = TTnew('BreakPolicyListFactory');
                                     if ($p_obj->setScheduleID($scheduled_id_cache[$p_obj->getID()]) == TRUE and is_object($p_obj->getScheduleObject()) == TRUE and is_object($p_obj->getScheduleObject()->getSchedulePolicyObject()) == TRUE) {
                                         $break_policy_ids = $p_obj->getScheduleObject()->getSchedulePolicyObject()->getBreakPolicy();
                                         $bplf->getByIdAndCompanyId($break_policy_ids, $user_date_obj->getUserObject()->getCompany());
                                     } else {
                                         //$bplf->getByPolicyGroupUserId( $user_date_obj->getUser() );
                                         $bplf->getByPolicyGroupUserIdAndDayTotalTime($user_date_obj->getUser(), $daily_total_time);
                                     }
                                     unset($break_policy_ids);
                                     $allowed_breaks = $bplf->getRecordCount();
                                     $add_exception = FALSE;
                                     if (strtolower($ep_obj->getType()) == 'b3' and $total_breaks > $allowed_breaks) {
                                         Debug::text(' Too many breaks taken...', __FILE__, __LINE__, __METHOD__, 10);
                                         $add_exception = TRUE;
                                     } elseif (strtolower($ep_obj->getType()) == 'b4' and $total_breaks < $allowed_breaks) {
                                         Debug::text(' Too few breaks taken...', __FILE__, __LINE__, __METHOD__, 10);
                                         $add_exception = TRUE;
                                     } else {
                                         Debug::text(' Proper number of breaks taken...', __FILE__, __LINE__, __METHOD__, 10);
                                     }
                                     if ($add_exception == TRUE and (strtolower($ep_obj->getType()) == 'b4' or strtolower($ep_obj->getType()) == 'b3' and $pair > $allowed_breaks - 1)) {
                                         Debug::text('Adding Exception! ' . $ep_obj->getType(), __FILE__, __LINE__, __METHOD__, 10);
                                         if (isset($time_stamp_arr['punch_id']) and strtolower($ep_obj->getType()) == 'b3') {
                                             $punch_id = $time_stamp_arr['punch_id'];
                                         } else {
                                             $punch_id = FALSE;
                                         }
                                         $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => $punch_id, 'punch_control_id' => FALSE);
                                         unset($punch_id);
                                     } else {
                                         Debug::text('Not Adding Exception!', __FILE__, __LINE__, __METHOD__, 10);
                                     }
                                 }
                             }
                         }
                     }
                     break;
                 case 'b5':
                     //No Break
                     if ($plf->getRecordCount() > 0) {
                         //If they are scheduled or not, we can check for a break policy and base our
                         //decision off that. We don't want a No Break exception on a 3hr short shift though.
                         //Also ignore this exception if the break is auto-deduct.
                         //**Try to assign this exception to a specific punch control id, so we can do searches based on punch branch.
                         //Find break policy
                         //Use scheduled break policy first.
                         $break_policy_obj = NULL;
                         if ($slf->getRecordCount() > 0) {
                             Debug::text('Schedule Found...', __FILE__, __LINE__, __METHOD__, 10);
                             foreach ($slf as $s_obj) {
                                 if ($s_obj->getSchedulePolicyObject() !== FALSE) {
                                     $break_policy_ids = $s_obj->getSchedulePolicyObject()->getBreakPolicy();
                                     if (is_array($break_policy_ids)) {
                                         $bplf = TTNew('BreakPolicyListFactory');
                                         $bplf->getByIdAndCompanyId($break_policy_ids, $user_date_obj->getUserObject()->getCompany());
                                         if ($bplf->getRecordCount() > 0) {
                                             foreach ($bplf as $bp_obj) {
                                                 if ($bp_obj->getType() != 10) {
                                                     $break_policy_obj = $bp_obj;
                                                     break;
                                                 }
                                             }
                                         }
                                     }
                                 }
                                 unset($s_obj, $break_policy_ids, $bplf, $bp_obj);
                             }
                         } else {
                             Debug::text('No Schedule Found...', __FILE__, __LINE__, __METHOD__, 10);
                             //Check if they have a break policy, with no schedule.
                             $bplf = TTnew('BreakPolicyListFactory');
                             $bplf->getByPolicyGroupUserId($user_date_obj->getUser());
                             if ($bplf->getRecordCount() > 0) {
                                 Debug::text('Found UnScheduled Break Policy...', __FILE__, __LINE__, __METHOD__, 10);
                                 foreach ($bplf as $bp_obj) {
                                     if ($bp_obj->getType() != 10) {
                                         $break_policy_obj = $bp_obj;
                                         break;
                                     }
                                 }
                                 unset($bplf, $bp_obj);
                             } else {
                                 //There is no  break policy or schedule policy with a break policy assigned to it
                                 //With out this we could still apply No Break exceptions, but they will happen even on
                                 //a 2minute shift.
                                 Debug::text('No break policy, applying No break exception.', __FILE__, __LINE__, __METHOD__, 10);
                                 $break_policy_obj = TRUE;
                             }
                         }
                         if (is_object($break_policy_obj) or $break_policy_obj === TRUE) {
                             $punch_control_id = FALSE;
                             $daily_total_time = 0;
                             $udtlf = TTnew('UserDateTotalListFactory');
                             $udtlf->getByUserDateIdAndStatus($user_date_id, 20);
                             if ($udtlf->getRecordCount() > 0) {
                                 foreach ($udtlf as $udt_obj) {
                                     $daily_total_time += $udt_obj->getTotalTime();
                                     $punch_control_total_time[$udt_obj->getPunchControlID()] = $udt_obj->getTotalTime();
                                 }
                             }
                             Debug::text('Day Total Time: ' . $daily_total_time, __FILE__, __LINE__, __METHOD__, 10);
                             //Debug::Arr($punch_control_total_time, 'Punch Control Total Time: ', __FILE__, __LINE__, __METHOD__,10);
                             if ($daily_total_time > 0 and ($break_policy_obj === TRUE or $daily_total_time > $break_policy_obj->getTriggerTime())) {
                                 //Check for break punch.
                                 $break_punch = FALSE;
                                 $tmp_punch_total_time = 0;
                                 $tmp_punch_control_ids = array();
                                 foreach ($plf as $p_obj) {
                                     if ($p_obj->getType() == 30) {
                                         //30 = Break
                                         Debug::text('Found break Punch: ' . $p_obj->getTimeStamp(), __FILE__, __LINE__, __METHOD__, 10);
                                         $break_punch = TRUE;
                                         break;
                                     }
                                     if (isset($punch_control_total_time[$p_obj->getPunchControlID()]) and !isset($tmp_punch_control_ids[$p_obj->getPunchControlID()])) {
                                         $tmp_punch_total_time += $punch_control_total_time[$p_obj->getPunchControlID()];
                                         if ($punch_control_id === FALSE and ($break_policy_obj === TRUE or $tmp_punch_total_time > $break_policy_obj->getTriggerTime())) {
                                             Debug::text('Found punch control for exception: ' . $p_obj->getPunchControlID(), __FILE__, __LINE__, __METHOD__, 10);
                                             $punch_control_id = $p_obj->getPunchControlID();
                                             //Don't break the loop here, as we have to continue on and check for other breaks.
                                         }
                                     }
                                     $tmp_punch_control_ids[$p_obj->getPunchControlID()] = TRUE;
                                 }
                                 unset($tmp_punch_total_time, $tmp_punch_control_ids);
                                 if ($break_punch == FALSE) {
                                     Debug::text('Triggering No Break exception!', __FILE__, __LINE__, __METHOD__, 10);
                                     $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => FALSE, 'punch_control_id' => $punch_control_id);
                                 }
                             }
                         }
                     }
                     break;
                 case 'v1':
                     //TimeSheet Not Verified
                     //Get pay period schedule data, determine if timesheet verification is even enabled.
                     if (is_object($user_date_obj->getPayPeriodObject()) and is_object($user_date_obj->getPayPeriodObject()->getPayPeriodScheduleObject()) and $user_date_obj->getPayPeriodObject()->getPayPeriodScheduleObject()->getTimeSheetVerifyType() > 10) {
                         Debug::text('Verification enabled... Window Start: ' . TTDate::getDate('DATE+TIME', $user_date_obj->getPayPeriodObject()->getTimeSheetVerifyWindowStartDate()) . ' Grace Time: ' . $ep_obj->getGrace(), __FILE__, __LINE__, __METHOD__, 10);
                         //*Only* trigger this exception on the last day of the pay period, because when the pay period is verified it has to force the last day to be recalculated.
                         //Ignore timesheets without any time, (worked and absence). Or we could use the Watch Window to specify the minimum time required on
                         //a timesheet to trigger this instead?
                         //Make sure we are after the timesheet window start date + the grace period.
                         if ($user_date_obj->getPayPeriodObject()->getStatus() != 50 and $current_epoch >= $user_date_obj->getPayPeriodObject()->getTimeSheetVerifyWindowStartDate() + $ep_obj->getGrace() and TTDate::getBeginDayEpoch($user_date_obj->getDateStamp()) == TTDate::getBeginDayEpoch($user_date_obj->getPayPeriodObject()->getEndDate())) {
                             //Get pay period total time, include worked and paid absence time.
                             $udtlf = TTnew('UserDateTotalListFactory');
                             $total_time = $udtlf->getTimeSumByUserIDAndPayPeriodId($user_date_obj->getUser(), $user_date_obj->getPayPeriodObject()->getID());
                             if ($total_time > 0) {
                                 //Check to see if pay period has been verified or not yet.
                                 $pptsvlf = TTnew('PayPeriodTimeSheetVerifyListFactory');
                                 $pptsvlf->getByPayPeriodIdAndUserId($user_date_obj->getPayPeriodObject()->getId(), $user_date_obj->getUser());
                                 $pay_period_verified = FALSE;
                                 if ($pptsvlf->getRecordCount() > 0) {
                                     $pay_period_verified = $pptsvlf->getCurrent()->getAuthorized();
                                 }
                                 if ($pay_period_verified == FALSE) {
                                     //Always allow for emailing this exception because it can be triggered after a punch is modified and
                                     //any supervisor would need to be notified to verify the timesheet again.
                                     $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => FALSE, 'punch_control_id' => FALSE, 'enable_email_notification' => TRUE);
                                 } else {
                                     Debug::text('TimeSheet has already been authorized!', __FILE__, __LINE__, __METHOD__, 10);
                                 }
                             } else {
                                 Debug::text('Timesheet does not have any worked or paid absence time...', __FILE__, __LINE__, __METHOD__, 10);
                             }
                             unset($udtlf, $total_time);
                         } else {
                             Debug::text('Not within timesheet verification window, or not after grace time.', __FILE__, __LINE__, __METHOD__, 10);
                         }
                     } else {
                         Debug::text('No Pay Period Schedule or TimeSheet Verificiation disabled...', __FILE__, __LINE__, __METHOD__, 10);
                     }
                     break;
                 case 'j1':
                     //Not Allowed on Job
                     if (getTTProductEdition() >= TT_PRODUCT_CORPORATE and $plf->getRecordCount() > 0) {
                         foreach ($plf as $p_obj) {
                             if ($p_obj->getStatus() == 10) {
                                 //In punches
                                 if (is_object($p_obj->getPunchControlObject()) and $p_obj->getPunchControlObject()->getJob() > 0) {
                                     //Found job punch, check job settings.
                                     $jlf = TTnew('JobListFactory');
                                     $jlf->getById($p_obj->getPunchControlObject()->getJob());
                                     if ($jlf->getRecordCount() > 0) {
                                         $j_obj = $jlf->getCurrent();
                                         if ($j_obj->isAllowedUser($user_date_obj->getUser()) == FALSE) {
                                             $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => FALSE, 'punch_control_id' => $p_obj->getPunchControlId());
                                         } else {
                                             Debug::text('    User allowed on Job!', __FILE__, __LINE__, __METHOD__, 10);
                                         }
                                     } else {
                                         Debug::text('    Job not found!', __FILE__, __LINE__, __METHOD__, 10);
                                     }
                                 } else {
                                     //Debug::text('    Not a Job Punch...', __FILE__, __LINE__, __METHOD__,10);
                                 }
                             }
                         }
                         unset($j_obj);
                     }
                     break;
                 case 'j2':
                     //Not Allowed on Task
                     if (getTTProductEdition() >= TT_PRODUCT_CORPORATE and $plf->getRecordCount() > 0) {
                         foreach ($plf as $p_obj) {
                             if ($p_obj->getStatus() == 10) {
                                 //In punches
                                 if (is_object($p_obj->getPunchControlObject()) and $p_obj->getPunchControlObject()->getJob() > 0 and $p_obj->getPunchControlObject()->getJobItem() > 0) {
                                     //Found job punch, check job settings.
                                     $jlf = TTnew('JobListFactory');
                                     $jlf->getById($p_obj->getPunchControlObject()->getJob());
                                     if ($jlf->getRecordCount() > 0) {
                                         $j_obj = $jlf->getCurrent();
                                         if ($j_obj->isAllowedItem($p_obj->getPunchControlObject()->getJobItem()) == FALSE) {
                                             $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => FALSE, 'punch_control_id' => $p_obj->getPunchControlId());
                                         } else {
                                             Debug::text('    Job item allowed on job!', __FILE__, __LINE__, __METHOD__, 10);
                                         }
                                     } else {
                                         Debug::text('    Job not found!', __FILE__, __LINE__, __METHOD__, 10);
                                     }
                                 } else {
                                     //Debug::text('    Not a Job Punch...', __FILE__, __LINE__, __METHOD__,10);
                                 }
                             }
                         }
                         unset($j_obj);
                     }
                     break;
                 case 'j3':
                     //Job already completed
                     if (getTTProductEdition() >= TT_PRODUCT_CORPORATE and $plf->getRecordCount() > 0) {
                         foreach ($plf as $p_obj) {
                             if ($p_obj->getStatus() == 10) {
                                 //In punches
                                 if (is_object($p_obj->getPunchControlObject()) and $p_obj->getPunchControlObject()->getJob() > 0) {
                                     //Found job punch, check job settings.
                                     $jlf = TTnew('JobListFactory');
                                     $jlf->getById($p_obj->getPunchControlObject()->getJob());
                                     if ($jlf->getRecordCount() > 0) {
                                         $j_obj = $jlf->getCurrent();
                                         //Status is completed and the User Date Stamp is greater then the job end date.
                                         //If no end date is set, ignore this.
                                         if ($j_obj->getStatus() == 30 and $j_obj->getEndDate() != FALSE and $user_date_obj->getDateStamp() > $j_obj->getEndDate()) {
                                             $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => FALSE, 'punch_control_id' => $p_obj->getPunchControlId());
                                         } else {
                                             Debug::text('    Job Not Completed!', __FILE__, __LINE__, __METHOD__, 10);
                                         }
                                     } else {
                                         Debug::text('    Job not found!', __FILE__, __LINE__, __METHOD__, 10);
                                     }
                                 } else {
                                     Debug::text('    Not a Job Punch...', __FILE__, __LINE__, __METHOD__, 10);
                                 }
                             }
                         }
                         unset($j_obj);
                     }
                     break;
                 case 'j4':
                     //No Job or Task
                     if (getTTProductEdition() >= TT_PRODUCT_CORPORATE and $plf->getRecordCount() > 0) {
                         foreach ($plf as $p_obj) {
                             $add_exception = FALSE;
                             //In punches only
                             if ($p_obj->getStatus() == 10 and is_object($p_obj->getPunchControlObject())) {
                                 //If no Tasks are setup, ignore checking them.
                                 if ($p_obj->getPunchControlObject()->getJob() == '' or $p_obj->getPunchControlObject()->getJob() == 0 or $p_obj->getPunchControlObject()->getJob() == FALSE) {
                                     $add_exception = TRUE;
                                 }
                                 if ($p_obj->getPunchControlObject()->getJobItem() == '' or $p_obj->getPunchControlObject()->getJobItem() == 0 or $p_obj->getPunchControlObject()->getJobItem() == FALSE) {
                                     //Make sure at least one task exists before triggering exception.
                                     $jilf = TTNew('JobItemListFactory');
                                     $jilf->getByCompanyID($user_date_obj->getUserObject()->getCompany(), 1);
                                     //Limit to just 1 record.
                                     if ($jilf->getRecordCount() > 0) {
                                         $add_exception = TRUE;
                                     }
                                 }
                                 if ($add_exception === TRUE) {
                                     $current_exceptions[] = array('user_date_id' => $user_date_id, 'exception_policy_id' => $ep_obj->getId(), 'type_id' => $type_id, 'punch_id' => $p_obj->getId(), 'punch_control_id' => $p_obj->getPunchControlId());
                                 }
                             }
                         }
                     }
                     break;
                 default:
                     Debug::text('BAD, should never get here: ', __FILE__, __LINE__, __METHOD__, 10);
                     break;
             }
         }
     }
     unset($ep_obj);
     $exceptions = self::diffExistingAndCurrentExceptions($existing_exceptions, $current_exceptions);
     if (is_array($exceptions)) {
         if (isset($exceptions['create_exceptions']) and is_array($exceptions['create_exceptions']) and count($exceptions['create_exceptions']) > 0) {
             Debug::text('Creating new exceptions... Total: ' . count($exceptions['create_exceptions']), __FILE__, __LINE__, __METHOD__, 10);
             foreach ($exceptions['create_exceptions'] as $tmp_exception) {
                 $ef = TTnew('ExceptionFactory');
                 $ef->setUserDateID($tmp_exception['user_date_id']);
                 $ef->setExceptionPolicyID($tmp_exception['exception_policy_id']);
                 $ef->setType($tmp_exception['type_id']);
                 if (isset($tmp_exception['punch_control_id']) and $tmp_exception['punch_control_id'] != '') {
                     $ef->setPunchControlId($tmp_exception['punch_control_id']);
                 }
                 if (isset($tmp_exception['punch_id']) and $tmp_exception['punch_id'] != '') {
                     $ef->setPunchId($tmp_exception['punch_id']);
                 }
                 $ef->setEnableDemerits(TRUE);
                 if ($ef->isValid()) {
                     $ef->Save(FALSE);
                     //Save exception prior to emailing it, otherwise we can't save audit logs.
                     if ($enable_premature_exceptions == TRUE or isset($tmp_exception['enable_email_notification']) and $tmp_exception['enable_email_notification'] == TRUE) {
                         $eplf = TTnew('ExceptionPolicyListFactory');
                         $eplf->getById($tmp_exception['exception_policy_id']);
                         if ($eplf->getRecordCount() == 1) {
                             $ep_obj = $eplf->getCurrent();
                             $ef->emailException($user_date_obj->getUserObject(), $user_date_obj, isset($tmp_exception['punch_obj']) ? $tmp_exception['punch_obj'] : NULL, isset($tmp_exception['schedule_obj']) ? $tmp_exception['schedule_obj'] : NULL, $ep_obj);
                         }
                     } else {
                         Debug::text('Not emailing new exception: User Date ID: ' . $tmp_exception['user_date_id'] . ' Type ID: ' . $tmp_exception['type_id'] . ' Enable PreMature: ' . (int) $enable_premature_exceptions, __FILE__, __LINE__, __METHOD__, 10);
                     }
                 }
                 unset($ef);
             }
         }
         if (isset($exceptions['delete_exceptions']) and is_array($exceptions['delete_exceptions']) and count($exceptions['delete_exceptions']) > 0) {
             Debug::Text('Deleting no longer valid exceptions... Total: ' . count($exceptions['delete_exceptions']), __FILE__, __LINE__, __METHOD__, 10);
             $ef = TTnew('ExceptionFactory');
             $ef->bulkDelete($exceptions['delete_exceptions']);
         }
     }
     $profiler->stopTimer("ExceptionPolicy::calcExceptions()");
     return TRUE;
 }