<?php
// $Id$

/**
 *		@file
 *		sabreQMS Module for plugin to Drupal 7 Framework
 *
 *		Punch Clock Event Admin Tasks
*/

//require_once('sabreQMS.utils.inc');
//require_once('sabreQMS.simulatordownlist.inc');

define('OPT_ACTIVE', 0);
define('OPT_INACTIVE', 1);
define('OPT_ALL', 2);

/*
 *	search_punch_clock_events()
 *
 */

function search_punch_clock_events() {


  if ( user_access('administer sabreQMS') == False ) {
    drupal_set_message(t('Unauthorized:  Permission is required'));
    return;
  }
  // this doesn't seem to load consistently unless specified here
  drupal_add_js('misc/tableheader.js');

  drupal_add_library('system','ui.dialog');
  drupal_add_library('system','ui.datepicker');
  drupal_add_js(drupal_get_path('module', 'sabreTools') . '/js/sabreTools.lib.js');
  drupal_add_js(drupal_get_path('module', 'sabreQMS') . '/js/sabreQMS.punchclocksearch.js');


  $form_cache_name = QMS_PUNCHCLOCKEVENT_SEARCH_FORM;

  $search_form = '';
  $search_results = '';


  $form_cache = cache_get($form_cache_name);
  if ( isset($form_cache->data) && ($form_cache->data <> '') ) {
    $search_form = $form_cache->data;
  }
  else {

    // search results not in cache, create empty div for ajax to populate after search
    // search results will get populated to cache after ajax call
    $form_elems = drupal_get_form('punch_clock_event_search_form');
    $search_form = render($form_elems);

    //maintains cache entry for the form for 20 min before refresh (time in seconds)
    cache_set($form_cache_name, $search_form, 'cache', time() + QMS_CACHE_TIMEOUT);
  }


  // determine cache name
  $results_cache_name = _get_qms_cache_name(QMS_PUNCHCLOCKEVENT_SEARCH_RESULTS);

  $results_cache = cache_get($results_cache_name);
  if ( isset($results_cache->data) && ($results_cache->data <> '') ) {
    $search_results = $results_cache->data;
  }
  else {
    // search results not in cache, create empty div for ajax to populate after search
    // search results will get populated to cache after ajax call
    $search_results = '<div id="qms-search-results-div"></div>';

    cache_set($results_cache_name, $search_results, 'cache', time() + QMS_CACHE_TIMEOUT);
  }

  $content = $search_form . $search_results;

  return $content;
}

/*
 * 	punch_clock_event_search_form()
 * 	display form to get user input of search parameters
 *
 */

