<?php
require_once(__DIR__."/../includes/sysinit.php");
require_once(SABLE_WORKING_PATH.'booking/booking_func.php');
class Booking
{
	// Properties of the class:
	var $hddnBookingId, $selClientId, $edtBookingDate, $txtBookingTime, $serviceList, $edtDayNumber, $selRepeatCycle, 
		$selMonthType, $selMonthWeekCycle, $lstDOW, $lstDOM, $cbRecurring, $saId, $cbActive, $bkts, $footerDesc, $selTeamId, 
		$eventDate, $cbScheduleActive, $params, $scheduleOnly, $hddnBsId, $hddnServiceId, $selPMId, $txtComment, $serviceItems,
		$edtCashAmount, $selBuildingId, $txtBookingNote;
	
	function __construct()
	{
		$this->saId = 'NULL';
		$this->bkts = new DateTime();
	}
	
	function __destruct(){}

	function addBooking()
	{
		$bookingDate = new DateTime($this->edtBookingDate);
		$bookingDate->setTime(0,0);
		$today = new DateTime();
		$today->setTime(0,0);
		
		if (empty($this->hddnBookingId))
		{
			if ($bookingDate < $today)
			{
				SableSystem::ajaxResponse(false, "", "Booking date cannot be in the past.", 5, "edtBookingDate", false, "edtBookingDate");
			}
			
			if (empty($this->serviceList))
			{
				SableSystem::ajaxResponse(false, "", "At least 1 service item should be added.", 5, "selServiceId", false, "selServiceId");
			}
			
			if ($this->cbRecurring)
			{
				$this->storeStandingAppointment(false);
			}
			else
			{
				if ($this->checkBookingExists())
					SableSystem::ajaxResponse(false, "", "This Booking has already been added.", 5, "edtBookingDate", false, "edtBookingDate");
				$this->loadBooking();
			}
		}
		else
		{
			if ($this->cbRecurring)
			{
				$this->storeStandingAppointment(true);
			}			
			else
			{
				if ($bookingDate < $today)
				{
					SableSystem::ajaxResponse(false, "", "Past bookings cannot be changed.", 5, "edtBookingDate", false, "edtBookingDate");
				}				
				$this->updateBooking();
			}
		}
	}
	
	public function checkHolidayConflicts($bookingDate, $silent = false)
	{
		global $sableDB;	
		/*
		If a booking lands on a public holiday, or a Sunday, then we must advise the schedule conflicts.
		We will return an error if there is a schedule conflict, and set a session flag to note they have been warned. If the flag is set and they save again, this means they want to override and we let them:
		*/
		$dow = $bookingDate->format('N');//N - The ISO-8601 numeric representation of a day (1 for Monday, 7 for Sunday)
		
		if ($dow == 7) 
		{
			$msg = "<span>Booking is on a Sunday. <br><b>Save again to accept.</b></span>";
			if (!($_SESSION['conflict_warning'] ?? 0))
			{
				$_SESSION['conflict_warning'] = 1;
				if ($silent)
				{
					return $msg;
				}
				else
					SableSystem::ajaxResponse(false, "", $msg, 5, "edtBookingDate", false, "edtBookingDate");
			}
			else
			{
				unset($_SESSION['conflict_warning']);
			}
		}
		
		
		$dom = $bookingDate->format('j'); //day of the month (from 1 to 31)
		$moy = $bookingDate->format('n'); //month of the year (from 1 to 12)
		
		/*
		$yr	 = $bookingDate->format('Y');//month of the year (from 1 to 12)
		
		$pubwkdy = strtotime($yr.'-'.$moy.'-'.$dom);
		$pubwkdy = date('N', $pubwkdy);
		*/
		
		if ($dow == 1) //booking date is on a Monday
		{
			//--> if a public holiday falls on a Sunday, then the following Monday becomes the public holiday:
			$bookingDate = $bookingDate->modify('-1 day'); //strtotime('-1 day',$bookingDate);
			//update the correct values
			$dom = $bookingDate->format('j'); //day of the month (from 1 to 31)
			$moy = $bookingDate->format('n'); //month of the year (from 1 to 12)	
		}
		
		$ph = $sableDB->getRow('select ph_id, ph_name from public_holidays where (ph_month = '.$moy.') and (ph_day = '.$dom.')');
		if ($ph['ph_id'] ?? 0)
		{
			$msg = "<span>Booking is on public holiday (".$ph['ph_name']."). <br><b>Save again to accept.</b></span>";
			if (!($_SESSION['conflict_warning'] ?? 0))
			{
				$_SESSION['conflict_warning'] = 1;			
				if ($silent)
					return $msg;
				else
					SableSystem::ajaxResponse(false, "", $msg, 5, "edtBookingDate", false, "edtBookingDate");
			}
			else
			{
				unset($_SESSION['conflict_warning']);
			}
		}
		else
		{
			if ($silent) return 0;
		}
	}
	
	private function checkBookingConflicts($edit = false)
	{
		global $sableDB;
		
		$this->checkHolidayConflicts(new DateTime($this->edtBookingDate), $edit);
		
		/*
		we must get the number of teams available for delivering services. For every team available, a booking for the same time
		slot is permitted, otherwise the user must choose a different time slot:
		
		Scheduling may also not overlap. If you try to set a booking for 8h30, but there is already a boooking from 8h00 to 9h00,
		then we must advise it conflicts (unless another team can be allocated that time slot).
		*/
		$teamSQL = 'select count(*) from team where team_active = 1';
		$teamCount = intval($sableDB->getValue($teamSQL));
		
		//calculate the estimated duration of the event:
		$dur = 0; //will render the duration in minutes
		foreach($this->serviceList as $services)
		{
			$dur += intval($sableDB->getValue('select service_duration from service where service_id = '.$services['tag']['serviceId']));
		}
		
		$bookStartTime 	= date('H:i', strtotime($this->txtBookingTime));
		$bookEndTime 	= date('H:i', strtotime('+'.$dur.' minutes', strtotime($this->txtBookingTime)));
		
		$bookSQL = 'select count(*) 
					from booking 
					where (booking_date = "'.$this->edtBookingDate.'") ';
		if ($edit)
		{
			$bookSQL .="and booking.booking_id <> ".$this->hddnBookingId;
		}
		
		$bookingCount = intval($sableDB->getValue($bookSQL)) * intval(getMaxDailyBookings());
		
		if ($bookingCount < $teamCount) 
			return true; 
		else
			SableSystem::ajaxResponse(false, "", "Maximum bookings for this day reached.", 5, "edtBookingDate", false, "edtBookingDate");
	}
	
