<?php
/**
 *		
 *		sabreScheduler Module for plugin to Drupal 7 Framework
 *
 *		Schedule assignments function handling
 *    
*/

require_once('sabreScheduler.classes.inc');
require_once('sabreScheduler.sessions.inc');
require_once('sabreScheduler.grid.inc');

define('SCHED_TYPE_SELECTED', 0);
define('SCHED_TYPE_DATE_RANGE', 1);
define('SCHED_TYPE_REPEAT_N_DAYS', 2);
define('SCHED_TYPE_REPEAT_UNTIL', 3);



/*
 *		schedule_assignment_form()
 *
 *		add or edit an assignment
 *		ADD:  schedule_id > 0  && session_id > 0
 *    EDIT:	assignment_id > 0
 */
function schedule_assignment_form($form, $form_state, $assignment_id = 0, $schedule_id = 0) {
	
	if ( user_access('view manage menu') == FALSE ) {
    drupal_set_message( t('Unauthorized.  Permission is required.'));
		drupal_goto(''); // go to main page -- not authorized for any other page
		return $form;
  }
	
	// determine where we go if we have an error here.
	$destination = drupal_get_destination();
	$goto_url = $destination['destination'];
  
  
	if( !strlen($goto_url) || ($goto_url == current_path()) ) {
		$goto_url = 'schedule/grid/' . $schedule_id . '/0';  // last resort option
	}
	
	$sel_sessions = '';
  $sel_session_list = array();
	$assignment = (object) Null;
	$session = (object) Null;
	$sched_sessions = array();
	$session_date = '';
	$session_id = 0;
	$session_date_display = '';
  
  $timezone = _get_schedule_timezone($schedule_id);
  
  if ( isset($_SESSION['sel_grid_sessions']) ) {
    $sel_sessions = $_SESSION['sel_grid_sessions'];
    // don't unset just yet, unset after submit or done
    //unset($_SESSION['sel_grid_sessions']); 
  }

	if ( $assignment_id ) {   // Get the existing record
		
		$assignment = _get_assignment($assignment_id);
		if ( $assignment == (object) Null ) {
			drupal_set_message( t('Oops!  Something seems to have gone wrong.  Session Assignment not found.'));
			drupal_goto($goto_url);
			return;
		}
		$session = _get_session($assignment->schedule_id, $assignment->schedule_session_id);
		if ( $session == (object) Null ) {
			drupal_set_message( t('Oops!  Something seems to have gone wrong.  Session not found.'));
			drupal_goto($goto_url);
			return;
		}
    
    $timezone = _get_schedule_timezone($assignment->schedule_id);
				
		$form['session'] = array(
			'#markup' => 
				'<h3>' . $assignment->customer . 
					($assignment->group_id ? ', ' . $assignment->group_name : '') . '<br />' . 
					_st_format_schedule_date($assignment->begin_timestamp, 'm/d/Y', $timezone) . ', ' . 
					$assignment->session_name . ': ' . 
					$assignment->begin_time_actual . ' - ' . $assignment->end_time_actual . 
					( ( ($session->begin_time != $assignment->begin_time_actual) || 
						($session->end_time != $assignment->end_time_actual) ) ? 
					'  (Original Session Time: ' . $session->begin_time . ' - ' . $session->end_time . ')' : '') . 
			 	'</h3>',
		);	
	}
	else if ( $schedule_id && strlen($sel_sessions) ) {
		
		$session_arr = explode('&', $sel_sessions);
		
		$n = 0;
		for($i=0; $i<count($session_arr); $i++) {
			if ( strlen($session_arr[$i])) {
				$s = explode('~', $session_arr[$i]);
				$sel_session_list[$n++] = array(
					'session_id' => $s[0],
					'session_date' => $s[1],
          'portion' => $s[2],
          'begin_time' => $s[3],
          'end_time' => $s[4],
				);
			}
		}
		
		if ( 0 == count($sel_session_list)) { // shouldn't happen, front end checks this
			drupal_set_message( t('Oops!  Something seems to have gone wrong.  No sessions selected.'));
			drupal_goto($goto_url);
			return;
			
		}
		else if ( 1 == count($sel_session_list)) {
			
			$session_id = $sel_session_list[0]['session_id'];
			$session_date = $sel_session_list[0]['session_date'];
      
      
      $begin_time = _st_format_schedule_date($sel_session_list[0]['begin_time'], 'Hi', $timezone);
      $end_time = _st_format_schedule_date($sel_session_list[0]['end_time'], 'Hi', $timezone);

			
			$session = _get_session( $schedule_id, $session_id );//$session_id);
			if ( $session == (object) Null ) {
				drupal_set_message( t('Oops!  Something seems to have gone wrong.  Session not found.'));
				drupal_goto($goto_url);
				return;
			}
			
			$session_date_display = str_replace('-', '/', $session_date);
			$form['session'] = array(
				'#markup' => 
					'<h3>' . $session_date_display . ', ' .
							$session->session_name . ': ' . $begin_time . ' - ' . $end_time . 
				 '</h3>',
			);	
			
		}
		else {  // multiple selected sessions -  get the sessions for this schedule
			
			$sched_sessions = _get_sessions($schedule_id, 0, ($key_by_id = True)) ;
			if ( !count($sched_sessions) ) {
				drupal_set_message( t('Oops!  Something seems to have gone wrong.  Schedule sessions not found.'));
				drupal_goto($goto_url);
				return;
			}
			
			$form['session'] = array(
				'#markup' =>  '<h3>' . t('Multiple') . '</h3>',
			);	
			
		}
	}
	else {
		// error -- missing required data
		drupal_set_message( t('Error.  Unable to continue with Session Assignment, missing required data.'));
		drupal_goto($goto_url); // go to main page -- not authorized for any other page
		return;
	}
	
	$form['#after_build'][] = 'schedule_assignment_form_after_build';
	
	
	$form['timestamp'] = array(
		'#markup' => ($assignment_id ? _st_format_record_timestamp_table($assignment) : '<hr />'),
	);
	
  
	$customer_list = new CustomerList();

	$form['customer_box'] = array(
		'#type' => 'fieldset',
		'#title' => t('Customer'),
		'#attributes' => array('id' => 'sch-customer-fieldset'),
	);

	$form['customer_box']['customer'] = array(
		'#type' => 'select',
		'#title' => t('Customer'),
		'#required' => True,
		'#options' => ($assignment_id ? $customer_list->getAll() : $customer_list->getActive() ),
		'#default_value' => ($assignment_id ? $assignment->customer_id : 0),
		'#validated' => True,
		'#attributes' => array('id' => 'sch-customer-select',
													 'class' => array('qms-select'),
													 'style' => 'clear:both;'),
		'#prefix' => '<div>',
		'#suffix' => '</div>',
	);	
	
	$form['customer_box']['group'] = array(
		'#type' => 'select',
		'#title' => t('Group'),
		'#required' => False,
		'#options' => ($assignment_id ? $customer_list->getCustomerGroups($assignment->customer_id) : 
																		array(0 => '- ' . t('Select') . ' -') ),
		'#default_value' => ($assignment_id ? $assignment->group_id : 0),
		'#validated' => True,
		'#attributes' => array('id' => 'sch-group-select',
													 'class' => array('qms-select')),
		'#prefix' => '<div>',
		'#suffix' => '</div>',		
	);	
	
	$form['settings_box'] = array(
		'#type' => 'fieldset',
		'#title' => t('Settings'),
		'#attributes' => array('id' => 'sch-settings-fieldset'),
		'#suffix' => '<br class="clearBoth">',
	);
	
	
	$type_list = new SessionTypeList();
	
	$form['settings_box']['session_type'] = array(
		'#type' => 'select',
		'#title' => t('Type'),
		'#required' => True,
		'#options' => $type_list->get(),
		'#default_value' => ($assignment_id ? $assignment->session_type : 1),  // default to full motion (1)
		'#validated' => True,
		'#attributes' => array('id' => 'sch-session-type-select',
													 'class' => array('qms-select')),
		//'#prefix' => '<div id="sch-type-div">',
		//'#suffix' => '</div>',
		
	);	
   
	
	$form['session_box'] = array(
		'#type' => 'fieldset',
		'#title' => (( $assignment_id || ( 1 == count($sel_session_list))) ? 
									t('Session Date & Time (actual)') : t('Sessions')),
		'#attributes' => array('id' => 'sch-session-fieldset'),
		'#suffix' => '<br class="clearBoth">',
	);
	
  
  /* Adding one assignment or Editing an Assignment (one at a time)  */
	if ( $assignment_id || ( 1 == count($sel_session_list)) ) {
    
    $begin_cal_date = 0;
    $end_cal_date = 0;
		
		if ( !$assignment_id ) {
      if ( 'P' == $sel_session_list[0]['portion']) {
        $begin_cal_date = _st_format_schedule_date($sel_session_list[0]['begin_time'], 'short', $timezone);
        $end_cal_date = _st_format_schedule_date($sel_session_list[0]['end_time'], 'short', $timezone);
      }
      else { // Full
        $isession_date = _st_format_schedule_timestamp($session_date_display, $timezone);  
        
        $ibegin_date = _format_timestamp($isession_date, $session->begin_time, $timezone);
        $iend_date = _format_timestamp($isession_date, $session->end_time, $timezone);
        if ( $ibegin_date > $iend_date) { $iend_date = _add_day_ts($iend_date); }

        $begin_cal_date = _st_format_schedule_date($ibegin_date, 'short', $timezone);
        $end_cal_date = _st_format_schedule_date($iend_date, 'short', $timezone);
        
        
        /*
        if (((int)$session->begin_time < 2400) && (2400 <= (int)$session->end_time)) {
          //$ed = _add_day_ts($isession_date);
          $end_time = sprintf('%04d', (int)$session->end_time - 2400);
          //$end_cal_date = _format_cal_date($ed, $end_time);
          
          $end_cal_date = _format_session_date($session_date, $end_time, $timezone, '+1 day');
          
        } else if ( (int)$session->begin_time > (int) $session->end_time ) {
          //$ed = $isession_date + SCH_ONE_TS_DAY
          //$ed = _add_day_ts($isession_date);
          //$end_cal_date = _format_cal_date($ed, $session->end_time);
          
          $end_cal_date = _format_session_date($session_date, $session->end_time, $timezone, '+1 day');
          
        } else {
          //$end_cal_date = _format_cal_date($isession_date, $session->end_time);
          $end_cal_date = _format_session_date($session_date, $session->end_time, $timezone);
        }
         * 
         */
      }
		}
		
		$form['session_box']['begin_date'] = array(
			'#type' => 'date_popup',
			'#title' => t('Begins'),
			'#size' => 15,
			'#date_format' => 'm-d-Y H:i',						// displayed format
				//default value has to be in this format 'Y-m-d
			'#default_value' => ( $assignment_id ? 
              _st_format_schedule_date($assignment->begin_timestamp, 'iso', $timezone) : 
              $begin_cal_date), 
			'#required' => True,   // if no date entered, returns NULL
			// don't set an id when there is a time involved (datepicker bug)
			// sets its own element id
			'#attributes' => array('class' => array('qms-date-picker')),
			'#prefix' => '<div id="sch-assignment-dates">',

		);
    
    $timezone = _get_schedule_timezone($schedule_id);
		
		$form['session_box']['end_date'] = array(
			'#type' => 'date_popup',
			'#title' => t('Ends'),
			'#size' => 15,
			'#date_format' => 'm-d-Y H:i',						// displayed format
				//default value has to be in this format 'Y-m-d
			'#default_value' => ( $assignment_id ? 
              _st_format_schedule_date($assignment->end_timestamp, 'iso', $timezone) :  
							$end_cal_date), 
			'#required' => True,   // if no date entered, returns NULL
			// don't set an id when there is a time involved (datepicker bug)
			// sets its own element id
			'#attributes' => array('class' => array('qms-date-picker')),
      '#suffix' => '<div class="timezone">'. t('Timezone') . ':&nbsp;&nbsp;'. $timezone .'</div></div>',
			//'#suffix' => '</div>',
		);
    
    
    /*----------------- Repeat Options -------------------*/
    /* Adding one assignment, but not editing */
    if ( !$assignment_id || ( 1 == count($sel_session_list)) ) {
      // allow for repeat option when one session selected for adding
      // do not allow for edit
      // do not allow for multi-select add
      
      $form['session_box']['repeat_box_begin'] = array(
        '#type' => 'markup',
        '#markup' => '<div id="sch-repeat-box">',
      );
      

      /*------------- Repeat-n Days ---------------*/
      $form['session_box']['repeat_days'] = array(
        '#type' => 'checkbox',
        '#title' => t('Repeat for'),
        '#default_value' => False, 
        '#attributes' => array('id' => 'sch-repeat-days-chk'),
        '#prefix' => '<div id="sch-repeat-days">'
      );	
      $form['session_box']['repeat_days_num'] = array(
        '#type' => 'textfield',
        //'#title' => t('Repeat'),
        '#maxlength' => 2,
        '#size' => 2,
        '#default_value' => False, 
        '#attributes' => array('id' => 'sch-repeat-days-num',
                               'class' => array('qms-numeric')),
      );	
      $form['session_box']['repeat_days_label'] = array(
          '#markup' => '<span class="sch-suffix-label">' . 
                        t('days total') . '</span></div>',
      );

      /*--------------- Repeat Until Date ----------*/
      $form['session_box']['repeat_until'] = array(
        '#type' => 'checkbox',
        '#title' => t('Repeat until (end on date)'),
        '#default_value' => False, 
        '#attributes' => array('id' => 'sch-repeat-until-chk'),
        '#prefix' => '<div id="sch-repeat-until">'
      );	
      $form['session_box']['repeat_until_date'] = array(
        '#type' => 'date_popup',
        //'#title' => t('Repeat'),
        '#size' => 11,
        '#date_format' => 'm-d-Y',						// displayed format
        '#default_value' => '', 
        '#attributes' => array('class' => array('qms-date-picker')),
        '#prefix' => '<div id="sch-repeat-until-date">',
        '#suffix' => '</div>',
      );
      
      $form['session_box']['repeat_box_end'] = array(
        '#type' => 'markup',
        '#markup' => '</div>',
      );
    }

		

		/*
		$form['session_box']['begin_time'] = array(
			'#type' => 'textfield',
			'#title' => t('Begin Time'),
			'#maxlength' => 4,
			'#size' => 4,
			'#required' => True,
			'#default_value' => ($assignment_id ? $assignment->begin_time_actual : $session->begin_time),
			'#attributes' => array('id' => 'sch-assignment-begin-time'),
		);	

		$form['session_box']['end_time'] = array(
			'#type' => 'textfield',
			'#title' => t('End Time'),
			'#maxlength' => 4,
			'#size' => 4,
			'#required' => True,
			'#default_value' => ($assignment_id ? $assignment->end_time_actual : $session->end_time),
			'#attributes' => array('id' => 'sch-assignment-begin-time'),
			//'#suffix' => '<br class="clearBoth">',
		);
		*/
		
		// hidden storage area 	
		
		$form['session_id'] = array(
			'#type' => 'textfield',
			'#default_value' => ($assignment_id ? $assignment->schedule_session_id : $session_id),
			'#attributes' => array('class' => array('qms-hidden'),
															'id' => 'sch-session-id'),
		);	
		$form['session_date_selected'] = array(
			'#type' => 'textfield',
			'#default_value' => $session_date,
			'#attributes' => array('class' => array('qms-hidden'),
															'id' => 'sch-session-date'),
		);	

		$form['begin_time_orig'] = array(
			'#type' => 'textfield',
			//'#default_value' => ($assignment_id ? $assignment->begin_time_actual : $session->begin_time),
			'#default_value' => $session->begin_time,
			'#attributes' => array('class' => array('qms-hidden'),
															'id' => 'sch-begin-time-orig'),
		);	

		$form['end_time_orig'] = array(
			'#type' => 'textfield',
			//'#default_value' => ($assignment_id ? $assignment->end_time_actual : $session->end_time),
			'#default_value' => $session->end_time,
			'#attributes' => array('class' => array('qms-hidden'),
															'id' => 'sch-end-time-orig'),
		);	
    
    
    
		
	}
	else {
    /* Adding multiple assignments based on grid selections  */
		
		// display a list of selected sessions 
		$table_header = array(
			array('data' => t('Date'), 'class' => array('sch-sess-tbl-date')),
			array('data' => t('Name'), 'class' => array('sch-sess-tbl-name')),
			array('data' => t('Begins'), 'class' => array('sch-sess-tbl-begins')),
			array('data' => t('Ends'), 'class' => array('sch-sess-tbl-ends')),
		);
		$table_rows = array();
		$i = 0;

		foreach ($sel_session_list as $s) {
			$sdate = str_replace('-', '/', $s['session_date']);
      $row_data = array();
      
      if ( 'P' == $s['portion']) {
        $row_data = array(
          $sdate,
          $sched_sessions[$s['session_id']]['session_name'],
          _st_format_schedule_date($s['begin_time'],'Hi', $timezone),
          _st_format_schedule_date($s['end_time'], 'Hi', $timezone),
        );
      }
      else { // Full session
        $row_data = array(
          $sdate,
          $sched_sessions[$s['session_id']]['session_name'],
          $sched_sessions[$s['session_id']]['begin_time'],
          $sched_sessions[$s['session_id']]['end_time'],
        );
      }

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

		$content = theme( 'table', array(
			'header' => $table_header,
			'rows' => $table_rows,
			'empty' => t('None'),
			'attributes' => array('id' => 'sch-sess-display'),
		));		
		
		$form['session_box']['session_table'] = array(
			'#markup' => $content,
		);
		
		
		// hidden storage area 	
		$form['selected_sessions'] = array(
			'#type' => 'textarea',
			'#default_value' => $sel_sessions,
			'#attributes' => array('class' => array('qms-hidden'),
															'id' => 'sch-selected-sessions'),
			'#prefix' => '<div class="qms-hidden">',
			'#suffix' => '</div',
		);	
	}
  
  //------------- Note Text Editor -----------------
	$text_settings = array(
		'name' => 'note_text',
		'title' => t('Notes'),
		'text' =>	(isset($assignment->note_text) ? $assignment->note_text : ''),
		'required' => False,
	);
	 
	_st_add_text_editor($form, $text_settings);
	
	
	// hidden storage area 	

	$form['assignment_id'] = array(
		'#type' => 'textfield',
		'#default_value' => $assignment_id,
		'#attributes' => array('class' => array('qms-hidden'),
														'id' => 'sch-assignment-id'),
	);	
	$form['schedule_id'] = array(
		'#type' => 'textfield',
		'#default_value' => ($assignment_id ? $assignment->schedule_id : $schedule_id),
		'#attributes' => array('class' => array('qms-hidden'),
														'id' => 'sch-schedule-id'),
	);	

	
	$group_text = '';
	$all_groups = $customer_list->getAllCustomerGroups();
	foreach($all_groups as $cust_id => $groups) {
		$group_list = array();
		foreach($groups as $gid => $g) {
			$group_list[] = $gid . '=' . $g;
		}
		$group_text .= $cust_id . '[' . implode('|', $group_list) . ']';
	}
	
	$form['customer_groups'] = array(
		'#markup' => '<div id="sch-customers-groups" class="qms-hidden">' . $group_text . '</div>',
	);
	
	
	// buttons
	$form['actions'] = array('#type' => 'actions');
	$form['actions']['submit'] = array(
		'#type' => 'submit',
		'#value' => t('Submit'),
    '#name' => 'submit',
	);
  $form['actions']['done'] = array(
		'#type' => 'submit',
		'#value' => t('Done'),
    '#name' => 'done',
		'#attributes' => array('class' => array('qms-btn-done', 'qms-btn-extra')),
                           //'onclick' => 'window.location="' . 
                                //url($goto_url) . '"; 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.
*/

/* 
 * assignment_form_after_build()
 *
 */

function schedule_assignment_form_after_build($form, &$form_state) {
	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', 'sabreTools') . '/js/sabreTools.ckeditor.js');
	
	drupal_add_js(drupal_get_path('module', 'sabreScheduler') . '/js/sabreScheduler.assignments.js');
  
  global $base_url;
	drupal_add_js( $base_url . QMS_CKEDITOR_PATH_CONFIG);
	// need to specify preprocess == false otherwise 'Aggregate Javascript' setting in drupal 
	// causes ckeditor not to load properly
	// adding scope to footer speeds up the page load
	drupal_add_js( $base_url . QMS_CKEDITOR_LIB, array('type' => 'file', 'scope' => 'footer', 'preprocess' => FALSE));
	
	return $form;
}

/* 
 * assignment_form_validation($form, $form_state)
 *
 */
function schedule_assignment_form_validate($form, $form_state) {
  
  $button_clicked = $form_state['triggering_element']['#name'];
  
  if ( $form['actions']['submit']['#name'] != $button_clicked ) {
    form_clear_error();
    $destination = drupal_get_destination();
    drupal_goto($destination['destination']);
    return $form;
  }
	
	if ( $form_state['values']['customer'] == 0) {
		form_set_error('customer', t('Customer selection is required.'));
	}
	
	if ( $form_state['values']['session_type'] == 0) {
		form_set_error('session_type', t('Session Type selection is required.'));
	}
  
  $schedule = Null;
  if (isset($form_state['values']['schedule_id'])) {
    $schedule_id = $form_state['values']['schedule_id'];
    $schedule = _get_schedule($schedule_id);
    if (empty($schedule)) {
      form_set_error('begin_date', t('Error:  Missing Schedule.'));
      return;
    }
  }
  $timezone = $schedule->timezone;
  
	
	//--- if only dealing with one session adding/editing, do validation ---- 
	// otherwise validate during the multi add process
	// selected_sessions only set if this is an add with a list of selected sessions
	if ( !isset( $form_state['values']['selected_sessions'] ) )  {
		
		$begin_date = $form_state['values']['begin_date'];
		$end_date = $form_state['values']['end_date'];
		
		if (  !isset($begin_date) || ($begin_date == '') || 
					 !isset($end_date) || ($end_date == '')   )  {
						
			if ( !isset($begin_date) || ($begin_date == '') ) {
				form_set_error('begin_date', t('Unable to save Schedule Assignment.  Session Begins is a required field'));
			}
			if ( !isset($end_date) || ($end_date == '') ) {
				form_set_error('end_date', t('Unable to save Schedule Assignment.  Session Ends is a required field'));
			}
			return;
		}
				
		
		$begin_time_ts = _st_format_schedule_timestamp($begin_date, $timezone);
		$end_time_ts = _st_format_schedule_timestamp($end_date, $timezone);
		
		if ( $begin_time_ts > $end_time_ts ) {
			form_set_error('begin_date', 
				t('Invalid session dates.  Session Begins cannot be set to a later date than Session Ends'));
				return;
		}
    
    
    // validate repeat settings
    // actual repeated sessions do not get validated for conflicts until they are created
    if ( isset($form_state['values']['repeat_days'])) {
      if ( 1 == (int)$form_state['values']['repeat_days'] ) {
        $day_count = (int)$form_state['values']['repeat_days_num'];
        if ( $day_count < 2 ) {
          form_set_error('repeat_days_num', 
                t('Value entered for "Repeat for ___ days total" must be 2 or greater.'));
        }
      }
      if ( 1 == (int)$form_state['values']['repeat_until']) {
        $end_on_date = $form_state['values']['repeat_until_date'];
        if ( '' == $end_on_date ) {
          form_set_error('repeat_until', 
                  t('"Repeat until (end on date)" requires a valid date value.'));
        }
        else {
          $eod_ts = _st_format_schedule_timestamp($end_on_date, $timezone);
          if ( $eod_ts <= $end_time_ts ) {
            form_set_error('repeat_until', 
                t('"Repeat until (end on date)" must be a later date than the specified session end date and time'));
          }
        }
      }
    }

		
		//-- check if date entered conflicts with another assignment
		$assignment_id = (int)$form_state['values']['assignment_id'];
		$schedule_id = (int)$form_state['values']['schedule_id'];
		$session_id = (int)$form_state['values']['session_id'];
		
		$sessValidator = new SessionValidator($assignment_id, 0, $schedule_id, 
																					$session_id, $begin_time_ts);
		
		
		// assignment can be extended in each direction, exceeding current session
		// when this happens, we are essentially creating new assignments for new overlapping sessions
		// provided that they are not already booked
		
		$result = $sessValidator->checkForConflict('A', $begin_time_ts, $end_time_ts);

		if ( ($result != SessionValidator::SV_NOCONFLICT) ) {
			$conflict_text = '';
      
      if ($result == SessionValidator::SV_SCHEDULE_RANGE) {
        list($schedule_begin_date_f, $schedule_end_date_f) = $sessValidator->getScheduleRange();
        $conflict_text .= '<li>' . t('Exceeds schedule date range') . ': '. 
                                  $schedule_begin_date_f . ' - ' . $schedule_end_date_f . '</li>';
                                   
      }
      
			$assigns = $sessValidator->getAssignmentConflicts();
			foreach($assigns as $a) {
				$conflict_text .= '<li>' . $a->session_name . ':  ' . 
                                   $a->begin_timestamp_f . ' - ' . $a->end_timestamp_f . '</li>';
			}
      
      $excepts = $sessValidator->getExceptionConflicts();
      foreach($excepts as $ex) {
        $conflict_text .= '<li>' . $ex->exception_desc . ':  ' . 
                                   $ex->begin_timestamp_f . ' - ' . $ex->end_timestamp_f . '</li>';
      }
			
			form_set_error('begin_date', 
				t('This assignment date & time conflicts with existing assignments, exceptions, or schedule date range.') . 
					(strlen($conflict_text) ? '<ul>' . $conflict_text . '</ul>' : '' )
				);
		}

	}
  
  
}

/* 
 * assignment_form_submit()
 *
 */
function schedule_assignment_form_submit($form, $form_state) {
  
  
  
  // determine where we go if we have an error here.
	$destination = drupal_get_destination();
	$goto_url = $destination['destination'];

	if( !strlen($goto_url) || ($goto_url == current_path()) ) {
		$goto_url = 'schedule/grid';  // last resort option
	}
  
  //---------------- Button Handlers --------------------
  
  $button_clicked = $form_state['triggering_element']['#name'];
  
  if ( isset($form['actions']['done']['#name']) && 
            ($form['actions']['done']['#name'] == $button_clicked) ){
    
    unset($_SESSION['sel_grid_sessions']);
    drupal_goto($goto_url);
    
  }
  else if ( $form['actions']['submit']['#name'] != $button_clicked ) {
    // if not done, then make sure its a submit click, otherwise, return
    return;
  }
  
  //---------------- SUBMIT:  Process Form --------------------
	
	
	global $user;
	$sessValidator = new SessionValidator();
	$selected_sessions = '';
	$sel_session_list = array();
	$sched_sessions = array();
	$sess_id_map = array();
  $conflicts_s = array();
	$conflicts_a = array();
  $conflicts_e = array();
	$bSkipped = False;
	$assignment_id = 0;
  $repeat_count = 1;
  $interval_days = 0;
	$bError = False;
  $assign_type = SCHED_TYPE_SELECTED;
	
	
	
	$assignment_id = (int)$form_state['values']['assignment_id'];
  $assignment = new stdClass();
	$assignment->schedule_id = (int)$form_state['values']['schedule_id'];
	$assignment->customer_id = (int)$form_state['values']['customer'];
	$assignment->group_id = (int)$form_state['values']['group'];
	$assignment->session_type = (int)$form_state['values']['session_type'];
	$assignment->cut_bill = 0;
  $assignment->note_text = _st_clean_ckeditor_text($form_state['values']['note_text_editor_value']);
  
  $timezone = _get_schedule_timezone($assignment->schedule_id);
  
  if ( isset($form_state['values']['repeat_days']) ) {
    if ( 1 == (int)$form_state['values']['repeat_days'] ) {
      $repeat_days_num = (int)$form_state['values']['repeat_days_num'];
      if ( $repeat_days_num > 1) {
        $repeat_count = $repeat_days_num;
      }
      $assign_type = SCHED_TYPE_REPEAT_N_DAYS;
    }
    else if ( 1 == (int)$form_state['values']['repeat_until'] ) {
      // add seconds to make it ISO format
      $begin_date = $form_state['values']['begin_date'] . ':00';
      $end_date = $form_state['values']['end_date'] . ':00';
      $end_on_date = $form_state['values']['repeat_until_date'];

      $repeat_days_num = _calc_repeat_days($begin_date, $end_date, $end_on_date, $timezone);
      if ( $repeat_days_num > 1 )  {
        $repeat_count = $repeat_days_num;
      }
      $assign_type = SCHED_TYPE_REPEAT_UNTIL;
    }
  }
	
	
	// get the sessions for the current schedule
	$sched_sessions = _get_sessions($assignment->schedule_id, 0, ($key_by_id = True)) ;
	if ( !count($sched_sessions) ) {
		drupal_set_message( t('Oops!  Something seems to have gone wrong.  Schedule sessions not found.'));
		drupal_goto($goto_url);
		return;
	}
	
	
  
	if ( isset($form_state['values']['selected_sessions']) ) {
    /*--------------- Add Assignments from Grid Selected Open Sessions ------------*/
    
		// this is a multi-add situation, individual session fields not set, 
		// we have a list of session ids and dates instead, parse the array
		
		$selected_sessions = $form_state['values']['selected_sessions'];
		$session_arr = explode('&', $selected_sessions);
		
		$n = 0;
		for($i=0; $i<count($session_arr); $i++) {
			if ( strlen($session_arr[$i])) {
				$s = explode('~', $session_arr[$i]);
        $s[1] = str_replace('-', '/', $s[1]);
        $sd = _st_format_schedule_timestamp($s[1], $timezone);
				$sel_session_list[$n++] = array(
					'session_id' => $s[0],
					'session_date' => $sd,
          'portion' => $s[2],
          'begin_time' => $s[3],
          'end_time' => $s[4],
				);
			}
		}
	}
	else {
    
    /*--------------- Single Assignment Edit or Add ------------*/
		$bts = $form_state['values']['begin_date'];
		$ets = $form_state['values']['end_date'];
		

		$assignment->begin_timestamp = _st_format_schedule_timestamp($bts, $timezone);
		$assignment->end_timestamp = _st_format_schedule_timestamp($ets, $timezone);
    
    $base_interval = $assignment->end_timestamp - $assignment->begin_timestamp;
    $interval_days = ceil($base_interval / SCH_ONE_TS_DAY); //always round up
    if ( $interval_days < 1) { $interval_days = 1; }
    
		
		$assignment->begin_time_actual = _st_format_schedule_date($assignment->begin_timestamp, 'Hi', $timezone);
		$assignment->end_time_actual = _st_format_schedule_date($assignment->end_timestamp, 'Hi', $timezone);
		
		$assignment->schedule_session_id = (int)$form_state['values']['session_id'];
		
    // assignment date now reflects the date of the session the assignment is booked in
    // if session starts before midnight, assignment booked for partial, after midnight,
    // assignment_date is the previous day when the session block began
		//$assign_date = _st_left($bts, 10) . ' 00:00:00';
		$assignment->assignment_date = _st_format_schedule_timestamp($bts, $timezone);
		
		//---------- everything on normal session settings up until here ---------------
    
    /*--------------- Add/Edit Assignment using input date&times  ------------*/	
		// the new session times can overlap multiple sessions & times
		// we need to create a separate assignment for each of those sessions
    
    $session_begin_time = $sched_sessions[$assignment->schedule_session_id]['begin_time'];
    $session_end_time = $sched_sessions[$assignment->schedule_session_id]['end_time'];
    
    // Is a non-standard time range selected for the assignment?
		if ( ( $session_begin_time != $assignment->begin_time_actual) ||
		 		 ($session_end_time != $assignment->end_time_actual)	) {
      
      $assign_type = SCHED_TYPE_DATE_RANGE;
      
      // assignment is using non-standard time-range, we need to determine how
      // many sessions will be included & booked for the submitted assignment time range
        $sel_session_list = _get_selected_session_range('A', $assignment, $sched_sessions, $timezone);		
		}
	}
	
	$sel_count = count($sel_session_list);
	
	// hang on to the original session_id
	$schedule_session_id = ($assignment_id ? $assignment->schedule_session_id : 0 );
	
	// enter the loop at least once
  // if adding one normal assignment (std session times)
  // editing a session with (std session times)
  // ... or adding/editing with expanded session input times (loop multiple times)
	$max_count = ( $sel_count ? $sel_count : 1);
	
  
  //--------------------- REPEAT OPTION ------------------------
  // should go through here at least once
  for ($r=0; $r < $repeat_count; $r++) {
    
  
    //----------- HANDLE MULTI-ADD to list of sessions -----------
    // the first assignment's session has already been set up above
    for ( $n = 0; $n < $max_count; $n++ ) {
      // new record
      $blocked = False;


      if ( $sel_count ) {
        // multi-add -- uses session times'
        $session_id = $sel_session_list[$n]['session_id'];
        $assignment->schedule_session_id = $session_id;


        if ( !isset($sel_session_list[$n]['begin_timestamp']) ) {
//             || ($assign_type == SCHED_TYPE_DATE_RANGE) ) {
          // no repeating option here
          // these sessions are based on selected open session from the grid
          // these were not set above for non-standard session times,
          // use the normal session time if portion of session is Full
          // use submitted session times if portion of session is Partial
          if ( !empty($sel_session_list[$n]['portion']) && ('P' == $sel_session_list[$n]['portion']) ) {
            // PARTIAL session use submitted times
            // begin_time and end_time from the sel_sesson_list are full timestamps
            $assignment->assignment_date = $sel_session_list[$n]['session_date'];
            if ($assign_type == SCHED_TYPE_DATE_RANGE) {
              $assignment->begin_timestamp = $sel_session_list[$n]['begin_timestamp'];
              $assignment->end_timestamp = $sel_session_list[$n]['end_timestamp'];
            } else  {
              $assignment->begin_timestamp = $sel_session_list[$n]['begin_time'];
              $assignment->end_timestamp = $sel_session_list[$n]['end_time'];
            }
             
            
            _calc_assignment_time_from_timestamp($assignment);
          }
          else {  // FULL session - use standard times
            $assignment->begin_time_actual = $sched_sessions[$session_id]['begin_time'];
            $assignment->end_time_actual = $sched_sessions[$session_id]['end_time'];
            // different date formats, too
            //$session_date = str_replace('-', '/', $sel_session_list[$n]['begin_time']);
            $assignment->assignment_date = _format_timestamp($sel_session_list[$n]['session_date'], 
                                                            $assignment->begin_time_actual, $timezone);
          }
          //_calc_assignment_time($assignment);
        } else {
          // repeat option capable
          // these sessions are calculated based on the input date & time ranges
          // use the calculated session dates and times
          //$assignment->assignment_date = $sel_session_list[$n]['session_date'];
          $assignment->assignment_date = $sel_session_list[$n]['session_date'];
          $assignment->begin_timestamp = $sel_session_list[$n]['begin_timestamp'];
          $assignment->end_timestamp = $sel_session_list[$n]['end_timestamp'];
          $assignment->begin_time_actual = $sel_session_list[$n]['begin_time'];
          $assignment->end_time_actual = $sel_session_list[$n]['end_time'];
          
          //---- increment days for repeat interval ---------
          // SCH_ONE_TS_DAY == seconds per day
          // here the date & ts values are stored & accessed from the $sel_session_list
          // not cumulative so use the $repeat_count as a multiplier for the days as
          // the repeat value gets further away from the base values
//          $assignment->assignment_date += (SCH_ONE_TS_DAY * $interval_days * $r);
//          $assignment->begin_timestamp += (SCH_ONE_TS_DAY * $interval_days * $r);
//          $assignment->end_timestamp += (SCH_ONE_TS_DAY * $interval_days * $r);
          
          $assignment->assignment_date = 
                  _add_day_ts($assignment->assignment_date, $interval_days * $r);
          $assignment->begin_timestamp =
                   _add_day_ts($assignment->begin_timestamp, $interval_days * $r);
          $assignment->end_timestamp =
                   _add_day_ts($assignment->end_timestamp, $interval_days * $r);
          
          $assignment->total_time = _date_diff_seconds($assignment->begin_timestamp,
                                                       $assignment->end_timestamp);
        }
      } else {
      
        //---- increment days for repeat interval ---------
        // SCH_ONE_TS_DAY == seconds per day
        // for a single session repeat, the date * ts values are cumulative
        // so don't use the repeat count multiplier
        if ( $r > 0 ) {
          // don't increment until after the base values are processed
//          $assignment->assignment_date += (SCH_ONE_TS_DAY * $interval_days);
//          $assignment->begin_timestamp += (SCH_ONE_TS_DAY * $interval_days);
//          $assignment->end_timestamp += (SCH_ONE_TS_DAY * $interval_days);
          
          $assignment->assignment_date = 
                  _add_day_ts($assignment->assignment_date, $interval_days);
          $assignment->begin_timestamp =
                   _add_day_ts($assignment->begin_timestamp, $interval_days);
          $assignment->end_timestamp =
                   _add_day_ts($assignment->end_timestamp, $interval_days);
          
          $assignment->total_time = _date_diff_seconds($assignment->begin_timestamp,
                                                       $assignment->end_timestamp);
        }
      }
      
      

      if ($assignment_id && ($schedule_session_id == $assignment->schedule_session_id) ) {
        // editing the original session
        $assignment->assignment_id = $assignment_id;
        $assignment->updated_date = REQUEST_TIME;
        $assignment->updated_by_user = $user->uid;
      }
      else {
        // add
        $assignment->created_date = REQUEST_TIME;
        $assignment->created_by_user = $user->uid;
      }

      if ( !isset($assignment->total_time) ) { _calc_assignment_time($assignment); }


      $sessValidator->init($assignment_id, 0, $assignment->schedule_id, 
                              $assignment->schedule_session_id, 
                              $assignment->assignment_date);
      $result = $sessValidator->checkForConflict('A', $assignment->begin_timestamp, 
                                                $assignment->end_timestamp);


      if ( SessionValidator::SV_NOCONFLICT == $result ){

        if ($assignment_id && ($schedule_session_id == $assignment->schedule_session_id) ) {
          // saving the original assignment
          if ( False == drupal_write_record('sch_assignments', $assignment, 'assignment_id')) {
            $msg = "Oops!  Something went wrong updating the assignment.";
            drupal_set_message(t($msg));
            drupal_goto($goto_url);
            return False;
          }
        }
        else { // adding session assignments
          if ( False == drupal_write_record('sch_assignments', $assignment)) {
            $msg = ( $sel_count ? 
                      t("Oops!  Something went wrong saving the assignment sequence") :
                      t("Oops!  Something went wrong saving the assignment") );
            drupal_set_message(t($msg));
            drupal_goto($goto_url);
            return False;
          }
        }
      }
      else {
        if ($result == SessionValidator::SV_SCHEDULE_RANGE) {
          $conflicts_s += $sessValidator->getScheduleRange();
        }
        $conflicts_a += $sessValidator->getAssignmentConflicts();
        $conflicts_e += $sessValidator->getExceptionConflicts();
        $bSkipped = True;
      }

      // clear this in the event this is a multi-add situation
      if ( isset($assignment->assignment_id) ) { 
        unset($assignment->assignment_id); 
        unset($assignment->total_time);
      }
    } // end -- FOR LOOP -  SESSION MULTI-ADD
    
  } // end -- FOR LOOP - REPEAT COUNT
	
	
	$msg = ( 1 < $sel_count ? t('Assignments') : t('Assignment'))  . 
					t(' successfully saved.');
	drupal_set_message( $msg );
	
	if ( $bSkipped ) {
		$conflict_text = '';
    if (!empty($conflicts_s)) {
      $conflict_text .= '<li>' . $a->session_name . ':  ' . 
                                $conflicts_s[0] . ' - ' . $conflicts_s[1] . '</li>';
    }
		foreach($conflicts_a as $a) {
			$conflict_text .= '<li>' . $a->session_name . ':  ' . 
                                $a->begin_timestamp_f . ' - ' . $a->end_timestamp_f . '</li>';
		}
    foreach($conflicts_e as $ex) {
      $conflict_text .= '<li>' . $ex->exception_desc . ':  ' . 
                                 $ex->begin_timestamp_f . ' - ' . $ex->end_timestamp_f . '</li>';
    }
			
		
		drupal_set_message( t('One or more conflicts with existing assignments or exceptions were found.') . 
													'<br />' . 
												t('New assignments were not created where sessions were already assigned.') .
												(strlen($conflict_text) ? '<ul>' . $conflict_text . '</ul>' : '' ) );
	}
  
  unset($_SESSION['sel_grid_sessions']);
	
	drupal_goto($goto_url);
	return True;
}






/*
 *	_paste_one_assignment_to_many_sessions() 
 *
 *   single assignment copied/cut, previously saved to clipboard
 *   now paste it to multiple selected session locations
 *	 the session_list array contains the multi sessions being pasted into
 */
function _paste_one_assignment_to_many_sessions($schedule_id, $sel_session_list, $clipboard) {
	
	if ( !$schedule_id || !count($sel_session_list) || !count($clipboard) ) { return False; }
	
	// get list of all sessions for this schedule
	$schedule_sessions = _get_sessions($schedule_id, 0, ($key_by_id = True));
	if ( !count($schedule_sessions) ) { return False; }
	
	global $user;
	$sessValidator = new SessionValidator();
	
	// get the clipboard assignment values
	$customer_id = (int)$clipboard[0]['customer_id'];	
	$group_id = (int)$clipboard[0]['group_id'];	
	$session_type = (int)$clipboard[0]['session_type'];
  $note_text = $clipboard[0]['note_text'];
	
	// create the assignments for each selected session
	foreach ( $sel_session_list as $s ) {
		
		$session_id = $s['session_id'];
    $timezone = $schedule_sessions[$session_id]['timezone'];

		$sdate = str_replace('-', '/', $s['session_date']);
		$session_date = _st_format_schedule_timestamp($sdate, $timezone);
		
		$assignment = new stdClass();
		$assignment->schedule_id = $schedule_id;
		$assignment->schedule_session_id = $session_id;
		$assignment->assignment_date = _format_timestamp($session_date, 
                                   $schedule_sessions[$session_id]['begin_time'],
                                   $timezone);
		$assignment->created_date = REQUEST_TIME;
		$assignment->created_by_user = $user->uid;
		$assignment->customer_id = $customer_id;
    $assignment->note_text = $note_text;
		$assignment->group_id = $group_id;
		$assignment->session_type = $session_type;
		//$assignment->cut_bill = 0;
    if ( 'P' == $s['portion'] ) {
      $assignment->begin_timestamp = $s['begin_time'];
      $assignment->end_timestamp = $s['end_time'];
      _calc_assignment_time_from_timestamp($assignment);
    }
    else { // FULL session (normal session time)
      $assignment->begin_time_actual = $schedule_sessions[$session_id]['begin_time'];
      $assignment->end_time_actual = $schedule_sessions[$session_id]['end_time'];
      
      // calculate the timestamps and total time
      _calc_assignment_time($assignment);	
    }
   

		$sessValidator->init(0, 0, $schedule_id,  $session_id, $session_date);
		$result = $sessValidator->checkForConflict('A', $assignment->begin_timestamp, $assignment->end_timestamp);

		if ( $result == SessionValidator::SV_NOCONFLICT ) {
		
			if ( False == drupal_write_record('sch_assignments', $assignment)) {
				$bSkipped = True;
			}
		}
		else {
			$bSkipped = True;
		}
		// precautionary
		if ( isset($assignment->assignment_id) ) { 
			unset($assignment->assignment_id); 
		}
	}

	
}



/*
 *	_paste_many_clipboard_assignments() 
 *
 *		Takes clipboard data and creates new assignments from a previous cut or copy
 *		new assignments created at the specified schedule/session/date location
 *		the session_list (only the first session used - top left) as the beginning position
 *    from which to paste the cluster of assignments
 */
function _paste_many_clipboard_assignments($schedule_id, $session_list, $clipboard) {
	
	if ( !$schedule_id || !count($session_list) || !count($clipboard) ) { return False; }
	
	// grab the first session in the list for position, ignore the rest
	$session_id = $session_list[0]['session_id'];
	$session_date = $session_list[0]['session_date'];
	
	if ( !$session_id || !strlen($session_date) ) { return False; }
	
	global $user;
	$bSkipped = False;
	$sessValidator = new SessionValidator();
	
	$sess_map = _get_session_map(0, $schedule_id);
	$sdate = str_replace('-', '/', $session_date);
	$base_date = _st_format_schedule_timestamp($sdate, $timezone);
	$base_index = null;
	
	foreach ($sess_map as $index => $sess)  {
      if ($sess['schedule_session_id'] == $session_id)  {   
          $base_index = $index;  
					// the index of the session location (in order) where the assignments should be pasted.
					break;
      } 
  }
  if ( $base_index == null ) { $base_index = 0; } // couldnt find the base index, force to zero
	
	$sess_offset = $base_index - $clipboard[0]['y'];   //determine the offset from the first clipboard assignment

	for ( $n = 0; $n < count($clipboard); $n++ ) {
		
		$sess_index = $clipboard[$n]['y'] + $sess_offset;
		$calc_sess_id = (isset($sess_map[$sess_index]['schedule_session_id']) ? $sess_map[$sess_index]['schedule_session_id'] : 0);
		
		if ( $calc_sess_id ) {
			// is this a valid session_id?  it could be the paste session is going off-grid
			
			$assignment = new stdClass();
			$assignment->schedule_id = $schedule_id;
			$assignment->schedule_session_id = $calc_sess_id;
			$assignment->assignment_date = 
              _add_day_ts($base_date, $clipboard[$n]['x']);
              
         //$base_date + ($clipboard[$n]['x'] *SCH_ONE_TS_DAY ); 
         // SCH_ONE_TS_DAY seconds in a day, x is the day multiplier
			$assignment->begin_time_actual = $sess_map[$sess_index]['begin_time'];
			$assignment->end_time_actual = $sess_map[$sess_index]['end_time'];
			$assignment->created_date = REQUEST_TIME;
			$assignment->created_by_user = $user->uid;
			$assignment->customer_id = (int)$clipboard[$n]['customer_id'];	
      $assignment->note_text = $clipboard[$n]['note_text'];
			$assignment->group_id = (int)$clipboard[$n]['group_id'];	
			$assignment->session_type = (int)$clipboard[$n]['session_type'];	
			//$assignment->cut_bill = 0;
			_calc_assignment_time($assignment);	
      
		}

		$sessValidator->init(0, 0, $assignment->schedule_id,  $assignment->schedule_session_id, $assignment->assignment_date);
		$result = $sessValidator->checkForConflict('A', $assignment->begin_timestamp, $assignment->end_timestamp);

		if ( $result == SessionValidator::SV_NOCONFLICT ) {
		
			if ( False == drupal_write_record('sch_assignments', $assignment)) {
				$bSkipped = True;
			}
		}
		else {
			$bSkipped = True;
		}
		// precautionary
		if ( isset($assignment->assignment_id) ) { unset($assignment->assignment_id); }
	}
	
}


/*
 *	_get_selected_assignments($assignments) 
 *
 *	Accepts a comma-separated list of assignment ids
 *  returns the assignments in the list
 */
function _get_selected_assignments($assignment_ids) {
	try {
		$assign_list = array();
		
		if ( strlen($assignment_ids) == 0) { return array(); }
		
		
		// need to turn text list of comma-sep ids into an array
		//$id_list = explode(',', $assignment_ids);
    
    // this breaks down the list into an array of separate int ids
    $id_list = json_decode('[' . $assignment_ids . ']', true);
		$sess_map = _get_session_map($id_list[0]);
		
		if ( count($sess_map) == 0 ) {
			return $assign_list;  // fail
		}
		
		$query = db_select('sch_assignments', 'a');
		$query->condition('assignment_id', $id_list, 'IN');
		$query->fields('a', array('customer_id', 'group_id', 'session_type', 
                              'schedule_session_id', 'begin_timestamp', 'end_timestamp','note_text' ));
		$query->orderBy('begin_timestamp', 'ASC')->orderBy('schedule_session_id', 'ASC');
		$results = $query->execute();
		
		$base_date = 0;
		
		if ( $results->rowCount() ) {
			$i = 0;
			$date_diff = 0;
			foreach($results as $row) {
				// need to create a new array so that we can calculate what the original grid layout was based
				// on the date span and the session span
				// store with the relative grid settings based on the 
        // first selected assignment as a base_date & session_id
				// then all other selected assignments are +1, +2, etc. in relation to the base assignment
				// we need to know this for when we paste.
				
				if ( $i == 0 ) { 
					$date_diff = 0;
					$base_date = $row->assignment_date;
				}
				else {
					$date_diff = ($row->assignment_date - $base_date) / SCH_ONE_TS_DAY; // SCH_ONE_TS_DAY=seconds in a day
				}
				$assign_list[] = array(
					'customer_id' => $row->customer_id,
					'group_id' => $row->group_id,
					'session_type' => $row->session_type,
          'note_text' => $row->note_text,
					'y' => $sess_map[$row->schedule_session_id],
					'x' => $date_diff,
				);
				$i++;
			}
		}
		return $assign_list;
	}
	catch(Exception $e) {
		watchdog(SCH_SCHEDULER, '_get_selected_assignments() ' . $e->getMessage(), array(), WATCHDOG_ERROR);
	}
}

/*
 *	_delete_selected_assignments($assignments) 
 *
 *	Accepts a comma-separated list of assignment ids
 *  deletes the assignments in the list
 */
function _delete_selected_assignments($assignment_ids) {
  
	try {
		
		$num_rows = 0;
		
		if ( strlen($assignment_ids) ) {
		
      // this breaks down the list into an array of separate int ids
      $assign_id_list = json_decode('[' . $assignment_ids . ']', true);
      $delete_ids = $assign_id_list;
      
      
      $query = db_select('sch_elogs', 'e');
      $query->condition('assignment_id', $assign_id_list, 'IN');
      $query->fields('e', array('assignment_id'));
      $result = $query->execute();
      
      if ( $result->rowCount() ) {
        $elog_assign_ids = array();
        
        foreach($result as $row) {
          $elog_assign_ids[] = (int)$row->assignment_id;
        }
        
        $delete_ids = array_diff($assign_id_list, $elog_assign_ids);
      }
      
      
			
			// only allow delete on assignments that do not have e-logs linked
      if ( count($delete_ids) ) {
        $num_rows = db_delete('sch_assignments')
                    ->condition('assignment_id', $delete_ids, 'IN')
                    ->execute();
      }
              
                  /*
                  ->where('assignment_id IN (:ids1) 
                           AND assignment_id NOT IN 
                           (SELECT assignment_id FROM sch_elogs WHERE assignment_id IN (:ids2))', 
                          array(':ids1' => $assignment_ids,
                                ':ids2' => $assignment_ids)) */
               
									//->condition('assignment_id', $id_list, 'IN')
									//->condition('assignment_id', $subquery_result, 'NOT IN')
									//->execute();		
		}
		return $num_rows;			
	}
	catch(Exception $e) {
		watchdog(SCH_SCHEDULER, '_delete_selected_assignments() ' . 
                            '$assignment_ids=' . $assignment_ids . '; ' . 
                            'queryString=' . $result->queryString . '; ' . 
                            $e->getMessage(), array(), WATCHDOG_ERROR);
	}
}


/*
 *	_cut_bill_selected_assignments($assignments) 
 *
 *	Accepts a comma-separated list of assignment ids
 *  updates the assignments in the list with the cut_bill flag
 */
function _cut_bill_selected_assignments($assignment_ids) {
	try {
		
		$num_rows = 0;
		global $user;
		
		if ( strlen($assignment_ids) ) {
			
			
      $assign_id_list = json_decode('[' . $assignment_ids . ']', true);
      $cut_ids = $assign_id_list;
      
      
      
      $query = db_select('sch_elogs', 'e')
               ->condition('assignment_id', $assign_id_list, 'IN')
               ->fields('e', array('assignment_id'));
      $result = $query->execute();
      
      if ( $result->rowCount() ) {
        $elog_assign_ids = array();
        
        foreach($result as $row) {
          $elog_assign_ids[] = (int)$row->assignment_id;
        }
        
        $cut_ids = array_diff($assign_id_list, $elog_assign_ids);
      }
			
		
			$num_rows = db_update('sch_assignments')
									->fields(array(
											'cut_bill' => 1,
											'updated_date' => REQUEST_TIME,
											'updated_by_user' => $user->uid,
										))
									->condition('assignment_id', $cut_ids, 'IN')
                  ->execute();
      
		}
		return $num_rows;			
	}
	catch(Exception $e) {
		watchdog(SCH_SCHEDULER, '_cut_bill_selected_assignments() ' . $e->getMessage(), array(), WATCHDOG_ERROR);
	}
}



/*
 *	v($assignment_id, $schedule_id, $session_id, $session_date) 
 *
 */
function _update_assignment_location($assignment_id = 0, $new_schedule_id = 0, $new_sess_id = 0, $new_date = 0,
                                     $portion = 'F', $begin_ts = 0, $end_ts = 0) {
	try {
		
		if ( !$assignment_id || !$new_schedule_id || !$new_sess_id || !$new_date ) { return False; }
		
		// update the session assignment with the new info
		global $user;
		$assign = new stdClass();
		$new_sess = (object) Null;
		
		/*
		$query = db_select('sch_assignments', 'a');
		$query->condition('assignment_id', $assignment_id);
		$query->fields('a', array('schedule_id', 'schedule_session_id', 
                              'begin_time_actual', 'end_time_actual'));
		$result = $query->execute();
		if ( $result->rowCount() == 0 ) {
			// this is an error
			return False;
		}
		$assign = $result->fetchObject();
     * 
     */
		$timezone = _get_schedule_timezone($new_schedule_id); 
    
    if ( 'P' == $portion ) {

      $assign->begin_timestamp = $begin_ts;
      $assign->end_timestamp = $end_ts;
      $assign->assignment_date = $new_date;
      
      _calc_assignment_time_from_timestamp($assign);
    }
    else {  // FULL session - standard times
      
      $query = db_select('sch_schedule_sessions', 's');
      $query->condition('schedule_id', $new_schedule_id);
      $query->condition('schedule_session_id', $new_sess_id);
      $query->fields('s', array('begin_time', 'end_time'));
      $result2=$query->execute();
      if ( $result2->rowCount() == 0 ) {
        // this is an error
        return False;
      }
      $new_sess = $result2->fetchObject();
    
    
      $assign->schedule_id = $new_schedule_id;
      $assign->schedule_session_id = $new_sess_id;
      $assign->assignment_date = _format_timestamp($new_date, $new_sess->begin_time, $timezone);
      $assign->begin_time_actual = $new_sess->begin_time;
      $assign->end_time_actual = $new_sess->end_time;
      
      // recalculate the the timestamps & total time
      _calc_assignment_time($assign);
    }
		
		
		
		$num_rows = db_update('sch_assignments')
					->fields(array(
										'schedule_id' => $new_schedule_id,
										'schedule_session_id' => $new_sess_id,
										'begin_time_actual' => $assign->begin_time_actual,
										'end_time_actual' => $assign->end_time_actual,
										'begin_timestamp' => $assign->begin_timestamp,
										'end_timestamp' => $assign->end_timestamp,
										'total_time' => $assign->total_time,
										'updated_date' => REQUEST_TIME,
										'updated_by_user' => $user->uid,
									))
					->condition('assignment_id', $assignment_id, '=')
					->execute();
		
		return True;
	}
	catch (Exception $e) {
		watchdog(SCH_SCHEDULER, '_update_assignment_location() ' . $e->getMessage(), array(), WATCHDOG_ERROR);
	} 
}



/*
 *		_get_assignment()
 *
 *		retrieves a single assignment record by its id
 */

function _get_assignment($assignment_id = 0, $elog_id = 0) {
	try {
		
		$assignment = (object) Null;
    
    if ( !$assignment_id && !$elog_id ) {
      return $assignment;
    }
		
		
    $query = db_select('sch_assignments', 'a');
    $query->leftJoin('sch_schedules', 'sch', 'a.schedule_id = sch.schedule_id');
    $query->leftJoin('sch_simulators', 'sim', 'sch.simulator_id = sim.simulator_id');
    $query->leftJoin('sch_schedule_sessions', 's', 'a.schedule_session_id = s.schedule_session_id');
    $query->leftJoin('sch_customers', 'c', 'a.customer_id = c.customer_id');
    $query->leftJoin('sch_groups', 'g', 'a.group_id = g.group_id');
    $query->leftJoin('sch_session_names', 'sn', 's.session_name_id = sn.session_name_id');
    $query->leftJoin('sch_session_types', 't', 'a.session_type = t.session_type');

    if ( $assignment_id ) { 
      $query->condition('assignment_id', $assignment_id);
    }
    else if ( $elog_id ) {
      $query->leftJoin('sch_elogs', 'el', 'a.assignment_id = el.assignment_id');
      $query->condition('el.elog_id', $elog_id);
    }
    $query->fields('a', array('schedule_id', 'schedule_session_id', 
                              'begin_time_actual', 'end_time_actual', 
                              'customer_id', 'group_id',  
                              'session_type', 'cut_bill', 'discrepancy_reported', 
                              'begin_timestamp', 'end_timestamp', 'total_time', 
                              'note_text', 
                              'created_date', 'created_by_user', 
                              'updated_date', 'updated_by_user',
                            ))
          ->fields('c', array('customer', 'customer_code'))
          ->fields('g', array('group_name', 'group_code'))
          ->fields('sn', array('session_name_id', 'session_name'))
          ->fields('t', array('session_type_desc'))
          ->fields('sch', array('timezone'))
          ->fields('sim', array('simulator_id', 'sim_name', 'faa_id', 'device_id_internal'));
    $result = $query->execute();

    if ( $result->rowCount() ) {
      $assignment = $result->fetchObject();
      $assignment->assignment_date = _format_timestamp($assignment->begin_timestamp, 
                                                       '0000', 
                                                       $assignment->timezone);
    }
													
		return $assignment;
	}
	catch (Exception $e) {
		watchdog(SCH_SCHEDULER, '_get_assignment() ' . $e->getMessage(), array(), WATCHDOG_ERROR);
	} 
	
}

/*
 *		_get_assignments()
 *
 *		retrieves the assignment records within the date range
 *    dates are expected in unix timestamp format
 */

function _get_assignments($begin_date, $end_date, $schedule_id = 0, $simulator_id = 0) {
	try {
		
		$assignment = array();
		
		if ( !$begin_date || !$end_date ) { return $assignment; }
		
		$query = db_select('sch_assignments', 'a');
    if ($simulator_id) {
      $query->leftJoin('sch_schedules', 'sch', 'a.schedule_id = sch.schedule_id AND sch.simulator_id = :sid', 
                        array(':sid' => $simulator_id));
    } else {
      $query->leftJoin('sch_schedules', 'sch', 'a.schedule_id = sch.schedule_id');
    }
		$query->leftJoin('sch_schedule_sessions', 's', 'a.schedule_session_id = s.schedule_session_id');
		$query->leftJoin('sch_customers', 'cu', 'a.customer_id = cu.customer_id');										
		$query->leftJoin('sch_groups', 'g', 'a.group_id = g.group_id');
		$query->leftJoin('sch_session_names', 'sn', 's.session_name_id = sn.session_name_id');
		$query->leftJoin('sch_session_types', 't', 'a.session_type = t.session_type');
    $query->leftJoin('sch_elogs', 'el', 'el.assignment_id = a.assignment_id');
    
    if ($schedule_id) {
      $query->condition('a.schedule_id', $schedule_id);
    }
    
		$query->condition('a.cut_bill', 0);
    
//		$query->condition('a.begin_timestamp', $begin_date_range, '>=');
//		$query->condition('a.begin_timestamp', $end_date_range, '<=');
    
    $query->where("(
                    ( DATE(FROM_UNIXTIME($begin_date)) <= DATE(FROM_UNIXTIME(a.begin_timestamp)) ) AND 
                    ( DATE(FROM_UNIXTIME(a.begin_timestamp)) < DATE(FROM_UNIXTIME($end_date)) )
                   ) OR (
                    ( DATE(FROM_UNIXTIME($begin_date)) < DATE(FROM_UNIXTIME(a.end_timestamp)) ) AND 
                    ( DATE(FROM_UNIXTIME(a.end_timestamp)) <= DATE(FROM_UNIXTIME($end_date)) )
                   )");
    
//    $query->where("(DATE(FROM_UNIXTIME($begin_date)) <= DATE(FROM_UNIXTIME(a.begin_timestamp)) AND 
//                    DATE(FROM_UNIXTIME(a.begin_timestamp)) <= DATE(FROM_UNIXTIME($end_date))) OR 
//                   (DATE(FROM_UNIXTIME($begin_date)) <= DATE(FROM_UNIXTIME(a.end_timestamp) AND 
//                    DATE(FROM_UNIXTIME(a.end_timestamp)) <= DATE(FROM_UNIXTIME($end_date)))");
    
    
		$query->fields('a', array('assignment_id', 'schedule_id', 
                               'schedule_session_id',
															 'customer_id', 'group_id', 
                               'note_text', 'session_type',
															 'begin_timestamp', 'end_timestamp', 'total_time', 
															 'begin_time_actual', 'end_time_actual'))
          ->fields('s', array('begin_time', 'end_time'))
          ->fields('cu', array('customer', 'customer_code'))  
          ->fields('sch', array('simulator_id', 'timezone'))
					->fields('g', array('group_name', 'group_code'))
          ->fields('sn', array('session_name'))
					->fields('t', array('session_type_desc'))
          ->fields('el', array('elog_id'));
					
    
    if ($schedule_id) {
      $query->orderBy('s.schedule_session_id', 'ASC');
    } 
    $query->orderBy('begin_timestamp', 'ASC');
		
		$results_assign = $query->execute();
		
		if ( $results_assign->rowCount() ) {
        $dt = new DateTime();
        //$dt->setTimezone(new DateTimeZone('GMT'));
        
				foreach ($results_assign as $a) {
          // Use DateTime object due to DST problems with format_date
          $dt->setTimestamp($a->begin_timestamp);
					$day = $dt->format('j');
          
          $assignment[$a->schedule_session_id][$day][$a->assignment_id] = $a;
				}
		}
													
		return $assignment;
	}
	catch (Exception $e) {
		watchdog(SCH_SCHEDULER, '_get_assignments() ' . $e->getMessage(), array(), WATCHDOG_ERROR);
	} 
	
}

/*
 *		_get_customer_assignments()
 *
 *		retrieves the assignment records for:
 *			specific customer
 *			specific simulator or ALL(0)
 *      within the date range
 *    			dates are expected in unix timestamp format
 * 	 returns:  array of assignment objects
 */

function _get_customer_assignments($customer_id, $simulator_id, $begin_date_range, $end_date_range, $cut_bill = 0) {
	try {
		
		$assignment = array();
		
		if ( !$customer_id || !$begin_date_range || !$end_date_range ) { return $assignment; }
		
		$query = db_select('sch_assignments', 'a');			
		$query->innerJoin('sch_schedules', 'sch', 'a.schedule_id = sch.schedule_id');
		
		if ( $simulator_id ) {
			$query->condition('sch.simulator_id', $simulator_id);
		}
		$query->innerJoin('sch_simulators', 'sim', 'sch.simulator_id = sim.simulator_id');		
		//$query->innerJoin('sch_schedule_sessions', 's', 'a.schedule_session_id = s.schedule_session_id');
		$query->innerJoin('sch_customers', 'cu', 'a.customer_id = cu.customer_id');		
		$query->condition('a.customer_id', $customer_id);
										
		$query->leftJoin('sch_groups', 'g', 'a.group_id = g.group_id');
		//$query->innerJoin('sch_session_names', 'sn', 's.session_name_id = sn.session_name_id');
		$query->innerJoin('sch_session_types', 't', 'a.session_type = t.session_type');
    
    $query->where('( :bd <= begin_timestamp AND begin_timestamp <= :ed ) OR 
                   ( :bd <= end_timestamp AND end_timestamp <= :ed )', 
                  array(':bd' => $begin_date_range, ':ed' => $end_date_range) );

		$query->condition('cut_bill', $cut_bill);   
		$query->fields('a', array('assignment_id', 'schedule_id', 'schedule_session_id',
															 'customer_id', 'group_id', 'note_text', 
															 'begin_time_actual', 'end_time_actual', 'cut_bill', 
															 'begin_timestamp', 'end_timestamp', 'total_time',
															 'updated_date', 'updated_by_user'))
					->fields('g', array('group_name', 'group_code'))
					->fields('t', array('session_type_desc'))
					->fields('sim', array('sim_name', 'device_id_internal'));
					
		$query->orderBy('a.begin_timestamp', 'ASC')
					->orderBy('a.begin_time_actual', 'ASC')
					->orderBy('sch.simulator_id', 'ASC');
		$results = $query->execute();
		
		if ( $results->rowCount() ) {
				$assignment = $results->fetchAll();
		}
													
		return $assignment;
	}
	catch (Exception $e) {
		watchdog(SCH_SCHEDULER, '_get_customer_assignments() ' . $e->getMessage(), array(), WATCHDOG_ERROR);
	} 
	
}



/*
 *		_get_session_map($assignment_id = 0, $schedule_id = 0)
 *
 *		Either $assignment_id or $schedule_id is passed in as parm
 *				map index is always (0-based)
 *		If $assignment_id is submitted, map is returned
 *						$sess_map[$session_id] = index 
 *		If $schedule_id is submitted, map is returned
 *						$sess_map[index] = $session_id 
 */

function _get_session_map($assignment_id = 0, $schedule_id = 0) {
	try {
		
		if ( !$assignment_id && !$schedule_id ) { return array(); }
		
		$sess_map = array();
		
		// get the sessions for this schedule in order so we can construct a mapping array
		$query = db_select('sch_schedule_sessions', 's');
		if ( $assignment_id ) {
			$query->innerJoin('sch_assignments', 'a', 'a.schedule_id = s.schedule_id');
			$query->condition('assignment_id', $assignment_id);
			$query->condition('cut_bill', 0);
		}
		else if ( $schedule_id ) {
			$query->condition('schedule_id', $schedule_id);
		}
		$query->fields('s', array('schedule_session_id', 'begin_time', 'end_time'));
		$query->orderBy('schedule_session_id', 'ASC');  
		$results = $query->execute();
		
		$i = 0;
		foreach($results as $row) {
			if ( $assignment_id ) {
				$sess_map[$row->schedule_session_id] = $i++;  // for this we disregard begin & end time
			}
			else {
				$sess_map[] = array( 
														 'schedule_session_id' => $row->schedule_session_id,
														 'begin_time' => $row->begin_time,
														 'end_time' => $row->end_time,
														);
			}
		}
		
		return $sess_map;
	}
	catch (Exception $e) {
		watchdog(SCH_SCHEDULER, '_get_session_map() ' . $e->getMessage(), array(), WATCHDOG_ERROR);
	} 
}

/*
 *			_calc_assignment_time()
 * 
 *			IN:	assignment object
 *			OUT:  adds fields to assignment object
 *						calculates begin_timestamp (based on assignment_date & begin_time_actual)
 *						calculates end_timestamp (based on assignment_date & end_time_actual)
 *						calculates total_time for the assignment
 */

function _calc_assignment_time(&$assign) {
	
  $tz = _get_schedule_timezone($assign->schedule_id);
  $bdt = new DateTime();
  $bdt->setTimezone(new DateTimeZone($tz));
  $bdt->setTimestamp($assign->assignment_date);
  $h = (int)_st_left($assign->begin_time_actual, 2);
  $m = (int)_st_right($assign->begin_time_actual, 2);
  $bdt->setTime($h, $m, 0);
  
  $assign->begin_timestamp = $bdt->getTimestamp();
  

  // see comment above...
  $edt = new DateTime();
  $edt->setTimezone(new DateTimeZone($tz));
  $edt->setTimestamp($assign->assignment_date);
  if ( (int)$assign->begin_time_actual > (int)$assign->end_time_actual ) {  // session wraps into next day
    $edt->modify('+1 day');
  }
  $h = (int)_st_left($assign->end_time_actual, 2);
  $m = (int)_st_right($assign->end_time_actual, 2);
  $edt->setTime($h, $m, 0);
  
  $assign->end_timestamp = $edt->getTimestamp();
  
	$assign->total_time = _DT_date_diff_seconds($bdt, $edt);
}


/*
 *  _calc_assignment_time_from_timestamp()
 *  for uniformity... formats the assignment times from the timestamps (reverse of _calc_assignment_time)
 * 
 *  IN:  assignment record
 *  OUT:  calculates the new fields (begin_time_actual, end_time_actual, assignment_date)
 *        from the begin_timestamp and end_timestamp fields passed in with the record
 *        
 */
function _calc_assignment_time_from_timestamp(&$assign) {
  
  if ( !$assign->begin_timestamp || !$assign->end_timestamp ) {
    return False;
  }
  // use DateTime lib instead for timezone
  $tz = _get_schedule_timezone($assign->schedule_id);
  $bdt = new DateTime('now', new DateTimeZone($tz));
  $bdt->setTimestamp($assign->begin_timestamp);
  
  $edt = new DateTime('now', new DateTimeZone($tz));
  $edt->setTimestamp($assign->end_timestamp);
    
  $assign->begin_time_actual = $bdt->format('Hi');
  $assign->end_time_actual = $edt->format('Hi');
  $assign->total_time = _DT_date_diff_seconds($bdt, $edt);
  return True;
}



/*
 *  _get_selected_session_range()
 * 
 * determines with the given custom time range, how many sessions will be booked
 * 
 *  IN:  $rtype              [ 'A', 'E' ] // assignment or exception
 *       $record            ( assignment or exception ) object
 *       $sched_sessions
 *  RET: $sel_session_list (array)
 */
function _get_selected_session_range($rtype, $record, $sched_sessions, $timezone) {
  
  $sel_session_list = array();
  $incr_session_date = False;
  $sess_idx = 0;
  $first = true;
  $sess_id_map = array();
  $session_date_ts = 0;
  $booking_begins_ts = 0;
  $booking_ends_ts = 0;
  $begin_time_actual = "";
  $end_time_actual = "";
  
  // these are for debugging
  $booking_begins_f = 0;
  $booking_ends_f = 0;
  $sess_begins_f = 0;
  $sess_ends_f = 0;
  $begin_thresh_ts_f = 0;
  $end_thresh_ts_f = 0;
  
  
  if ( $rtype == "A" ) {
    // These assignment time fields are in "Hi" format (hhmm 24-hr)

    // starts at the assignment date, but increments by a day at a time
    // as it is detected that the assignment extends into sessions in the next day
    $session_date_ts = $record->begin_timestamp; 
    $booking_begins_ts = $record->begin_timestamp; 
    $booking_ends_ts = $record->end_timestamp; 
    $begin_time_actual = $record->begin_time_actual;
    $end_time_actual = $record->end_time_actual;
    
    // these are for debugging
    $timezone = $sched_sessions[$record->schedule_session_id]['timezone'];
    $booking_begins_f = _st_format_schedule_date($record->begin_timestamp, 'short', $timezone);
    $booking_ends_f = _st_format_schedule_date($record->end_timestamp, 'short', $timezone);
  }
  else if ( $rtype == "E" ) {
    $booking_begins_ts = $record->begin_timestamp; 
    $booking_ends_ts = $record->end_timestamp; 
  }
  else {
    watchdog(SCH_SCHEDULER, '_get_selected_session_range(): Invalid rtype, "' . $rtype . '"', array(), WATCHDOG_ERROR);
    return array();
  }
 
  
  // since the sched_sessions array is keyed by session_id for access later in this function
	// we also need an index->session_id map for use earlier 
	$m = 0;  
  // reset the array pointer to the first element
  reset($sched_sessions);
  $session = current($sched_sessions);
	while($session) {
    // build session_id map
		$sess_id_map[$m] = $session['schedule_session_id'];
    
    // what is the first session in the booking?
    if ( (int)$session['begin_time'] > (int)$session['end_time'] ) {
      // session overlaps into next day
      if ( ((int)$session['begin_time'] < (int) $begin_time_actual) &&
           ( (int) $begin_time_actual < 2400) ) {
        // session falls before midnight
        $session_date_ts = $booking_begins_ts;
        $sess_idx = $m;
      } else if ( ( 0 < (int) $begin_time_actual ) &&
           ( (int) $begin_time_actual < (int)$session['end_time']) )  {
        // SPECIAL CASE HANDLING
        // booking that begins during the last session of the day 
        // (typically overlaps into next day)
        // but has custom times set so it actually begins after midnight (the next day)
        // the session date is really the day before, subtract 1 day
        $session_date_ts = _add_day_ts($booking_begins_ts, -1); 
        $session_date_ts =  _format_timestamp($session_date_ts, $session['begin_time'], $timezone);
        $record->session_date = $session_date_ts;
        $sess_idx = $m;
      } else if ( ((int)$session['begin_time'] < (int) $begin_time_actual) &&
           ( (int) $begin_time_actual < 2400) ) {
        $session_date_ts = $booking_begins_ts;
        $sess_idx = $m;
      }
    } else {
      // normal - session contained within one day
      if ( ( (int)$session['begin_time'] <= (int) $begin_time_actual ) &&
           ( (int) $begin_time_actual <= (int)$session['end_time']) )  {
        $session_date_ts = $booking_begins_ts;
        $sess_idx = $m;
      }
    }
    $m++;
    $session = next($sched_sessions);
	}
  
  // reset the sessions then advance to the first one for this bookin
  $session = reset($sched_sessions);
  $m = 0;
  while ($m < $sess_idx) { $m++; next($sched_sessions); }
  
  $session = current($sched_sessions);

  // step through each session to determine which are covered by the new begin/end times
  while( $session ) {
    
    // set ptrs to the prev session
    $prev_idx = (($sess_idx-1) < 0) ? (count($sched_sessions)-1) : $sess_idx-1;
    $prev_sess_id = $sess_id_map[$prev_idx];
    $prev_sess_ends_ts = 
      _format_timestamp($session_date_ts, $sched_sessions[$prev_sess_id]['end_time'], $timezone);
    $prev_sess_ends_hm = $sched_sessions[$prev_sess_id]['end_time'];
    
    // previous session is the day before the current session, increment date
    if ( !$first && ((int) $prev_sess_ends_hm > (int) $session['begin_time']) ) {
      $session_date_ts = _add_day_ts($session_date_ts); 
      $sess_date_f = _st_format_schedule_date($session_date_ts, 'short', $timezone);
      //$incr_session_date = True; 
    }
    
    // reset the session date to the booking begin date
    //$session_date_ts = $booking_begins_ts;
    $session_date_ts = _format_timestamp($session_date_ts, $session['begin_time'], $timezone);
    $sess_begins_ts = $session_date_ts;
    $sess_ends_ts = _format_timestamp($session_date_ts, $session['end_time'], $timezone);
   
    
    // these are for debugging
    $sess_begins_f = _st_format_schedule_date($sess_begins_ts, 'short', $timezone);
    $sess_ends_f = _st_format_schedule_date($sess_ends_ts, 'short', $timezone);

    // session straddles midnight
    if ( ($sess_begins_ts > $sess_ends_ts)) { 
      // just increment the end date for now since the session straddles midnight
      // need to increment session date after doing the date comparisons
      $sess_ends_ts = _add_day_ts($sess_ends_ts); 
      $sess_ends_f = _st_format_schedule_date($sess_ends_ts, 'short', $timezone);
      $incr_session_date = True; 
    }

    // set ptrs to the next session
    // look ahead to the next session
    $next_idx = (($sess_idx+1) > (count($sched_sessions)-1)) ? 0 : $sess_idx+1;
    $next_sess_id = $sess_id_map[$next_idx];
    $next_sess_begins_ts = 
      _format_timestamp($session_date_ts, $sched_sessions[$next_sess_id]['begin_time'], $timezone);
    $next_sess_begins_hm = $sched_sessions[$next_sess_id]['begin_time'];
    

    //---------- gap + threshold handling -------------------
    $prev_gap = $sess_begins_ts - $prev_sess_ends_ts;
    if ( $prev_gap < 60 ) {$prev_gap = 0; }
    $begin_threshold_ts = $sess_begins_ts - $prev_gap - SCH_THRESHOLD;
    $begin_thresh_ts_f = _st_format_schedule_date($begin_threshold_ts, 'short', $timezone);
    
    $next_gap = $next_sess_begins_ts - $sess_ends_ts;
    if ( $next_gap < 60 ) {$next_gap = 0; }
    $end_threshold_ts = $sess_ends_ts + $next_gap + SCH_THRESHOLD;
    $end_thresh_ts_f = _st_format_schedule_date($end_threshold_ts, 'short', $timezone);
    
    $x = $sess_begins_f;
    $x = $sess_ends_f;
    $x = $booking_begins_f;
    $x = $booking_ends_f;
    $x = _st_format_schedule_date($sess_ends_ts - SCH_THRESHOLD, 'short', $timezone);
    
    //if ( $sess_idx == 4 ) {
    //  $debug = 1;
    //}
    //------------------------------------------------------------
    // BOOKING OVERLAPS SESSION  MIDDLE --> END
    //------------------------------------------------------------
    if ( ( $sess_begins_ts <= $booking_begins_ts ) && 
         ( $booking_begins_ts <=  ($sess_ends_ts - SCH_THRESHOLD) ) &&
         ( $sess_ends_ts <= $booking_ends_ts ) ) {

      //assignment overlaps the middle to end of this session - add assignment for this session
      // no gap time added

      $use_end_time_hm = '';
      $use_end_time_ts = 0;
      $portion = False;
      $break = False;
      
      if ( $sess_begins_ts < $booking_begins_ts ) {
        $portion = True;
      }

      if ( ($sess_ends_ts <= $booking_ends_ts) && ($booking_ends_ts < $end_threshold_ts) ) {
        // assignment end falls within the session trailing gap time & threshold
        // pad the extra time at the end of this session ( do not allow for another session to be created)
        $use_end_time_hm = $end_time_actual;
        $use_end_time_ts = $booking_ends_ts;
        $portion = True;
        $break = True;
      }
      else { 
        $use_end_time_hm = $session['end_time'];
        $use_end_time_ts = $sess_ends_ts;
      }
      
      if ($booking_ends_ts < $sess_ends_ts) { $portion = True; }

      // assignment is the same or overlaps the mid to end of this session time
      $sel_session_list[] = array(
          'session_id' => $session['schedule_session_id'],
          'session_date' => $session_date_ts,
          'begin_timestamp' => $booking_begins_ts,
          'begin_time' => $begin_time_actual,
          'end_timestamp' => $use_end_time_ts,
          'end_time' => $use_end_time_hm,
          'portion' => $portion,
        );
      if ( $break ) { break; }
    }
    //------------------------------------------------------------
    // BOOKING OVERLAPS SESSION  BEGINNING --> MIDDLE
    //------------------------------------------------------------
    else if ( ( $booking_begins_ts <= $sess_begins_ts ) && 
              ( ($sess_begins_ts + SCH_THRESHOLD) <= $booking_ends_ts ) && 
              ( $booking_ends_ts <= $sess_ends_ts ) ) {
      //assignment overlaps the beginning to middle of this session - add assignment for this session
      // include leading gap time

      $use_begin_time_hm = '';
      $use_begin_time_ts = 0;
      $portion = False;

      if ( ($begin_threshold_ts <= $booking_begins_ts) && ($booking_begins_ts < $sess_begins_ts) ) {
        // assignment begins falls within the session leading gap time & threshold
        // pad the extra time at the beginning of this session 
        // ( do not allow for another session to be created)
        $use_begin_time_hm = $begin_time_actual;
        $use_begin_time_ts = $booking_begins_ts;
        $portion = True;
      }
      else if ( $booking_begins_ts < $begin_threshold_ts ) {
        // include preceding gap
        $use_begin_time_hm = $prev_sess_ends_hm;
        $use_begin_time_ts = $prev_sess_ends_ts;
      }
      else {
        $use_begin_time_hm = $session['begin_time'];
        $use_begin_time_ts = $sess_begins_ts;
      }

      $sel_session_list[] = array(
          'session_id' => $session['schedule_session_id'],
          'session_date' => $session_date_ts,
          // include the gap time from the previous session to allow for the bleedover
          'begin_timestamp' => $use_begin_time_ts,
          'begin_time' => $use_begin_time_hm,
          'end_timestamp' => $booking_ends_ts,
          'end_time' => $end_time_actual,
          'portion' => True,
        );
      break;  
    }
    //------------------------------------------------------------
    // BOOKING CONTAINS SESSION (WHOLE)
    //------------------------------------------------------------
    else if ( ( $booking_begins_ts < $sess_begins_ts  ) && 
              ( $sess_ends_ts < $booking_ends_ts ) ) {
      //assignment completely overlaps this session within threshold limits - add assignment for this session

      $use_begin_time_hm = '';
      $use_begin_time_ts = 0;
      $use_end_time_hm = '';
      $use_end_time_ts = 0;
      $break = False;

      if ( ($begin_threshold_ts <= $booking_begins_ts) && ($booking_begins_ts < $sess_begins_ts) ) {
        // assignment begins falls within the session leading gap time & threshold
        // pad the extra time at the beginning of this session 
        // ( do not allow for another session to be created)
        $use_begin_time_hm = $begin_time_actual;
        $use_begin_time_ts = $booking_begins_ts;
      }
      else if ( $booking_begins_ts < $begin_threshold_ts ) {
        // include preceding gap
        $use_begin_time_hm = $prev_sess_ends_hm;
        $use_begin_time_ts = $prev_sess_ends_ts;
      }
      else {
        $use_begin_time_hm = $session['begin_time'];
        $use_begin_time_ts = $sess_begins_ts;
      }

      if ( ($sess_ends_ts <= $booking_ends_ts) && ($booking_ends_ts < $end_threshold_ts) ) {
        // assignment end falls within the session trailing gap time & threshold
        // pad the extra time at the end of this session ( do not allow for another session to be created)
        $use_end_time_hm = $end_time_actual;
        $use_end_time_ts = $booking_ends_ts;
        $break = True;
      }
      else { 
        $use_end_time_hm = $session['end_time'];
        $use_end_time_ts = $sess_ends_ts;
      }

      $sel_session_list[] = array(
          'session_id' => $session['schedule_session_id'],
          'session_date' => $session_date_ts,
          // include the gap time from the previous session to allow for the bleedover
          'begin_timestamp' => $use_begin_time_ts,
          'begin_time' => $use_begin_time_hm,
          'end_timestamp' => $use_end_time_ts,
          'end_time' => $use_end_time_hm,
          'portion' => False,
        );		

      if ( $break ) { break; }				
    }
    
    //------------------------------------------------------------
    // BOOKING (WHOLE) CONTAINED BY SESSION
    //------------------------------------------------------------
    else if ( ($sess_begins_ts <= $booking_begins_ts ) && ( $booking_ends_ts <= $sess_ends_ts ) ) {
      $portion = False;
      //assignment is less than the session - add assignment for this session
      if (($sess_begins_ts != $booking_begins_ts) || ($booking_ends_ts != $sess_ends_ts)) {
        $portion = True;
      }
      //assignment is less than the session - add assignment for this session
      $sel_session_list[] = array(
          'session_id' => $session['schedule_session_id'],
          'session_date' => $session_date_ts,
          'begin_timestamp' => $booking_begins_ts,
          'begin_time' => $begin_time_actual,
          'end_timestamp' => $booking_ends_ts,
          'end_time' => $end_time_actual,
          'portion' => $portion,
        );
        break;
    }
    
    if ( $incr_session_date ) {
      //do not just add seconds as it doesn't work with DST
      //$session_date_ts += SCH_ONE_TS_DAY;
      $session_date_ts = _add_day_ts($session_date_ts);
      $incr_session_date = False;
    }

    $session = next($sched_sessions);
    $sess_idx++;

    if ( False === $session ) {
      // reset the sessions to the beginning of the array
      reset($sched_sessions);
      $session = current($sched_sessions);
      $sess_idx = 0;
    }
    
    
    $first = false;

  }
  return $sel_session_list;
}