function punch_clock_event_search_form($form, $form_state) {

    //------------ BUILD SEARCH FORM ------------------
    global $base_url;
    global $tech_list;
    $job_list = new JobList;

    $opts = array(
      0 => t('Active'),
      1 => t('Inactive'),
      2 => t('All'),
    );

    $form['search'] = array(
      '#type' => 'fieldset',
      '#title' => t('Search'),
      '#collapsible' => True,
      '#collapsed' => False,
      '#attributes' => array('id' => array('qms-search-div')),
    );
    
//    $form['search']['markup'] = array(
//      '#markup' => '<table class="qms-plain-table"><tr><td rowspan="2" style="width:40%;">',
//    );
    
    $form['search']['employee'] = array(
      '#type' => 'container',
      '#attributes' => array('class' => array('qms-punch-clock-employee-div')),
    );
    
    $form['search']['employee']['employee_opts'] = array(
      '#type' => 'radios',
      '#title' => t('Employee'),
      '#options' => $opts,
      '#default_value' => 0,
      '#attributes' => array('class' => array('qms-opts', 'qms-opts-employee')),
      '#suffix' => '<br class="clearBoth" />',
    );
    
    $form['search']['employee']['employee_active'] = array(
      '#type' => 'select',
      '#title' => t('Active'),
      '#options' => $tech_list->get_active(),
      '#default_value' => 0,
      '#attributes' => array('class' => array('qms-select', 'qms-select-employee-active'),
                            'id' => 'qms-search-employee-active'),
    );
    
    $form['search']['employee']['employee_inactive'] = array(
      '#type' => 'select',
      '#title' => t('Inactive'),
      '#options' => $tech_list->get_inactive(),
      '#default_value' => 0,
      '#attributes' => array('class' => array('qms-select', 'qms-select-employee-inactive'),
                            'id' => 'qms-search-employee-inactive'),
    );
    
    $form['search']['employee']['employee_all'] = array(
      '#type' => 'select',
      '#title' => t('All'),
      '#options' => $tech_list->get_all(),
      '#default_value' => 0,
      '#attributes' => array('class' => array('qms-select', 'qms-select-employee-all'),
                            'id' => 'qms-search-employee-all'),
    );
    
    $form['search']['job'] = array(
      '#type' => 'container',
      '#attributes' => array('class' => array('qms-punch-clock-job-div')),
    );
    
    $form['search']['job']['job_opts'] = array(
      '#type' => 'radios',
      '#title' => t('Job'),
      '#options' => $opts,
      '#default_value' => 0,
      '#attributes' => array('class' => array('qms-opts', 'qms-opts-job')),
      '#suffix' => '<br class="clearBoth" />',
    );
    
    $form['search']['job']['job_active'] = array(
      '#type' => 'select',
      '#title' => t('Active'),
      '#options' => $job_list->get_active(),
      '#default_value' => 0,
      '#attributes' => array('class' => array('qms-select', 'qms-select-job-active'),
                              'id' => 'qms-search-job-active'),
    );
    
    $form['search']['job']['job_inactive'] = array(
      '#type' => 'select',
      '#title' => t('Inactive'),
      '#options' => $job_list->get_inactive(),
      '#default_value' => 0,
      '#attributes' => array('class' => array('qms-select', 'qms-select-job-inactive'),
                              'id' => 'qms-search-job-inactive'),
    );
    
    $form['search']['job']['job_all'] = array(
      '#type' => 'select',
      '#title' => t('All'),
      '#options' => $job_list->get_all(),
      '#default_value' => 0,
      '#attributes' => array('class' => array('qms-select', 'qms-select-job-all'),
                              'id' => 'qms-search-job-inactive'),
    );
    
    
//    $form['search']['markup2'] = array(
//      '#markup' => '</td>',
//    );


    //-----------------------------------------

//    $form['search']['markup3'] = array(
//      '#markup' => '<td colspan="2" style="vertical-align:top">',
//    );


//    $form['search']['search_date_label'] = array(
//      '#markup' => '<label style="padding-bottom:8px">Search Date Range for punch event entries</label></td></tr>',
//    );



    $form['search']['from_date'] = array(
      '#type' => 'date_popup',
      '#title' => t('From Date'),
      '#size' => 10,
      '#date_format' => 'm-d-Y',
      '#attributes' => array('style' => array('float:left', 'width:50px'),
                              'id' => 'qms-search-from-date',
                              'class' => array('qms-date-picker')),
//      '#prefix' => '<tr><td style="width:22%;text-align:left;">',
//      '#suffix' => '</td>',
    );

    $form['search']['to_date'] = array(
      '#type' => 'date_popup',
      '#title' => t('To Date'),
      '#size' => 10,
      '#date_format' => 'm-d-Y',
      '#attributes' => array('style' => array('float:left', 'clear:right', 'width:50px'),
                              'id' => 'qms-search-to-date',
                                'class' => array('qms-date-picker')),
//      '#prefix' => '<td>',
//      '#suffix' => '</td></tr></table>',
    );


    //--------------------------------------------
    // Adds a simple submit button that refreshes the form and clears its contents
    // -- this is the default behavior for forms.
    $form['search']['actions'] = array('#type' => 'actions');
    $form['search']['actions']['submit'] = array(
      '#type' => 'button',
      '#value' => 'Search',
      '#attributes' => array('id' => 'qms-search-btn-submit',
                             'style' => 'font-weight:bolder;',
                              'qms-url' => url('punchclockevents/search') ),
  /*	DO NOT do Drupal AJAX here, being done through JQuery by the javascript file
  **	as we need the .live("click") function due to form caching, which won't work here with Drupal
  */
    );

    $form['search']['actions']['clear'] = array(
      '#type' => 'button',
      '#value' => t('Clear'),
      '#attributes' => array('id' => 'qms-search-btn-clear',
                             'class' => array('qms-btn-extra'),
                             'qms-url' => url('punchclockevents/clear') ),
      '#suffix' => '<span class="qms-waiting"><img class="qms-waiting-img" src="' .
                    $base_url . QMS_IMAGES_DIR . 'waiting.gif" /></span>',
    );

    // storage area for dynamic dialog element
    $form['popup_dialog'] = array(
      '#markup' => '<div id="qms-message-box"></div>',
    );

    $form['add_punch_clock_event'] = array(
      '#markup' => l(t('Add Punch Clock Event'), 'punchclockevent/add',	array('attributes' => array('class' => array('qms-punchclock-add')) ) ),
    );

    return $form;
}