	//private function checkScheduleConflicts($edit, $bsid, $teamid, $field)
	private function checkScheduleConflicts($param)
	{
		/**
				$param = [];
				$param['edit']		= $bsid;
				$param['bs_id']		= $bsid;
				$param['team_id']	= $this->selTeamId;
				$param['field_id']	= $field;
				$param['service_duration']	= $this->params['service_duration']; //must be in minutes
				$param['travel_time']		= $this->params['travel_time']; //must be in minutes
		**/
		global $sableDB;
		
		$this->checkHolidayConflicts(new DateTime($this->edtBookingDate), $param['edit']);
		
		/*
		we must get the number of teams available for delivering services. For every team available, a booking for the same time
		slot is permitted, otherwise the user must choose a different time slot:
		
		Scheduling may also not overlap. If you try to set a booking for 8h30, but there is already a boooking from 8h00 to 9h00,
		then we must advise it conflicts (unless another team can be allocated that time slot).
		*/
		$teamSQL = 'select count(*) from team where team_active = 1';
		$teamCount = intval($sableDB->getValue($teamSQL));
		
		//Check if we have overlapping times for the current schedule:
		$bookSQL = 'select count(*) 
					from booking_schedule 
					where (booking_time = "'.$this->edtBookingDate.' '.$this->txtBookingTime.'") and (team_id = '.$param['team_id'].')';
		
		if ($param['edit'])
		{
			$bookSQL .="and (booking_schedule.bs_id <> ".$param['bs_id'].") ";
		}
		
		$cnt = $sableDB->getValue($bookSQL);
		
		if ($cnt > 0)
		{
			//There is already a booking for this team for this time.
			SableSystem::ajaxResponse(false, "", "Time slot already filled.", 5, $param['field_id'], false, $param['field_id']);
		}
		
		$bookSQL = 'select * 
					from booking_schedule 
					where (DATE(booking_time) = "'.$this->edtBookingDate.'") ';
		
		if ($param['edit'])
		{
			$bookSQL .="and (booking_schedule.bs_id <> ".$param['bs_id'].") ";
		}
		$bookSQL .= "order by booking_time ";
				
		$bookings			= $sableDB->getRows($bookSQL);
		$bookingsCount		= $sableDB->recordCount;
		//Ensure we have not reached the maximum number of scheduled bookings, per team, for the booking date:
		$maxDailyBookings	= getMaxDailyBookings();
		$bookingCount = intval($maxDailyBookings) * intval($bookingsCount);
		
		if ($bookingCount < $teamCount) 
		{
			/** removed checks 19-Jul-2021
			//now ensure that any preceding bookings' durations allow for this time slot to be used.
			$idx = 0;
			$bookStartTime = null;
			//$bookStartTime 	= date('H:i', strtotime($this->txtBookingTime));
			//$bookEndTime 	= date('H:i', strtotime('+'.$dur.' minutes', strtotime($this->txtBookingTime)));			
			foreach($bookings as $booking)
			{
				if ($idx === 0) 
				{
					$bookStartTime = new DateTime($booking['booking_time']); //the very first time slot
					//
					//!!! We can also get the distance here to workout if there is enought time to reach the new 
					//appointment from the given schedule time. For example workout 5 minutes per km?
					//
				}
				if ($bsid != $booking['bs_id']) //ignore the schedule we're working on currently
				{
					
					//$qry = 'select service.service_duration 
					//from booking_schedule 
					//		inner join booking__service on booking__service.booking_id = booking_schedule.booking_id 
					//		inner join service on service.service_id = booking__service.service_id 
					//		where bs_id = '.$booking['bs_id'];
					//$duration = $sableDB->getValue($qry);
					//$totalduration += intval($duration); //in minutes.
					
					$totalduration = (float)$param['service_duration']+(float)$param['travel_time'];
					$idx++;
				}
			} //foreach
			
			
			
			if ($idx)
			{
				$bookEndTime = clone($bookStartTime);
				$tst = '+'.$totalduration.' minutes';
				$bookEndTime->modify('+'.round($totalduration).' minutes');
				$comptime = new DateTime($this->edtBookingDate.' '.$this->txtBookingTime);

				if ($comptime < $bookEndTime)
				{
					$timediff = clone $bookEndTime;
					$timediff = $bookStartTime->diff($bookEndTime);

					$hrs = intval($timediff->format('%h'));
					$mns = intval($timediff->format('%i'));
					$hrstxt = ($hrs > 1) ? 'hours' : 'hour';
					$mnstxt = ($mns > 1) ? 'minutes' : 'minute';

					$starttime = clone $bookEndTime;
					$starttime->modify('-'.(($hrs*60)+$mns).' minutes');

					SableSystem::ajaxResponse(false, "", "Time conflict; must start after ".$bookEndTime->format('H:i').".", 5, $param['field_id'], false, $param['field_id']);
				}
				else return true; 
			} else return true; //no other bookings for this date yet 
			
			**/
			return true;
		}
		else
			SableSystem::ajaxResponse(false, "", "Maximum bookings for this day reached.", 5, $param['field_id'], false, $param['field_id']);
	}

	private function loadBooking($checkConflicts = true, $silent = false)
	{
		global $sableDB;
		$returnURL = '/booking/list.php'; //default
		$bkdt = "'".$this->edtBookingDate."'";
		
		if ($checkConflicts) 
		{
			$this->checkBookingConflicts(false);
		}
		else
		{
			$bkdt = "NULL";
		}
		
		$bknt = empty($this->txtBookingNote) ? "NULL" : "'".addslashes($this->txtBookingNote)."'";
		
		$insertQuery = "INSERT INTO booking (
						client_id, booking_repeats, sa_id, booking_date, booking_time, booking_user, booking_ip, 
						booking_timestamp, booking_note
						) VALUES (
						'".$this->selClientId."', 
						".$this->cbRecurring.", 
						".$this->saId.",
						".$bkdt.",
						NULL,
						'".$_SESSION['user']['user_code']."',
						'".SableGeneralFunctions::getRealIpAddr()."',
						'".$this->bkts->format('Y-m-d H:i:s')."', 
						".$bknt.")";
		$res=$sableDB->updateQuery($insertQuery);
		
		//Check if the Booking details were successfully added:
		$bktyp = $this->cbRecurring ? "Standing Appointment" : "Booking";
		$bktxt = $this->cbRecurring ? "New Standing Appointment added: ".$this->footerDesc : "New Booking added: ".$this->edtBookingDate;
		