/**
 * punch_clock_event_search_form_callback()
 * displays the search results, first page only
 * Has to be a separate handler from pager & sort link callback
 * This is the callback that gets called when the Search button is clicked
 *
 */
function punch_clock_event_search_form_callback() {

  $search = new stdClass;

  $search->job_opts = (int) trim($_POST['job_opts']);
  $search->job_id = (int) trim($_POST['job_id']);
  $search->employee_opts = (int) trim($_POST['employee_opts']);
  $search->employee_user_id = (int) trim($_POST['employee_user_id']);
  $search->from_date = trim($_POST['from_date']);
  $search->to_date = trim($_POST['to_date']);

  // cache the latest search key
  // determine cache name, always use it specific to this user + session
  // set key cache to expire in 30 minutes
  $key_cache_name = _get_qms_cache_name(QMS_PUNCHCLOCKEVENT_SEARCH_KEY);

  cache_set($key_cache_name, $search, 'cache', time() + QMS_CACHE_TIMEOUT);

  die(_get_punch_clock_event_search_list($search));
}


/**
 * punch_clock_event_pager_callback()
 * displays the search results, first page only
 * Has to be a separate handler from pager & sort link callback
 * This is the callback that gets called when the Search button is clicked
 *
 */
function punch_clock_event_pager_callback() {

  $search = (object) NULL;

  // determine the key cache
  $key_cache_name = _get_qms_cache_name(QMS_PUNCHCLOCKEVENT_SEARCH_KEY);

  $key_cache = cache_get($key_cache_name);
  if ( isset($key_cache->data) && ($key_cache->data <> '') ) {
    $search = $key_cache->data;
  }
  else {
    // search key not in cache, get it from POST
    // though, this should never happen... should always be in cache
    $search->job_opts = (int) trim($_POST['job_opts']);
    $search->job_id = (int) trim($_POST['job_id']);
    $search->employee_opts = (int) trim($_POST['employee_opts']);
    $search->employee_user_id = (int) trim($_POST['employee_user_id']);
    $search->from_date = trim($_POST['from_date']);
    $search->to_date = trim($_POST['to_date']);

    // cache the latest search key
    cache_set($key_cache_name, $search, 'cache', time() + QMS_CACHE_TIMEOUT);
  }

  die(_get_punch_clock_event_search_list($search));
}


/*
 * punch_clock_event_clear_results_callback()
 *
 * Clears the search results cache
 *
 */

function punch_clock_event_clear_results_callback() {

  // Clear the cache
  $search_results = '<div id="qms-search-results-div"></div>';

  // determine cache name
  $results_cache_name = _get_qms_cache_name(QMS_PUNCHCLOCKEVENT_SEARCH_RESULTS);
  $key_cache_name = _get_qms_cache_name(QMS_PUNCHCLOCKEVENT_SEARCH_KEY);

  cache_set($results_cache_name, $search_results, 'cache', time() + QMS_CACHE_TIMEOUT);
  cache_clear_all($key_cache_name, 'cache', TRUE);
  // this is an ajax callback.  Need to return + die or it renders a full page
  // we only want a piece of a page

  die($search_results);
}


/*
 * _get_punch_clock_event_search_list()
 * display the search results
 * This function gets called by punch_clock_event_search_form_callback() and punch_clock_event_pager_callback()
 * also gets called after a delete submit to refresh the cache ($bRefresh = True), but does not return anything
 *
 */

function _get_punch_clock_event_search_list($search,	$bRefresh = False) {

  if ( user_access('administer sabreQMS') == FALSE ) {
    drupal_set_message(t('Unauthorized:  User authentication required'));
    return;
  }

  $bAdmin = user_access('administer sabreQMS');
  $num_per_page =  QMS_RECORDS_PER_PAGE;

  // need to force this or pager picks up the wrong path
  $_GET['q'] = 'punchclockevents/pager';

  //This is handled as a GET
  // this is the index of the next page being requested
  $page = 0;
  if ( isset($_GET['page'])) {
    $page = (int)$_GET['page'];
  }

  $table_header = array(
    array( 'data' => 'Employee', 'field' => 'full_name', 'sort' => 'asc', 'class' => array('qms-punchclock-results-employee') ),
    array( 'data' => 'Job', 'field' => 'job_name', 'sort' => 'asc', 'class' => array('qms-punchclock-results-job') ),
    array( 'data' => 'Clocked In', 'field' => 'clock_in', 'sort' => 'desc', 'class' => array('qms-punchclock-results-in') ),
    array( 'data' => 'Clocked Out', 'field' => 'clock_out', 'sort' => 'desc', 'class' => array('qms-punchclock-results-out') ),
    array( 'data' => 'Time Worked', 'field' => 'full_name', 'sort' => 'asc', 'class' => array('qms-punchclock-results-timeworked') ),
  );
  if ( $bAdmin ) {
    $table_header[] = array( 'data' => 'Admin', 'class' => array('qms-results-admin'));
  }

  $search_init = array(
    'table_name' => 'qms_punch_clock',
    'table_alias' => 'p',
    'table_header' => $table_header,
    'pager_path' => 'punchclockevents/pager',
    'order' => 'Employee',
    'sort' => 'asc',
    'variable' => False,
  );

  $query = _st_setup_paged_search($search_init);


  //--------- Date filtering -----------
  // init just in case

  if ( !empty($search->from_date) || !empty($search->to_date) ) {
    if ( !empty($search->from_date) && !empty($search->to_date)) {
      $query->condition('clock_in', _st_format_timestamp($search->from_date . " 00:00:00"), '>=');
      $query->condition('clock_in', _st_format_timestamp($search->to_date . " 23:59:59"), '<=');
    }
    else if (!empty($search->from_date)) {
      $query->condition('clock_in', _st_format_timestamp($search->from_date . " 00:00:00"), '>=');
    }
    else if (!empty($search->to_date)) {
      $query->condition('clock_in', _st_format_timestamp($search->to_date . " 23:59:59"), '<=');
    }
  }

  // job
  $query->innerJoin('qms_jobs', 'j', 'j.job_id = p.job_id');
  
  if ( !empty($search->job_id) ) {
    $query->condition('p.job_id', $search->job_id);
  }
  
  if (!empty($search->job_opts)) {
    switch($search->job_opts) {
      case OPT_ACTIVE:
        $query->condition('j.date_closed', 0, '=');   break;
      case OPT_INACTIVE:
        $query->condition('j.date_closed', 0, '>');   break;
    }
  } else {
    $query->condition('j.date_closed', 0, '=');
  }

  // employee
  
  if ( !empty($search->employee_user_id) ) {
    $query->condition('employee_user_id', $search->employee_user_id);
  }
  
  if (!empty($search->job_opts)) {
    switch($search->employee_opts) {
      case OPT_ACTIVE:
        $query->condition('u.status', 1, '=');   break;
      case OPT_INACTIVE:
        $query->condition('u.status', 0, '=');   break;
    }
  } else {
    $query->condition('u.status', 1, '=');
  }


  $query->leftJoin('qms_employees', 'e', 'e.user_id = p.employee_user_id');
  $query->leftJoin('users', 'u', 'u.uid = p.employee_user_id');


  $query->fields('p', array('punch_clock_id', 'clock_in', 'clock_out', 'time_worked') )
        ->fields('j', array('job_name', 'date_closed'))
        ->fields('e', array('full_name'))
        ->fields('u', array('name'));

  $max_count = 0;
  $result = _st_execute_paged_search($query, $max_count);

  $i = 0;
  $table_rows = array();

  foreach ($result as $row) {

    $row_data = array(
      ( (strlen($row->full_name) > 0) ? check_plain($row->full_name) : check_plain($row->name) . "*"),
      $row->job_name . (($row->date_closed > 0) ? '*' : ''),
      _st_format_date($row->clock_in, 'short'),
      ( $row->clock_out > 0 ? _st_format_date($row->clock_out, 'short') : ''),

      // time_worked stored in seconds.  Convert to hours (2 decimal places)
      (!empty($row->time_worked > 0) ? round(($row->time_worked / (60 * 60) ), 2) : ''),
      _get_results_table_options('punchclockevent', $row->punch_clock_id, True,
                                  'qmssettings/punchclockevents'),
    );

    $table_rows[] = array('data' => $row_data);
    $i++;
  }

  $content = '<div id="qms-search-results-div">';

  $content .= theme( 'table', array(
    'header' => $table_header,
    'rows' => $table_rows,
    'empty' => t('None'),
    'sticky' => True,
  ));

  //Append pager:  http://api.drupal.org/api/drupal/includes--pager.inc/function/theme_pager
  $content .= theme('pager', array('tags' => array(), 'quantity' => QMS_RECORDS_PER_PAGE));
  $content .= '</div>';

  // Save to cache
  $results_cache_name = _get_qms_cache_name(QMS_PUNCHCLOCKEVENT_SEARCH_RESULTS);

  $search_results = $content;
  cache_set($results_cache_name, $search_results, 'cache', time() + (30*60));

  return $content;
}