		if ($res)
		{
			$this->setBookingId();
			if ($this->storeBuildingServices())
			{
				SableDBFunctions::loadAuditDetail($_SESSION['user']['user_code'], $bktxt, $this->hddnBookingId);
				if ($silent)
					return true;
				else
				{
					if (($_SESSION['module']['parent'] ?? 0) == 'client')
					{
						//tells booking this request comes from the client module
						unset($_SESSION['module']['parent']);
						$returnURL = '/client/';
					}
					SableSystem::ajaxResponse(true, $returnURL, 'The '.$bktyp.' was successfully added.', 0, "", 0, "");
				}
			}
			else SableSystem::ajaxResponse(false, "", "Add of ".$bktyp." failed. Please try again or contact support.", 
										   5, "selServiceId", false, "selServiceId");
		}
		else
			SableSystem::ajaxResponse(false, "", "Add of a new ".$bktyp." failed. Please try again or contact support.", 
									  5, "edtBookingDate", false, "edtBookingDate");
	}
	
	private function updateBooking($checkConflicts = true)
	{
		global $sableDB;
		$returnURL = '/booking/list.php'; //default
		
		$bkdt = "'".$this->edtBookingDate."'";
		if ($checkConflicts) 
		{
			$this->checkBookingConflicts(true);
		}
		else
		{
			$bkdt = "NULL";
		}
		
		$code = SableSystem::sableDecode($this->hddnBookingId);
		$pdt = $sableDB->getValue('select booking_date from booking where booking_id = '.$code);
		if (!$pdt) $pdt = "";
		$prevbookdate = new DateTime($pdt);
		$currbookdate = new DateTime($this->edtBookingDate);
		
		$bknt = empty($this->txtBookingNote) ? "NULL" : "'".addslashes($this->txtBookingNote)."'";
		
		$updateQuery = "UPDATE booking set 
						client_id = '".$this->selClientId."', 
						booking_repeats = ".$this->cbRecurring.", 
						sa_id = ".$this->saId.", 
						booking_date = ".$bkdt.", 
						booking_time = NULL, 
						booking_user = '".$_SESSION['user']['user_code']."', 
						booking_ip = '".SableGeneralFunctions::getRealIpAddr()."', 
						last_update = '".date('Y-m-d H:i:s')."', 
						booking_note = ".$bknt." 
						where booking_id = '".$code."'";

		$res=$sableDB->updateQuery($updateQuery);
		
		//Check if the details were successfully updated:
		$bktyp = $this->cbRecurring ? "Standing Appointment" : "Booking";
		$bktxt = $this->cbRecurring ? "New Standing Appointment added: ".$this->footerDesc : "New Booking added: ".$this->edtBookingDate;
		
		if ($res)
		{			
			//Has our booking date changed?
			if ($prevbookdate !== $currbookdate)
			{
				//check if there is a scheduled booking for this booking, if so, we need to update that scheduled booking to the 
				//same date (if the booking.booking_date <> DATE(booking_schedule.booking_time)) and if bs_active = 1 and bs_completed = 0;
				$bsrow = $sableDB->getRow('select bs_id, booking_time as schedule_date 
										from booking_schedule 
										where (booking_id = '.$code.') and (bs_active = 1) and (bs_completed = 0)');
				if (!empty($bsrow))
				{
					$scheddate = new DateTime($bsrow['schedule_date']); //get the schedule date (and time)
					$currbookdate->setTime($scheddate->format('H'),$scheddate->format('i')); //set the times to be the same for comparison
					if ($currbookdate > $scheddate)
					{
						$upd = 'update booking_schedule set booking_time = "'.$currbookdate->format('Y-m-d H:i').
								'" where bs_id = '.$bsrow['bs_id'];
						$res = $sableDB->updateQuery($upd);
						if ($res) SableDBFunctions::loadAuditDetail($_SESSION['user']['user_code'], 'Scheduled booking updated according to modified booking', $bsrow['bs_id']);
					}
				}
			}
			
			if ($this->storeBuildingServices())
			{
				SableDBFunctions::loadAuditDetail($_SESSION['user']['user_code'], $bktxt, $code);
				
				if (($_SESSION['module']['parent'] ?? 0) == 'client')
				{
					//tells booking this request comes from the client module
					unset($_SESSION['module']['parent']);
					$returnURL = '/client/';
				}
				
				SableSystem::ajaxResponse(true, $returnURL, 'The '.$bktyp.' was successfully updated.', 0, "", 0, "");
			}
			else SableSystem::ajaxResponse(false, "", "Modification of the ".$bktyp." failed. Please try again or contact support.", 
										   5, "selServiceId", false, "selServiceId");
		}
		else 
			SableSystem::ajaxResponse(false, "", "Modification of the ".$bktyp." failed. Please try again or contact support.", 
									  5, "edtBookingDate", false, "edtBookingDate");
	}

	private function getBookingId()
	{
		global $sableDB;
		/**
		if ($this->cbRecurring)
			$sql = "select booking_id from booking where (client_id = ".$this->selClientId.") and (sa_id = '".$this->saId."')";
		else
			$sql = "select booking_id from booking where (client_id = ".$this->selClientId.") and (booking_date = '".$this->edtBookingDate."')";
		**/
		if (!$this->hddnBookingId)
		{
			$sql = "select booking_id 
					from booking 
					where booking_user = ".$_SESSION['user']['user_code']." and 
					booking_ip = '".SableGeneralFunctions::getRealIpAddr()."' and 
					booking_timestamp  = '".$this->bkts->format('Y-m-d H:i:s')."'";
			return $sableDB->getValue($sql);
		}
		else return $this->hddnBookingId;
	}

	private function checkBookingExists()
	{
		$cid = $this->getBookingId();
		if (!empty($cid)) return true; else return false;
	}

	private function setBookingId()
	{
		$this->hddnBookingId = $this->getBookingId();
	}

	function viewBooking()
	{
		$url = '/booking/view.php?'.SableSystem::sableDecode($this->hddnBookingId);
		SableSystem::ajaxPageRedirect($url);
	}

	function editBooking()
	{
		$url = '/booking/edit.php?'.SableSystem::sableDecode($this->hddnBookingId);
		SableSystem::ajaxPageRedirect($url);
	}

	function deleteBooking()
	{
		global $sableDB;
		$code = SableSystem::sableDecode($this->hddnBookingId);
		
		if (!intval($this->scheduleOnly))
		{
			$this->hddnBsId = intval($sableDB->getValue("select bs_id from booking_schedule where booking_id = ".$code));
		}
		
		if ($this->hddnBsId)
		{
			//only delete the scheduled booking.
			$dt		= $sableDB->getRow("select * from booking_schedule where bs_id = ".$this->hddnBsId);
			$cnt	= $sableDB->recordCount;
			if ($cnt <= 0)
			{
				SableSystem::ajaxResponse(false, "", "Delete failed - invalid Booking selected.", 5, "edtBookingDate", false, "edtBookingDate");
			}
			else
			{
				$res = $sableDB->updateQuery("update booking_schedule set bs_deleted = 1 where bs_id = ".$this->hddnBsId);
				if ($res)	
				{
					SableDBFunctions::loadAuditDetail($_SESSION["user"]["user_code"], 
													  'Booking Schedule for '.$dt['booking_time'].' deleted.', $this->hddnBsId);
					SableSystem::ajaxPageRedirect('/booking/','The schedule was successfully deleted.');				
				}
				/*
				else
				{
					SableSystem::ajaxResponse(false, "", "System error: The schedule failed to delete. ".
											  "Please try again later or contact support.", 5, "edtBookingDate", false, 
											  "edtBookingDate");
				}
				*/
			}
		}

		//delete the booking
		$cnt = $sableDB->getValue("select count(*) from booking where booking_id = ".$code);
		if ($cnt <= 0)
			SableSystem::ajaxResponse(false, "", "Delete failed - invalid Booking selected.", 5, "edtBookingDate", false, "edtBookingDate");
		else
		{
			$said = intval($sableDB->getValue('select sa_id from booking where booking_id = '.$code));
			
			if ($said)
			{
				$sql = "update standing_appointment set sa_deleted = 1 where (standing_appointment.sa_id = ".$said.")";
				$res = $sableDB->updateQuery($sql);
				if ($res) SableDBFunctions::loadAuditDetail($_SESSION["user"]["user_code"], 'Standing appointments deleted.', $code);
			}

			$sql = "update booking set booking_deleted = 1 where (booking.booking_id = ".$code.")";			
			$res = $sableDB->updateQuery($sql);
			if ($res)
			{
				SableDBFunctions::loadAuditDetail($_SESSION["user"]["user_code"], 'Booking deleted.', $code);
				SableSystem::ajaxPageRedirect('/booking/','The booking was successfully deleted.');
			}
			else
			{
				SableSystem::ajaxResponse(false, "", "System error: The Booking failed to delete. ".
										  "Please try again later or contact support.", 5, "edtBookingDate", 
										  false, "edtBookingDate");
			}			

			/**  WE NO LONGER PHYSICALLY DELETE RECORDS
			$sql = "delete from booking__service where (booking.booking_id = ".$code.") and (bs_completed = 0)";
			$res = $sableDB->updateQuery($sql);
			if ($res)
			{
				$txt = $res > 1 ? 'services' : 'service';
				SableDBFunctions::loadAuditDetail($_SESSION["user"]["user_code"], $res.' booking '.$txt.' deleted.', $code);
			}
			**/
		}
	}
	
	private function storeBuildingServices()
	{
		global $sableDB;
		$sableDB->updateQuery('delete from booking__service where booking_id = '.$this->hddnBookingId); //remove previous entries.
		$sql = 'insert into booking__service (booking_id, service_id, building_id, bs_price_override) values ';
		$count = 0;
		foreach($this->serviceList as $si) //Service Item
		{
			$d = $count ? ',' : '';
			$prc = $si['tag']['newPrice'] ?? 'NULL';
			$sql .= $d.'('.$this->hddnBookingId.', '.$si['tag']['serviceId'].', '.$si['tag']['buildingId'].'., '.$prc.')';
			$count++;
		}
		//SableDebug::debugx($sql, 1);
		return $sableDB->updateQuery($sql);
	}
	
	private function storeStandingAppointment($edit)
	{
		global $sableDB;
		//SableSystem::ajaxResponse(false, "", "Work in progress. Functionality not yet available.", 5, "cbRecurring", false, "cbRecurring");
		$occType	= $this->selRepeatCycle;
		$mnthType	= $this->selRepeatCycle == 3 ? $this->selMonthType		: 0;
		$dowOccur	= $this->selRepeatCycle == 3 ? $this->selMonthWeekCycle : 0;
		
		if ($edit)
		{
			$this->saId = $sableDB->getValue('select sa_id from booking where booking_id = '.$this->hddnBookingId);
			$upd = 'update standing_appointment set 
					sa_start_date = "'.$this->edtBookingDate.'", 
					sa_active = '.$this->cbActive.', 
					client_id = '.$this->selClientId.', 
					sa_occurrence = '.$this->edtDayNumber.', 
					sa_occ_type = '.$occType.',
					sa_month_type = '.$mnthType.', 
					sa_month_dow_occ = '.$dowOccur.', 
					sa_description = "'.$this->footerDesc.'", 
					last_update = "'.date('Y-m-d H:i:s').'" 
					where sa_id = '.$this->saId;
			$res = $sableDB->updateQuery($upd);
		}
		else
		{
			$ins = 'insert into standing_appointment 
			(client_id, sa_start_date, sa_active, sa_occurrence, sa_occ_type, sa_month_type, sa_month_dow_occ, sa_description, user_code, sa_ip, sa_date) 
			values 
			('.$this->selClientId.', "'.$this->edtBookingDate.'", '.$this->cbActive.', '.$this->edtDayNumber.', '.$occType.', '.$mnthType.', '.$dowOccur.', 
			"'.$this->footerDesc.'", '.$_SESSION['user']['user_code'].', "'.SableGeneralFunctions::getRealIpAddr().'", "'.date('Y-m-d').'")';
			$res = $sableDB->updateQuery($ins);

			$this->saId = $sableDB->getValue('select sa_id 
				from standing_appointment 
				where (client_id = '.$this->selClientId.') and (sa_start_date = "'.$this->edtBookingDate.'") 
				and (sa_occurrence = '.$this->edtDayNumber.') and (sa_occ_type = '.$occType.') and 
				(sa_month_type = '.$mnthType.') and (sa_month_dow_occ = '.$dowOccur.') and 
				(user_code = '.$_SESSION['user']['user_code'].') and (sa_ip = "'.SableGeneralFunctions::getRealIpAddr().'") 
				and (sa_date = "'.date('Y-m-d').'")');
		}
		
		if ($res)
		{
			$delSQL = 'delete from standing_appointment__dow where sa_id = '.$this->saId;
			$sableDB->updateQuery($delSQL); //clean slate.
			$delSQL = 'delete from standing_appointment__dom where sa_id = '.$this->saId;
			$sableDB->updateQuery($delSQL); //clean slate.
			//add the days of the week (DOW) or days of the month (DOM) depending on the month type cycle selected.
			switch($this->selRepeatCycle)
			{
				case 1: break;	//day
				case 2: {		//week
							foreach($this->lstDOW as $dow)
							{
								$r = $sableDB->updateQuery('insert into standing_appointment__dow (sa_id, dow_id) values ('.$this->saId.', '.(intval($dow['day'])+1).')');
							}
							break;
						}
				case 3: {		//month
							if ($mnthType == 2)
							{
								foreach($this->lstDOW as $dow)
								{
									$r = $sableDB->updateQuery('insert into standing_appointment__dow (sa_id, dow_id) values ('.$this->saId.', '.(intval($dow['day'])+1).')');
								}							}
							else
							{
								foreach($this->lstDOM as $dom)
								{
									$r = $sableDB->updateQuery('insert into standing_appointment__dom (sa_id, dom_id) values ('.$this->saId.', '.$dom['day'].')');
								}	
							}
							break;
						}
			}
			//now add/update the booking itself:
			if ($edit)
				$this->updateBooking(false);
			else
				$this->loadBooking(false); //do not check conflicts now.
		}
		else
		{
			SableSystem::ajaxResponse(false, "", "
			System error: Failed to add the Standing Appointment. Please try again later or contact support.", 
				5, "cbRecurring", false, "cbRecurring");
		}
	}
	
	private function getBookingScheduleId()
	{
		global $sableDB;
		$sql = 'select bs_id 
				from booking_schedule 
				where (booking_id = '.$this->hddnBookingId.') and (DATE(booking_time) = "'.$this->eventDate.'")';
		$bsid = $sableDB->getValue($sql);
		return $bsid;
		//booking_time = "'.$this->edtBookingDate.' '.$this->txtBookingTime.'"';
	}
	
	private function checkScheduleExists($bookingId, $teamId, $scheduleDate)
	{
		//booking_id, team_id, booking_time
		global $sableDB;
		$bsid = $sableDB->getValue('select bs_id from booking_schedule where booking_id = '.$bookingId.' and 
									team_id = '.$teamId,' and 
									DATE(booking_time) = "'.$scheduleDate.'"');
		return $bsid;
	}

	public function saveSchedule()
	{
		global $sableDB;
		$this->hddnBookingId= $this->params['booking_id'];
		$this->eventDate	= $this->params['schedule_date'];
		$booking			= $sableDB->getRow('select * from booking where booking_id = '.$this->hddnBookingId);
		
		$upd = 0;
		
		$this->selClientId = $booking['client_id'];
		
		$this->serviceList = [];
		$tmp = [];
		$total = 0;
		foreach($this->serviceItems as $service)
		{
			$total += floatval($service['price']);
			$tmp['tag']['buildingId']		= $service['building_id'];
			$tmp['tag']['serviceId']	= $service['service_id'];
			$tmp['tag']['newPrice']		= $service['price'];
			$this->serviceList[] = $tmp;
		}
		
		if ($total) $this->storeBuildingServices();
		
		$bsid = $this->getBookingScheduleId();
		
		$crdt	= new DateTime();
		$bkdt	= new DateTime($this->edtBookingDate.' '.$this->txtBookingTime); //the booking date (if the user decides to move this)
		$schedt = new Datetime($this->edtBookingDate);
		$evdt	= new DateTime($this->eventDate); //the current event date we are working on.
		$field	= 'edtBookingTime'.$this->hddnBookingId;
		/**
		$bkdt is the date of the schedule. We will manage the bookings as follows:
		if $bkdt and $evdt are the same, then we need a time and a team  to be assigned because this schedule. 
		If the 2 dates are not the same, then:
			1.	Ensure that $bkdt is later than the current date.
			2.	Ensure that we have a booking time scheduled
			3.	Ensure that we don't schedule a time that is already alotted for the same team ID (if we have a team id)
			
		if the 2 dates are not the same, then:
			1.	if this is a single booking, then update the booking to the same date as the schedule date. We may check for conflicts.
			2.	If this is a recurring booking, set the current schedule to "inactive" and create a new single booking for new date. If 
				this ever is modified, we need to remove the "inactive" boolean, and remove the booking. (or update the date.)
			
		**/
		
		if ($this->selTeamId)
		{
			if (empty($this->txtBookingTime)) 
				SableSystem::ajaxResponse(false, "", "A time is required.", 5, $field, false, $field);
		}

		if ($evdt != $schedt) //the user has changed the schedule date and it is now different to the booking date.
		{
			if ($crdt > $bkdt) 
				SableSystem::ajaxResponse(false, "", "Must be a future date.", 5, $field, false, $field);
			else
			{
				$param = [];
				$param['edit']		= $bsid;
				$param['bs_id']		= $bsid;
				$param['team_id']	= $this->selTeamId;
				$param['field_id']	= $field;
				$param['service_duration']	= $this->params['service_duration']; //must be in minutes
				$param['travel_time']		= $this->params['travel_time']; //must be in minutes
				//$this->checkScheduleConflicts($bsid, $bsid, $this->selTeamId, $field);
				$this->checkScheduleConflicts($param);
				
				//add/update existing booking here
				if ($booking['sa_id']) //recurring booking
				{
					//if a booking schedule doesn't exist, we need to create one and disable it so it doesn't show up in the planner
					$deactivate = true;
					if (!$bsid)
					{
						$bsid = $this->checkScheduleExists($this->hddnBookingId, $this->selTeamId, $evdt->format('Y-m-d'));
						if ($bsid)
						{
							SableSystem::ajaxResponse(false, "", "This ocurrence has already been moved.", 5, $field, false, $field);
						}
						$sql = 'insert into booking_schedule 
								(booking_id, team_id, booking_time, bs_active, bs_user, bs_ip) 
								values 
								('.$this->hddnBookingId.', '.$this->selTeamId.', "'.$evdt->format('Y-m-d').' 00:00", 
								"0", '.$_SESSION['user']['user_code'].', "'.SableGeneralFunctions::getRealIpAddr().'")';
						$upd = $sableDB->updateQuery($sql);
						$deactivate = false; //already created disabled, no need to disable
					}
					
					if ($upd || $bsid)
					{
						//$bsid = $this->getBookingScheduleId();
						if ($deactivate)
							$upd = $sableDB->updateQuery('update booking_schedule set bs_active = "0" where bs_id = '.$bsid);
						else
							$upd = true; //already deactivated.
						if ($upd)
						{
							//here we create a new single booking to replace the schedule we are attempting to change:
							$this->hddnBookingId = null; //ensure we create a new one
							$this->selClientId = $booking['client_id'];
							$this->cbRecurring = 0; //must remain a single booking that can be deleted if necessary.
							$this->sa_id = 'NULL'; //not recurring
							$this->edtBookingDate = $bkdt->format('Y-m-d'); //must be the event date
							$this->bkts = new DateTime(); //reset this value
							$this->loadBooking(true, true);
							$bsid = null; //reset this so we generate a new schedule for the new booking.
						}
						else
						{
							SableSystem::ajaxResponse(false, "", "Failed to create a single booking for this occurrence.", 5, 
													  $field, false, $field);
						}
					} else	SableSystem::ajaxResponse(false, "", "Failed to disable this occurrence.", 5, $field, false, $field);
				}
				else //single booking
				{
					$sql = 'update booking set 
							booking_date = "'.$this->edtBookingDate.'",  
							last_update = "'.$crdt->format('Y-m-d H:i:s').'" 
							where booking_id = '.$this->hddnBookingId;
					$upd = $sableDB->updateQuery($sql);
					if (!$upd)
						SableSystem::ajaxResponse(false, "", "Failed to change the date.", 5, $field, false, $field);
				}
			}
		}
		//$this->edtBookingDate = $bkdt->format('Y-m-d'); //restore the correct date after use.
	
		if ($bsid) //edit
		{
			$sql = 'update booking_schedule set 
					team_id = '.$this->selTeamId.', 
					booking_time = "'.$bkdt->format('Y-m-d H:i:s').'", 
					bs_active = "'.intval($this->cbScheduleActive).'", 
					last_update = "'.$crdt->format('Y-m-d H:i:s').'" 
					where bs_id = '.$bsid;
		}
		else //insert
		{
			$sql = 'insert into booking_schedule 
					(booking_id, team_id, booking_time, bs_active, bs_user, bs_ip) 
					values 
					('.$this->hddnBookingId.', '.$this->selTeamId.', "'.$bkdt->format('Y-m-d H:i:s').'", 
					"'.intval($this->cbScheduleActive).'", '.$_SESSION['user']['user_code'].', "'.SableGeneralFunctions::getRealIpAddr().'")';
		}

		$res = $sableDB->updateQuery($sql);
		if ($res) 
		{
			$evdt->setTime(0,0);
			$bkdt->setTime(0,0);
			//If different date, refresh the page to remove the entry:
			$field = 'edtBookingTime'.$this->hddnBookingId;
			SableSystem::ajaxResponse(($evdt != $bkdt), "/booking/+".$evdt->format('d')."+".$evdt->format('m')."+".$evdt->format('Y'), "Successfully saved.", 7, $field, false, $field);
		}
	}
	
	public function savePlanner()
	{
		/**
		{
			Array
			(
				[0] => Array
					(
						[team_id] => 4
						[hour] => 07
						[minute] => 30
						[client_id] => 72
						[booking_id] => 28
					)

				[1] => Array
					(
						[team_id] => 1
						[hour] => 08
						[minute] => 00
						[client_id] => 125
						[booking_id] => 91
					)

				[2] => Array
					(
						[team_id] => 4
						[hour] => 08
						[minute] => 00
						[client_id] => 67
						[booking_id] => 25
					)

				[3] => Array
					(
						[team_id] => 2
						[hour] => 09
						[minute] => 15
						[client_id] => 69
						[booking_id] => 27
					)

				[4] => Array
					(
						[team_id] => 1
						[hour] => 10
						[minute] => 30
						[client_id] => 61
						[booking_id] => 23
					)

			)
		}
		**/
		global $sableDB;
		$plantime = new DateTime($this->eventDate);
		
		$count = 0;
		$saved = 0;
		foreach($this->params as $plan)
		{
//			$booking	= $sableDB->getRow('select * from booking where booking_id = '.$plan['booking_id']);
			$qry=	'select bs_id 
					from booking_schedule 
					where (booking_id = '.$plan['booking_id'].') and 
					(DATE(booking_time) = "'.$plantime->format('Y-m-d').'")';
			
			$bsid	= $sableDB->getValue($qry);
			$plantime->setTime($plan['hour'], $plan['minute']);
			if ($bsid) //edit
			{
				$sql = 'update booking_schedule set 
						team_id = '.$plan['team_id'].', 
						booking_time = "'.$plantime->format('Y-m-d H:i:s').'", 
						last_update = NOW(),
						bs_active = 1 
						where bs_id = '.$bsid;

			}
			else //insert
			{
				$sql = 'insert into booking_schedule 
						(booking_id, team_id, booking_time, bs_active, bs_user, bs_ip) 
						values 
						('.$plan['booking_id'].', '.$plan['team_id'].', "'.$plantime->format('Y-m-d H:i:s').'", 
						1, '.$_SESSION['user']['user_code'].', "'.SableGeneralFunctions::getRealIpAddr().'")';
			}
			
			$res = 0;
			$res = $sableDB->updateQuery($sql);
			
			if ($res) 
			{
				$saved++;
			}
			$count++;

		}
		
		$url = SableSystem::getParameterLink("booking", "index.php", $plantime->format('d+m+Y'));
		if ($count === $saved)
		{
			SableSystem::ajaxPageRedirect('/booking/+'.$plantime->format('d+m+Y'),'The plan was successfully updated.');
		}
		else
		{
			SableSystem::ajaxPageRedirect('/booking/+'.$plantime->format('d+m+Y'),'Not all items were successfully saved.');
		}
	}
	
	public function filterScheduleByTeam()
	{
		$evdt = new DateTime($this->edtBookingDate);
		$html = getDayBookings($evdt, null, $this->selTeamId);
		SableSystem::ajaxFillField($html, "divBookingSchedule");
	}
	
	public function cancelScheduledItem()
	{
		global $sableDB;
		$sql = 'select booking_id from booking_schedule where bs_id = '.$this->hddnBsId;
		$this->hddnBookingId = $sableDB->getValue($sql);		
		$sql = 'update booking__service set service_active = 0 
				where booking_id = '.$this->hddnBookingId.' and 
				service_id = '.$this->hddnServiceId.' and 
				building_id = '.$this->selBuildingId;
		$res = $sableDB->updateQuery($sql);
		if (!$res) 
			SableSystem::ajaxDisplayMessage('This booking item could not be cancelled.');
		else
		{
			$url = '/themes/sable/mobi/index.php+'.$this->hddnBsId;
			SableSystem::ajaxPageRedirect($url, 'Service item successfully cancelled.');
		}
		
	}
	
	public function updateServices()
	{
		global $sableDB;
		$sql = 'select booking_id from booking_schedule where bs_id = '.$this->hddnBsId;
		//SableDebug::debugx($sql, 1);
		$this->hddnBookingId = $sableDB->getValue($sql);
		if ($this->storeBuildingServices())
		{
			SableDBFunctions::loadAuditDetail($_SESSION['user']['user_code'], 'Services updated on site.', $this->hddnBookingId);
			$url = '/themes/sable/mobi/index.php+'.$this->hddnBsId;
			SableSystem::ajaxPageRedirect($url, 'Service items successfully added.');
		}
		else  SableSystem::ajaxDisplayMessage('Failed to add the service items.');
	}
	
	private function notifyNextClient()
	{
		$row = getDriverScheduleData(true);
		if (!empty($row['client_cell'])) //if empty, then the list has come to an end. The day is done. Time to rest :)
		{
			$time	= new DateTime($row['booking_time']);
			$msg	= SABLE_SENDER_NAME.' are on their way for your '.$time->format('H:i').' appointment. See you soon!';
			SableSystem::sendSMS($msg, $row['client_cell'], $row['client_id']);
		}
	}
	
	public function addServiceTransaction()
	{
		global $sableDB;
		
		$cash	= ($this->edtCashAmount == -989898) ? false : true;
		
		$sql = 'select SUM(coalesce(bs_price_override, service_price))
				from booking_schedule 
				inner join booking on booking.booking_id = booking_schedule.booking_id 
				inner join booking__service on booking__service.booking_id = booking_schedule.booking_id 
				inner join service on service.service_id = booking__service.service_id 
				where (booking_schedule.bs_id = '.$this->hddnBsId.') and (booking__service.service_active = 1)';
		$total	= floatval($sableDB->getValue($sql)); //e.g. R220
		$rcvd	= $cash ? floatval($this->edtCashAmount) : $total; //e.g. R200
		
		if ($rcvd < $total)
		{
			//SableSystem::ajaxResponse(false, "", "Not enough cash received.", 5,'edtCashAmount', false, 'edtCashAmount');		
		}
		
		$res = $sableDB->updateQuery('update booking_schedule set bs_completed = 1 where bs_id = '.$this->hddnBsId);
		
		$sql = 'select booking_id from booking_schedule where bs_id = '.$this->hddnBsId;
		$this->hddnBookingId = $sableDB->getValue($sql);		
		
		if ($res)
		{
			$sql = 'select client.client_id, client_email, client_cell  
					from booking_schedule 
					inner join booking on booking.booking_id = booking_schedule.booking_id 
					inner join client on client.client_id = booking.client_id 
					where booking_schedule.bs_id = '.$this->hddnBsId;
			$clientRow		= $sableDB->getRow($sql);
			$clientId		= $clientRow['client_id'];
			$clientCell		= $clientRow['client_cell'];
			$clientEmail	= $clientRow['client_email'];
			
			//add a transaction for the record:
			/**
			txn_type_id
			txn_date
			txn_amount
			client_id
			bs_id
			txn_notes
			txn_paid
			txn_ip
			txn_user
			txn_timestamp
			last_update
			**/
			$now = new DateTime();
			//add the invoice transaction:
			$ins = 'insert into finance (txn_type_id, pm_id, txn_amount, client_id, bs_id, txn_ip, txn_user, txn_timestamp) values 
			(1, '.$this->selPMId.', '.$total.', '.$clientId.', '.$this->hddnBsId.', "'.SableGeneralFunctions::getRealIpAddr().'", '.$_SESSION['user']['user_code'].', "'.$now->format('Y-m-d H:i:s').'")';
			$res = $sableDB->updateQuery($ins);
			
			$smsbody = "Thank you for choosing Champooches. R".$total." is due for your account. Please send proof of payment to 0738062037. DO NOT REPLY TO THIS SMS.";

			if ($res)
			{
				if ($cash)
				{
					//cash received, add the payment transaction now:
					$ins = 'insert into finance (txn_type_id, pm_id, txn_amount, client_id, bs_id, txn_ip, txn_user, txn_timestamp) values 
					(3, '.$this->selPMId.', -'.$rcvd.', '.$clientId.', '.$this->hddnBsId.', "'.SableGeneralFunctions::getRealIpAddr().'", '.$_SESSION['user']['user_code'].', "'.$now->format('Y-m-d H:i:s').'")';
					$res = $sableDB->updateQuery($ins);
					
					$qrys = 'select finance_id 
							from finance 
							where (txn_type_id = 2) and 
							(txn_amount = '.$rcvd.') and 
							(client_id = '.$clientId.') and  
							(bs_id = '.$this->hddnBsId.') and 
							(txn_timestamp = "'.$now->format('Y-m-d H:i:s').'")';
					$payid = $sableDB->getValue($qrys);
					SableDBFunctions::loadAuditDetail($_SESSION['user']['user_code'], 
												  'Service transaction added (R'.number_format($rcvd, 2).')', $payid);
					
					if ($rcvd < $total)
					{
						$balance = $total - $rcvd;
						$smsbody = "Thank you for choosing Champooches. Your cash payment of R".$rcvd." has been received. R".$balance.' is still due. Please send proof of payment to 0738062037. DO NOT REPLY TO THIS SMS.';
					}
					else
						$smsbody = "Thank you for choosing Champooches. Your cash payment of R".$rcvd." has been received.";
				}
				
				if ($res)
				{
					$url = '/themes/sable/mobi/index.php+'.$this->hddnBsId;
					$qrys = 'select finance_id 
							from finance 
							where (txn_type_id = 1) and 
							(txn_amount = '.$total.') and 
							(client_id = '.$clientId.') and  
							(bs_id = '.$this->hddnBsId.') and 
							(txn_timestamp = "'.$now->format('Y-m-d H:i:s').'")';
					$invid = $sableDB->getValue($qrys);
					SableDBFunctions::loadAuditDetail($_SESSION['user']['user_code'], 'Service finalised.', $this->hddnBookingId);
					SableDBFunctions::loadAuditDetail($_SESSION['user']['user_code'], 
													  'Service transaction added (R'.number_format($total, 2).')', $invid);
					
					//Notifications here:
					SableSystem::sendSMS($smsbody, $clientCell, $clientId);					
					$this->notifyNextClient();
					SableSystem::ajaxPageRedirect($url, 'Service was successfully finalised.');
				} 
				else SableSystem::ajaxDisplayMessage('Failed to add a payment transaction.');
				

				
			}
			else  SableSystem::ajaxDisplayMessage('Failed to finalise the service.');
		}
	}
	
	public function addServiceComment()
	{
		global $sableDB;
		$ts = new DateTime();
		$ins = 'insert into booking_schedule__comment (bs_id, bs_comment, user_code, bs_ip, bs_timestamp) values 
		('.$this->hddnBsId.', "'.addslashes($this->txtComment).'", '.$_SESSION['user']['user_code'].', "'.SableGeneralFunctions::getRealIpAddr().'", "'.$ts->format('Y-m-d H:i:s').'")';
		$res = $sableDB->updateQuery($ins);
		if ($res)
		{
			$url = '/themes/sable/mobi/index.php+'.$this->hddnBsId;
			SableDBFunctions::loadAuditDetail($_SESSION['user']['user_code'], 'Service comment added.', $this->hddnBsId);
			SableSystem::ajaxPageRedirect($url, 'Comment was successfully added.');
		}
		else  SableSystem::ajaxDisplayMessage('Failed to add the comment.');
	}
	
	public function showNextOccurrence()
	{
		global $sableDB;
		$today = new DateTime();
		$today->setTime(0,0);
		
		$sql = 'select booking_repeats, DATE(booking_date) as booking_date from booking where booking_id = '.$this->hddnBookingId;
		
		$bkng = $sableDB->getRow($sql);
		$repeats = intval($bkng['booking_repeats']);
		if ($repeats)
		{
			$date = getNextOccurrence($today, $this->hddnBookingId);
			$count = 0;
			while ($date < $today)
			{
				$today->modify('+1 day');
				$date = getNextOccurrence($today, $this->hddnBookingId);
				$count++;
				if ($count > 9000) break;
			}
			
			if ($date)
				SableSystem::ajaxDisplayMessage('Next occurrence will take place on '.$date->format('l, d F Y'));
			else
				SableSystem::ajaxDisplayMessage('No results available for this booking.');
		}
		else
		{
			SableSystem::ajaxDisplayMessage('This is not a recurring booking; this booking occurs once on '.$bkng['booking_date']);
		}
	}
	
	public function addPayment()
	{
		global $sableDB;
		$now = new DateTime();
		
		$fid = $sableDB->getValue('select * 
								from finance 
								where (txn_type_id = 3) and 
								(client_id = '.$this->params['client_id'].') and 
								(bs_id = '.$this->params['bs_id'].')');	
		if ($fid)
		{
			//A payment for this booking schedule has already been allocated:
			$field	= 'edtBookingTime'.$this->params['booking_id'];
			SableSystem::ajaxResponse(false, "", "Transaction already created.", 5, $field, false, $field);
		}
		else
		{
			//Get the invoice:
			$row = $sableDB->getRow('select * 
									from finance 
									where (txn_type_id = 1) and 
									(client_id = '.$this->params['client_id'].') and 
									(bs_id = '.$this->params['bs_id'].')');

			//add the invoice transaction:
			$ins = 'insert into finance (txn_type_id, pm_id, txn_amount, client_id, bs_id, txn_ip, txn_user, txn_timestamp) 
			values 
			(3, '.$row['pm_id'].', '.(floatval($row['txn_amount'])*-1).', '.$row['client_id'].', '.$row['bs_id'].', "'.SableGeneralFunctions::getRealIpAddr().'", '.$_SESSION['user']['user_code'].', "'.$now->format('Y-m-d H:i:s').'")';
			$res = $sableDB->updateQuery($ins);
			
			if ($res)
			{
				SableDBFunctions::loadAuditDetail($_SESSION["user"]["user_code"], "Payment registered: R".number_format((floatval($row['txn_amount'])*-1), 2).".", $row['bs_id']);
				$repl = "<div>
							<span class='success'><i class='fa fa-check'></i> Transaction successfully generated.</span>
						</div>";
				SableSystem::ajaxFillField($repl, "btnRegPayment".$this->params['booking_id']);
			}
			else
			{
				SableSystem::ajaxResponse(false, "", "Failed to create transaction.", 5, $field, false, $field);
			}
		}
	}
	
	function SMSNotify()
	{
		global $sableDB;
		
		$currentDate = new DateTime();
		$currentDate->setTime(0, 0);		
		
		$plantime = new DateTime($this->eventDate);
		$plantime->setTime(0, 0);
		
		$past = $plantime < $currentDate;
		if ($past)
		{
			SableSystem::ajaxDisplayMessage('Cannot send notifications for past dates.');
		}
		else
		{
			$sql = 'select COALESCE(client_cell, client_phone) as client_mobile, booking_schedule.booking_time, client.client_id  
					from booking_schedule 
					inner join booking on booking.booking_id = booking_schedule.booking_id 
					inner join client on client.client_id = booking.client_id 
					where (DATE(booking_schedule.booking_time) = "'.$plantime->format('Y-m-d').'") 
					and (bs_completed = 0) and (bs_active = 1) and (bs_deleted = 0) 
					and (booking_deleted = 0) and (client_deleted = 0)';
			$rows = $sableDB->getRows($sql);
			if (!empty($rows))
			{
				$count= 0;
				$sent = 0;
				unset($currentDate);
				$currentDate = new DateTime(); //reset the current date to include the current time
				foreach($rows as $row)
				{
					$booktime = new DateTime($row['booking_time']);
					if ($booktime > $currentDate)
					{
						/*
						$message = "Just a reminder that your paw-babies are booked for a Champion grooming session ".
									$booktime->format('Y-m-d')." @ ".$booktime->format('H:i');
						*/
						$message = "Champooches-Just a reminder that your paw-babies are booked for a grooming session ".
							$booktime->format('Y-m-d')." @ ".$booktime->format('H:i').PHP_EOL.
							"Cash/EFT".PHP_EOL."Bookings @ 0738062037. DO NOT REPLY TO THIS SMS.";
						
						$ok = SableSystem::sendSMS($message, $row['client_mobile'], $row['client_id']);
						usleep(100); //allow some time for the sending
						if ($ok) $sent++;
						$count++;
					}
				}
				if ($sent == $count)
					SableSystem::ajaxDisplayMessage($count.' SMS\'s successfully sent.');
				else
					SableSystem::ajaxDisplayMessage($sent.' out of '.$count.'SMS\'s.');
			}
			else
			{
				SableSystem::ajaxDisplayMessage('No notifications were sent.');
			}
		}
	}
	
	function sendSingleSMS()
	{
		global $sableDB;		

		$sql = 'select COALESCE(client_cell, client_phone) as client_mobile, concat(client_name, " ", client_surname) as full_name, 
				client.client_id, booking_schedule.booking_time 
				from booking_schedule 
				inner join booking on booking.booking_id = booking_schedule.booking_id 
				inner join client on client.client_id = booking.client_id 
				where bs_id = '.$this->hddnBsId;
		$row = $sableDB->getRow($sql);
		
		$go = true;
		if (!empty($row))
		{
			if ($row['bs_completed'])
			{
				$go = false;
				SableSystem::ajaxDisplayMessage('Cannot send SMS: this scheduled item has already been completed.');
			}

			if ($row['bs_active'])
			{
				$go = false;
				SableSystem::ajaxDisplayMessage('Cannot send SMS: this scheduled item was cancelled.');
			}

			if ($go)
			{
				$count= 0;
				$sent = 0;
				unset($currentDate);
				$currentDate = new DateTime(); //reset the current date to include the current time
				$booktime = new DateTime($row['booking_time']);
				if ($booktime > $currentDate)
				{
					$message = "Champooches-Just a reminder that your paw-babies are booked for a grooming session ".
						$booktime->format('Y-m-d')." @ ".$booktime->format('H:i').PHP_EOL.
						"Cash/EFT".PHP_EOL."Bookings @ 0738062037. DO NOT REPLY TO THIS SMS.";

					if (SableSystem::sendSMS($message, $row['client_mobile'], $row['client_id']))
						SableSystem::ajaxDisplayMessage('SMS successfully sent to '.$row['full_name']);
					else
						SableSystem::ajaxDisplayMessage('SMS did not send.');					
				}
				else
				{
					SableSystem::ajaxDisplayMessage('Cannot send SMS: cannot send for past dates.');
				}
			}
		}
		else
		{
			SableSystem::ajaxDisplayMessage('No notifications were sent.');
		}
		
	}

} //classBooking