/*
 *	punch_clock_admin_form()
 *
 *  overloads:  hook_form()
 *
 *	Displays the punch clock admin form for adding/updating
 */

function punch_clock_admin_form($form, $form_state, $punch_clock_id = 0) {

  if ( user_access('administer sabreQMS') == FALSE ) {
    return form_set_error( t('Unauthorized'), t('Administrator access required'));
  }

  $punch_clock = array();
  global $tech_list;
  $job_list = new JobList;


  // all page-specific javascript loaded in the after_build function
  $form['#after_build'][] = 'punch_clock_admin_form_after_build';


  if ( $punch_clock_id > 0 ) {   // Edit existing record

    // get the record
    $sql = "SELECT p.punch_clock_id, p.clock_in, p.clock_out, p.time_worked, p.job_id, p.employee_user_id,
                   p.modified, u.name, j.job_name, j.date_opened, j.date_closed, j.active
            FROM {qms_punch_clock} p
            LEFT JOIN {users} u ON u.uid = p.modified_by_user
            INNER JOIN {qms_jobs} j ON j.job_id = p.job_id
            WHERE p.punch_clock_id = :pcid";
    $results = db_query($sql, array(':pcid' => $punch_clock_id));

    if ( $results->rowCount() == 0 ) {
      drupal_set_message( t('Oops!  Something seems to have gone wrong.  Punch clock record not found.'));
      drupal_goto('qmssettings/punchclockevents');
      return;
    }

    $punch_clock = $results->fetchObject();
  }

  if ( isset($punch_clock->modified) && $punch_clock->modified ) {
    $form['markup1'] = array(
      '#markup' => 'Modified by:  ' . $punch_clock->name . ', ' .
                    ( $punch_clock->modified ? _st_format_date($punch_clock->modified, 'short') : '' ) . '<hr />',
    );
  }


  $form['employee'] = array(
    '#type' => 'select',
    '#title' => t('Employee'),
    '#options' => $tech_list->get(),
    '#default_value' => ( ($punch_clock_id > 0) ? $punch_clock->employee_user_id : 0 ),
    '#required' => True,
    '#attributes' => array('class' => array('qms-select'),
                          'id' => 'qms-search-employee'),
    '#prefix' => '<table class="qms-plain-table"><tr><td style="width:40%;">'
  );

  $form['job_active'] = array(
    '#type' => 'select',
    '#title' => t('Job') . ' (' . t('active') . ')',
    '#options' => $job_list->get_active(),
    '#default_value' => ( ($punch_clock_id > 0) ? $punch_clock->job_id : 0 ),
    '#required' => True,
    '#attributes' => array('class' => array('qms-select'),
                            'id' => 'qms-job-active'),
    //'#suffix' => '</td>',
  );

  $form['job_all'] = array(
    '#type' => 'select',
    '#title' => t('Job') . ' ( * = ' . t('inactive') . ')',
    '#options' => $job_list->get(),
    '#default_value' => ( ($punch_clock_id > 0) ? $punch_clock->job_id : 0 ),
    '#required' => False,
    '#attributes' => array('class' => array('qms-select'),
                            'id' => 'qms-job-all'),
  );

  $form['closed_jobs'] = array(
    '#type' => 'checkbox',
    '#title' => t('Include Closed Jobs'),
    '#default_value' => False,
    '#attributes' => array('id' => 'qms-chk-incl-closed-jobs'),
  );


  $form['clock_in'] = array(
    '#type' => 'date_popup',
    '#title' => t('Clock In'),
    '#size' => 14,
    '#date_format' => 'm-d-Y H:i',						// displayed format
      //default value has to be in this format
    //'#default_value' => date('Y-m-d H:i'),
    '#default_value' => ( ($punch_clock_id > 0) ? _st_format_date($punch_clock->clock_in, 'short') : '' ),
    '#required' => True,   // if no date entered, returns NULL
    '#attributes' => array('class' => array('qms-date-picker')),
    '#prefix' => '<td style="width:30%; text-align:left">',
    '#suffix' => '</td>',
  );

  $form['clock_out'] = array(
    '#type' => 'date_popup',
    '#title' => t('Clock Out'),
    '#size' => 14,
    '#date_format' => 'm-d-Y H:i',						// displayed format
      //default value has to be in this format
    '#default_value' => ( ( isset($punch_clock->clock_out) && ($punch_clock->clock_out > 0)) ? _st_format_date($punch_clock->clock_out, 'short') : '' ),
    '#attributes' => array('class' => array('qms-date-picker')),
    '#prefix' => '<td style="width:30%; text-align:left">',
    '#suffix' => '</td></tr></table>',
  );


  $form['punch_clock_id'] = array(
    '#type' => 'value',
    '#value' => ( ($punch_clock_id > 0) ? $punch_clock_id : 'NEW' ),
  );

  $form['actions'] = array('#type' => 'actions');
  $form['actions']['submit'] = array(
    '#type' => 'submit',
    '#value' => 'Submit',
  );
  if ( $punch_clock_id ) {


    $form['actions']['delete'] = array(
    '#type' => 'button',
    '#value' => t('Delete'),
    '#attributes' => array('class' => array('qms-btn-delete', 'qms-btn-extra'),
                           'onclick' => 'window.location="' .
                                url('punchclockevent/delete/' . $punch_clock_id ) . '"; return false;'),
  );
  }
  $form['actions']['done'] = array(
    '#type' => 'button',
    '#value' => t('Done'),
    '#attributes' => array('class' => array('qms-btn-done', 'qms-btn-extra'),
                           'onclick' => 'window.location="' .
                                url('qmssettings/punchclockevents') . '"; return false;'),
  );



  return $form;
}

/*------ AFTER BUILD FUNCTION --------
*	 functions called, as it implies, after the form is built
*  this is necessary when custom javascript and/or css files are added as needed
*  at the page level for forms that go through validation with hook_form_validate()
*  Otherwise, if a form fails validation, the page/form is reloaded for the user to correct
*  but the accompanying javascript & css is not reloaded with it.
*  when $form['#after_build][] is used, the external scripts will be reloaded properly.
*/

/*
 * punch_clock_admin_form_after_build()
 *
 */
function punch_clock_admin_form_after_build($form, &$form_state)
{
  drupal_add_library('system','ui.datepicker');
  _st_add_js_timezone();
  drupal_add_js(drupal_get_path('module', 'sabreTools') . '/js/sabreTools.lib.js');
  drupal_add_js(drupal_get_path('module', 'sabreQMS') . '/js/sabreQMS.punchclockaddedit.js');

  return $form;
}





/*
 *	punch_clock_admin_form_validate()
 *
 *  overloads:  hook_form_validate()
 *
 *	Validates punch_clock_admin_form after it is submitted
 */

function punch_clock_admin_form_validate($form, $form_state) {
//  echo "validate:  punch_clock_admin_form_validate<br>\n";
//  var_dump($form_state['values']);
  
  if ( (int)$form_state['values']['employee'] == 0 ) {
    form_set_error('employee', t('Employee is a required field'));
  }
  if ( (int)$form_state['values']['job_active'] == 0
       && (int)$form_state['values']['job_all'] == 0  ) {
    form_set_error('job_active', t('Job is a required field'));
  }

  //----------------- date checking ---------------------

  // add seconds to make it DATE_ISO format:  'YYYY-MM-DD HH24:MI:SS'
  $clock_in = '';
  $iclock_in = 0;
  if ( isset($form_state['values']['clock_in']) ) {
    $clock_in = $form_state['values']['clock_in'];
    $iclock_in = _st_format_timestamp($clock_in);
    if ( $iclock_in == 0 ) {
      form_set_error('clock_in', t('Clock In is a required field'));
    }
  }


  $clock_out = ( !empty($form_state['values']['clock_out']) ? $form_state['values']['clock_out'] : '' );
  $iclock_out = 0;
  if (!empty($clock_out) ) {
    $iclock_out = _st_format_timestamp($clock_out . ':00');
  }

  if ( !empty($iclock_out) )  {
    // this is ok since you could be clocking someone in and having them clock themselves out later.
    if ( (!empty($iclock_in)) && (!empty($iclock_out)) && ($iclock_out < $iclock_in)) {
      form_set_error('clock_out', t('Clock Out cannot be set to a time earlier than Clock In.'));
    }
  }

  // check for date overlap with other punch clock records
  $employee_user_id = (int)$form_state['values']['employee'];
  $job_id = !empty($form_state['values']['job_active']) ?
                  (int)$form_state['values']['job_active'] :
                  (int)$form_state['values']['job_all'];
  $punch_clock_id = (int)$form_state['values']['punch_clock_id'];

  $query = db_select('qms_punch_clock', 'p')
              ->fields('p', array('punch_clock_id', 'employee_user_id', 'job_id', 'clock_in', 'clock_out'))
              ->condition('employee_user_id', $employee_user_id)
              ->condition('job_id', $job_id);

  if ( $punch_clock_id != 'NEW') {
    $query->condition('punch_clock_id', $punch_clock_id, '!=');
  }


  $and1 = db_and()->condition('clock_in', $iclock_in, '<=')->condition('clock_out', $iclock_in, '>=')->condition('clock_out', 0, '>');
  $and2 = db_and()->condition('clock_in', $iclock_in, '<=')->condition('clock_out', 0, '=');
  $and3 = '';

  if ( !empty($iclock_out)) {
    //$and3 = db_and()->condition('clock_in', $iclock_out, '<=');  // WRONG!!  Sleepcoding again
    $and3 = db_and()->condition('clock_in', $iclock_in, '>=')->condition('clock_in', $iclock_out, '<=');
  }
  else {
    // are we trying to save an open punch clock event before an existing event
    $and3 = db_and()->condition('clock_in', $iclock_in, '>=');
  }

  $or = db_or()->condition($and1)->condition($and2)->condition($and3);
  $query->condition($or);
  $query->range(0,1);

  $result = $query->execute();
  if ( $result->rowCount() > 0 ) {
    form_set_error('clock_in', t('Time span overlaps or interferes with an existing punch clock record for this employee and job.  <br />' .
                                  'Punch clock records with no clock out time cannot precede other punch clock records for this employee and job.'));
  }
//  echo "validate:  punch_clock_admin_form_validate<br>\n";
//  echo "clock_in: $clock_in<br>\n";
//  echo "clock_out: $clock_out<br>\n";
}

/*
 *	punch_clock_admin_form_submit()
 *
 *  overloads:  hook_form_submit()
 *
 *	Saves form data upon successful submit
 */

function punch_clock_admin_form_submit($form, $form_state) {
  $punch_clock = new stdClass();
  
//  echo "submit:  punch_clock_admin_form_submit<br>\n";
//  var_dump($form_state['values']);

  $mode = $form_state['values']['punch_clock_id'];
  $punch_clock->punch_clock_id = (int) $form_state['values']['punch_clock_id'];
  $punch_clock->employee_user_id = (int) $form_state['values']['employee'];
  $punch_clock->job_id =  ( (int) $form_state['values']['job_active'] > 0 ) ?
                            (int) $form_state['values']['job_active'] :
                            (int) $form_state['values']['job_all'];
  $clock_in = trim($form_state['values']['clock_in']);
  $clock_out = trim($form_state['values']['clock_out']);
//  echo "submit:  punch_clock_admin_form_submit<br>\n";
//  echo "clock_in: $clock_in<br>\n";
//  echo "clock_out: $clock_out<br>\n";
//  var_dump($punch_clock);
  $punch_clock->clock_in = _st_format_timestamp($clock_in);
  $punch_clock->clock_out = (!empty($clock_out)) ? _st_format_timestamp($clock_out) : 0;
  $punch_clock->time_worked = 0;

  if ( $punch_clock->clock_out > 0 ) {
    $punch_clock->time_worked = $punch_clock->clock_out - $punch_clock->clock_in;
  }

  global $user;
  $punch_clock->modified = time();
  $punch_clock->modified_by_user = $user->uid;

  if  ( $mode == 'NEW' )  {
    // new record
    // Table:  {qms_punch_clock}
    if ( False == drupal_write_record('qms_punch_clock', $punch_clock)) {
      $msg = "Oops!  Something went wrong storing the punch clock record.";
      drupal_set_message(t($msg));
    }
  }
  else {

    // update existing
    // Table:  {qms_punch_clock}
    if ( False == drupal_write_record('qms_punch_clock', $punch_clock, 'punch_clock_id')) {
      $msg = "Oops!  Something went wrong updating the punch clock record.";
      drupal_set_message(t($msg));
    }
  }

  // Reload the cache

  // determine cache name
  $search = Null;
  $key_cache_name = _get_qms_cache_name(QMS_PUNCHCLOCKEVENT_SEARCH_KEY);

  $key_cache = cache_get($key_cache_name);
  if ( isset($key_cache->data) && ($key_cache->data <> '') ) {
    // found existing search
    $search = $key_cache->data;
  } else {
    // no search found, set up search key based on new record
    $search = new stdClass();
    $search->employee_user_id = $punch_clock->employee_user_id;
    $search->from_date = _st_format_date($punch_clock->clock_in, 'custom', 'Y-m-d');

    $key_cache_name = _get_qms_cache_name(QMS_PUNCHCLOCKEVENT_SEARCH_KEY);
    cache_set($key_cache_name, $search, 'cache', time() + QMS_CACHE_TIMEOUT);
  }
  
  //refresh the cached search results in the event of any changes may be displayed
  _get_punch_clock_event_search_list($search);

  drupal_set_message('Punch clock event has been saved.');
  drupal_goto('qmssettings/punchclockevents');
}

/*
 *	punch_clock_delete_confirm()
 *
 *	Validate and Ask for confirmation before deleting record
 */

function punch_clock_delete_confirm($form, $form_state, $punch_clock_id) {

  if ( user_access('administer sabreQMS') == FALSE ) {
    drupal_set_message( t('Unauthorized Access.  Administrator access required.'));
    drupal_goto('');
    return;
  }

  if ( $punch_clock_id == 0 ) {
    return;
  }


  // Get Punch Clock record by id
  $sql = "SELECT u.name, e.full_name, j.job_name, p.clock_in, p.clock_out
          FROM  {users} u, {qms_jobs} j, {qms_punch_clock} p
          LEFT JOIN {qms_employees} e ON p.employee_user_id = e.user_id
          WHERE punch_clock_id = :pcid
          AND   p.employee_user_id = u.uid
          AND   p.job_id = j.job_id";
  $result = db_query($sql, array(':pcid' => $punch_clock_id));

  if ( $result->rowCount() == 0 ) {
    form_set_error( t('Oops!'), t('Something seems to have gone wrong.  Punch clock record not found.'));
    drupal_goto('qmssettings/punchclockevents');
    return;
  }

  $punch_clock = $result->fetchObject();
  $clock_in = _st_format_date($punch_clock->clock_in, 'short');
  $clock_out = ($punch_clock->clock_out > 0) ? _st_format_date($punch_clock->clock_out, 'short') : '...';

  // its possible this is a contractor, not an employee account
  $employee = (!empty($punch_clock->full_name)) ?
                  $punch_clock->full_name : $punch_clock->name;
  $punch_clock_desc = "$employee<br />{$punch_clock->job_name}<br />".
                      "($clock_in to $clock_out)";

  $form['punch_clock_id'] = array(
    '#type' => 'value',
    '#value' => $punch_clock_id,
  );

  $form['punch_clock_desc'] = array(
    '#type' => 'value',
    '#value' => $punch_clock_desc,
  );

  $title = t('Delete Punch Clock Record') . '?';
  $question = t('Are you sure you want to delete?') .
              '<h2>' . $punch_clock_desc . '</h2><br />' .
              t('This action cannot be undone.');
  $goto_if_canceled = 'qmssettings/punchclockevents';
  $yes_btn = 	t('Delete');
  $no_btn = t('Cancel');

  // force this here to avoid a problem with routing if cancelled
  //$_GET['destination'] = $goto_if_canceled;

  return confirm_form($form, $title,	$goto_if_canceled, $question,
                      $yes_btn, $no_btn);

}

/*
 *	punch_clock_delete_confirm_submit()
 *
 *	Submit after confirmation, delete the specified record
 */

function punch_clock_delete_confirm_submit($form, $form_state) {

  if ( $form_state['values']['confirm']) {
    $punch_clock_id = $form_state['values']['punch_clock_id'];
    $punch_clock_desc = $form_state['values']['punch_clock_desc'];


    // delete from database
    $num_rows = db_delete('qms_punch_clock')
                ->condition('punch_clock_id', $punch_clock_id, '=')
                ->execute();

    $msg = '';
    if ( $num_rows == 1 ) {
      $msg = 'Punch clock record for ' . $punch_clock_desc . ' has been deleted.';
    }
    else {
      $msg = 'Oops!  Unable to delete record for ' . $punch_clock_desc . '.';
    }
    drupal_set_message(t($msg));

    // Reload the cache

    // determine cache name
    $search = (object) Null;
    $key_cache_name = _get_qms_cache_name(QMS_PUNCHCLOCKEVENT_SEARCH_KEY);

    $key_cache = cache_get($key_cache_name);
    if ( isset($key_cache->data) && ($key_cache->data <> '') ) {
      $search = $key_cache->data;

      //refresh the cached search results in the event of any changes may be displayed
      _get_punch_clock_event_search_list($search);
    }
  }

  drupal_goto('qmssettings/punchclockevents');
}
