<?php
include_once(SABLE_WORKING_PATH.'almanac/almanac_func.php');

function getMaxDailyBookings()
{
	global $sableDB;
	$mxsql ='select max_daily_bookings 
			from sable_settings 
			where (sable_settings_from <= "'.date('Y-m-d').'") and 
			((sable_settings_to = "0000-00-00") or (sable_settings_to >= "'.date('Y-m-d').'"))';
	$maxDailyBookings = $sableDB->getValue($mxsql); //per team
	return $maxDailyBookings;
}

function printDaysOfMonth($sadom=0)
{
	$html	= '';
	$chk	= '';
	for($i = 1; $i < 32; $i++)
	{
		$chk = !empty($sadom) && isset($sadom[$i]) ? 'checked' : '';
		$html.='<label for="chkbxDay'.$i.'" class="holder" style="width:5%;">
					<span style="margin-left: 6px;">'.sprintf('%02d', $i).'</span>
					<input type="checkbox" name="chkbxDay" id="chkbxDay'.$i.'" value="'.$i.'"  onChange="setSchedulingFields()" '.$chk.'/>
					<span class="checkmark"></span>
				</label>';
	}
	echo($html);
}

function getCheckedDOW($sadow, $dow)
{
	$checked = false;
	foreach($sadow as $sad)
	{
		if ($sad['dow_id'] == $dow) 
		{
			$checked = true;
			break;
		}
	}
	if ($checked) echo('checked');
}

function getHumanDuration($minutes)
{
	if ($minutes == 60)
	{
		$dur = "1 hour";
	}
	elseif ($minutes > 60)
	{
		$durHrs = ($minutes / 60); //gives us the number of hours
		$durMin = $durHrs - (int)($durHrs); //get the minutes of the remainder
		$hrttl	= (int)($durHrs) == 1 ? "hour" : "hours";
		$tm		= (float)($durMin * 60);
		$dur	= (int)($durHrs)." ".$hrttl.", ".number_format($tm, 1)." minutes";
	}
	else
	{
		$dur = number_format($minutes, 1)." minutes";
	}
	return $dur;
}

function getTeamOptions($teamId, $dayDate, $defaultCaption = "Assign Team")
{
	global $sableDB;
	$dow = $dayDate->format('N'); //N - The ISO-8601 numeric representation of a day (1 for Monday, 7 for Sunday)
	$sql = 'select team.team_id, team_name 
			from team 
			inner join team__dow on team__dow.team_id = team.team_id 
			where (team_active = 1) and (team__dow.dow_id = '.$dow.')';
	$teams = $sableDB->getRows($sql);
	$options = '<option value="0">'.$defaultCaption.'</option>';
	$sel = '';
	foreach($teams as $team)
	{
		$sel = ($teamId == $team['team_id']) ? 'selected' : '';
		$options .= '<option value="'.$team['team_id'].'" '.$sel.'>'.$team['team_name'].'</option>';
	}
	return $options;
}

function printTeamOptions($teamId, $dayDate)
{
	$options = getTeamOptions($teamId, $dayDate);
	echo($options);
}

function getDayPlanData($eventDate)
{
	global $sableDB;
	$duration = 0;
	$distance = 0;
	$conflict = 0;
	
	//are we in the present, or the future..?
	$currentDate = new DateTime();
	$currentDate->setTime(0, 0);
	$eventDate->setTime(0,0);
	$past = ($eventDate < $currentDate);
	$tmptime = null;
	$strdtime= null;

	$teams = $sableDB->getRows("select *
								from team 
								inner join team__dow on team__dow.team_id = team.team_id 
								where (team_active = 1) and (team__dow.dow_id = {$eventDate->format('N')})  
								order by RAND()");
								//order by team.team_id"); 
								//order by RAND()');
	$teamMax = count($teams) - 1; //for indexing - indexing starts at zero

	$rows = getDayData($eventDate);

	$sched = [];

	//get coords for the company:
	$coyaddr = $sableDB->getRow('select address.*, company_name
								from company 
								inner join address on address.address_id = company.address_id 
								where company.company_id = '.COMPANY_ID);
	
	$lastAddressId = $coyaddr['address_id'];

	//we have a complete list of all items bookings for the day, single & repeats. 
	//We now go through each of these and:
	foreach($rows as $row)
	{
		//if there is a booking_date, then this is a single booking.
		if (!$row['booking_date']) 
		{
			//scheduled booking, so populate this event date as the booking date:
			$row['booking_date'] = $eventDate->format('Y-m-d');
		}
		
		//Get any booking schedule info, from any previous saves, in which case we need to populate the planner
		//according to this information, rather than work out the schedule:
		$sql = 'select * 
				from booking_schedule 
				where (booking_id = '.$row['booking_id'].') and
				(DATE(booking_time) = "'.$row['booking_date'].'") and (bs_deleted = 0)';	

		$itm		= $sableDB->getRow($sql); //will be empty without any scheduling done yet.
		$isScheduled= !empty($itm); //if not empty, then this booking has been scheduled.

		$bktm 	= $itm['booking_time'] ?? 0;
		$teamid = $itm['team_id'] ?? 0;
		if ($isScheduled) 
		{
			$itm = array_merge($itm, $row);
			//the following fields get lost in the merge??
			$itm['booking_time']	= $bktm;
			$itm['team_id']			= $teamid;
		}
		else
		{
			$itm = $row;
		}
		
		$itm['is_scheduled']	= $isScheduled;	//if already scheduled, then no need to use the DistanceMatrix which takes time.
		$itm['is_past']			= $past; 		//if this event is in the past, then also no need for distance
		$itm['bs_active']		= ($itm['is_scheduled']) ? $itm['bs_active'] : 1; //won't be available if there isn't any schedule info.
		$itm['bs_completed']	= isset($itm['bs_completed']) 	? $itm['bs_completed']	: 0; //won't be available if there isn't any schedule info.	

		//add other relevant data:
		$aid = intval($row['address_id']) ? $row['address_id'] : $coyaddr['address_id']; //in case there is no address for this client.
		$lastAddressId	= $row['address_id'];
		
		//get the time needed for the appointment:
		$totaltime = 0;
		foreach($row['service_info'] as $svc) $totaltime += intval($svc['service_duration']);
		$itm['service_duration_text']	= getHumanDuration($totaltime);
		$itm['service_duration_value']	= $totaltime;

		$sched[] = $itm; //build an array we can work with.
	}
	
	//let's sort according to distance, closest to the office, to furthest:
	$tmp = array_column($sched, 'client_distance');
	array_multisort($tmp, SORT_ASC, $sched);
	
	//now that we have sorted according to distance, we need to allocate each to a team and time-slot:
	$starttime	= clone $eventDate;
	$nexttime	= new DateTime();
	$starttime->setTime(8,0);
	$plan	= [];
	foreach($teams as $team) $plan['team_id'][$team['team_id']] = [];
	$count	= count($teams);
	$c		= 0; //start with the first team - remember this list is randmized for fairness to employees.
	$orgn	= $coyaddr['address_id'];
	$strt	= 1; //start time,from office
	$minutes= 0;
	$svctm	= 0;
	$trvltm = 0;
	
	//SableDebug::debug($teams, 1);
	$shortestDuration	= 0;
	$schedCount			= count($sched);
	$tempSched			= null;
	
	/**
	HERE - before assigning actual times to each auto scheduled item, we should iterate through $sched looking for the closest address (using distance Matrix) in a "bubble-sort" fashion. This means that we start at the top of the list with the closest to the office, and then find the closest address to that address, and so on. Then we can move on the the next for loop which is the scheduling.
	
	!!IMPORTANT!!
	Distance Matrix slows things down a shitload, so if it's too slow, leave this forloop out. Once the Distance Matrix values are stored in the database it goes a lot quicker, but till then, you may need to run it a few times.
	
	REMOVED - TOO SLOW for now...
	for ($x = 0; $x < $schedCount; $x++)
	{
		$shortestDuration = 999999; //meters
		
		for ($i = $x+1; $i < $schedCount; $i++)
		{
			$coords = [];
			$coords['orig'] = array('address_lat' => $sched[$x]['address_lat'],	'address_lng' => $sched[$x]['address_lng']);
			$coords['dest'] = array('address_lat' => $sched[$i]['address_lat'],	'address_lng' => $sched[$i]['address_lng']);
			$distanceMatrix	= SableGeneralFunctions::getDistanceMatrix($sched[$x]['address_id'], $sched[$i]['address_id'], $coords);
			$duration = intval($distanceMatrix['duration']);
			if ($duration < $shortestDuration)
			{
				$shortestDuration = $duration;
				$tempSched = $sched[$x];
				$sched[$x] = $sched[$i]; //replace the current "$sched[$x]" value
				$sched[$i] = $tempSched; //do the swop;
			}
		}	
	}
	
	**/
	
	/**
	Now that we have all of the bookings (client and service info), and we have the list sorted by distance, we can apply the scheduling. Auto scheduling is applied to any non-scheduled items, and previously stored schedules are kept and displayed in their time-slot.
	**/
	foreach($sched as $itemKey => $item)
	{
		$teamid	= $teams[$c]['team_id'];
		$tmp	= [];
		//$active	= intval($item['bs_active'] ?? 1);
		
		//Get the address id for where we are going:
		$dest = isset($item['address_id']) && !empty($item['address_id']) ? $item['address_id'] : $coyaddr['address_id'];
		
		if ($item['is_scheduled'] || $item['is_past'])
		{
			//this item has already been scheduled, so keep it according to the schedule:
			$teamid = $item['team_id']; //assign a team		
		}
		else
		{
			/**
			Being here means this booking is not yet scheduled, or has already been completed.
			**/
			$teamid = $teams[$c]['team_id'];
			$item['team_id']= $teamid;
		}
		
		//Get the distance to the time to travel (ttt) from the previous address to the current address:
		$orgn = $strt ? ($coyaddr['address_id'] ?? 0) : ($plan['team_id'][$teamid]['last_address'] ?? '');
		$orgn = intval($orgn) ? $orgn : $coyaddr['address_id'];

		$coords = [];
		$coords['orig'] = array('address_lat' => $coyaddr['address_lat'],	'address_lng' => $coyaddr['address_lng']);
		$coords['dest'] = array('address_lat' => $item['address_lat'],		'address_lng' => $item['address_lng']);
		$distanceMatrix	= SableGeneralFunctions::getDistanceMatrix($orgn, $dest, $coords);
		$duration		= $distanceMatrix['duration'] ?? 0;

		$strt	= empty($plan['team_id'][$teamid]); //nothing assigned to this team yet, so start at 8:00AM
		
		//store the address for the next round to calculate the distance:
		$plan['team_id'][$teamid]['last_address'] = $dest;
		
		$trvltm= round($duration/60); //convert seconds to minutes
		
		$svctm = $item['service_duration_value'] ?? 0;
		$plan['team_id'][$teamid]['last_service_duration'] = $svctm;
		
		$minutes = (intval($trvltm)+intval($svctm))*1; //ensures numeric
		$item['total_time'] = $minutes;

		//get start time of the previous client for the time for the next appointment:
		$strthr = $strt ? 8 : ($plan['team_id'][$teamid]['next_start_hour']		?? 8);
		$strtmn = $strt ? 0 : ($plan['team_id'][$teamid]['next_start_minute']	?? 0);

		$starttime->setTime($strthr, $strtmn);

		if ($item['is_scheduled'] || $item['is_past'])
		{
			$bktm = new DateTime($item['booking_time']);
			$hour		= $bktm->format('H');
			$minutes	= $bktm->format('i');
		}
		else
		{
			$hour		= $starttime->format('H');
			$minutes	= $starttime->format('i');
		}

		$nexttime = clone $starttime;
		$nexttime->modify("+ {$item['total_time']} minutes");
		
		$plan['team_id'][$teamid]['next_start_hour']	= $nexttime->format('H');
		$plan['team_id'][$teamid]['next_start_minute']	= $nexttime->format('i');
		$plan['team_id'][$teamid]['last_start_hour']	= $hour;
		$plan['team_id'][$teamid]['last_start_minute']	= $minutes;

		//round to the nearest 15 minute slot:
		if (($minutes < 15) && ($minutes > 0))	$minutes = 15;
		elseif (($minutes < 30) && ($minutes > 15)) $minutes = 30;
		elseif (($minutes < 45) && ($minutes > 30)) $minutes = 45;
		elseif (($minutes < 59) && ($minutes > 45)) $minutes = 60;

		$starttime->setTime($hour, $minutes); //rounded to the nearest 15 minutes
		
		$schedtime = ($item['booking_time'] ?? 0) ? new DateTime($item['booking_time']) : $starttime;

		$tmp['client_full_name'] = $item['client_full_name'];
		
		if ($item['is_scheduled'])
		{
			$tmptime = $schedtime->format('H:i');
			$tmHour  = $schedtime->format('H');
			$tmMin   = $schedtime->format('i');
			if (($tmHour > 19) || ($tmHour == 19) && ($tmMin > 0))
			{
				$schedtime->setTime(7,0); //reset this conflicting time; start early
				$tmptime = $schedtime->format('H:i');
			}
		}
		else
		{
			$tmptime = $starttime->format('H:i');
		}
		
		if ($plan['team_id'][$teamid]['times'] ?? 0)
		{
			//"times" array has not been set yet:
			$plan['team_id'][$teamid]['times'][$tmptime] = $item;
		}
		else
		{
			//Now we must ensure that un-scheduled items do not conflict with scheduled items:
			$conflict = 0;
			$strdtime = $tmptime;

			//"times" array has already been set for this team, so check for possible conflicts:
			while (isset($plan['team_id'][$teamid]['times'][$tmptime]))
			{
				$starttime->modify('+15 minutes'); //move if off the space by 15 minutes so it's visible to the user (not overlapping)
				$tmptime = $starttime->format('H:i');
				$item['time_team_conflict'] = 1;
				$conflict = 1;
			}

			if (!$conflict) $plan['team_id'][$teamid]['times'][$strdtime] = $item;			
		}

		//if the time is past 17h00 then move to the next team and start again at 8AM:
		if ($starttime ?? 0)
		{
			if	(($plan['team_id'][$teamid]['next_start_hour'] >= 17) || 
				 (($plan['team_id'][$teamid]['next_start_hour'] > 16) && 
				  ($plan['team_id'][$teamid]['next_start_minute'] >= 30)))
			{
				if ($c < $teamMax) $c++;  //move to the next team
				$teamid = $teams[$c]['team_id'];
				//xxx --> $teamid	= $teams[$c]['team_id'];
				$starttime->setTime(8,0);
				$tmptime = $starttime->format('H:i');
				$plan['team_id'][$teamid]['last_start_hour'] = 8;
				$plan['team_id'][$teamid]['last_start_minute'] = 0;
			}
		}
		
		$tmp['time'] = $tmptime;

		//ammend the plan:
		$plan['team_id'][$teamid]['times'][$tmp['time']] = $item; //$tmp['client_full_name'];
		
		/**
		SableDebug::debug("Team ID: {$teamid}, Client ID: {$item['client_id']} ({$item['client_full_name']}) - {$trvltm} minutes from departure, Appointment Starts: {$starttime->format('H:i')} and lasts for {$svctm} minutes.", 1);
		**/
		
	} //foreach $item
	//SableDebug::debug($plan, 1);
	
	//sort the times from earliest to latest, per team:
	if (is_array($plan['team_id']))
	{
		foreach($plan['team_id'] as $key => $team)
		{
			if (is_array($team['times'] ?? 0))
			{
				$tmp = $team['times'];
				ksort($tmp);
				$plan['team_id'][$key]['times'] = $tmp;
			}
		}
	}
	
	//SableDebug::debug($plan, 1);
	return $plan;
}

function getDayBookings($eventDate, $plan, $filterTeamId = 0)
{
	global $sableDB;
	
	if (empty($plan))
		$rows = getDayPlanData($eventDate);// getDayPlanData calls getDayData($eventDate) and sorts all the info for us.
	else
		$rows = $plan;
	
	//SableDebug::debug($plan, 1);
	
	/**
	{
		Array
		(
			[team_id] => Array
				(
					[3] => Array
						(
							[last_address] => 42
							[last_service_duration] => 45
							[last_start_hour] => 8
							[last_start_minute] => 0
							[08:00] => Array
								(
									[distance_text] => 55 m
									[distance_value] => 55
									[duration_text] => 1 min
									[duration_value] => 9
									[service_duration_text] => 45.0 minutes
									[service_duration_value] => 45
									[booking_id] => 10
									[client_full_name] => Victor 
									[client_phone] => 0836447967
									[address_lat] => 28.094232
									[address_lng] => -26.292679
									[client_id] => 63
									[booking_date] => 2021-08-28
									[address_id] => 42
								)

						)

					[4] => Array
						(
							[last_address] => 43
							[last_service_duration] => 60
							[last_start_hour] => 8
							[last_start_minute] => 0
							[08:00] => Array
								(
									[distance_text] => 0.3 km
									[distance_value] => 293
									[duration_text] => 1 min
									[duration_value] => 63
									[service_duration_text] => 1 hour
									[service_duration_value] => 60
									[booking_id] => 32
									[client_full_name] => Hannelie 
									[client_phone] => 0824922712
									[address_lat] => 28.0932009
									[address_lng] => -26.2909975
									[client_id] => 64
									[booking_date] => 2021-08-28
									[address_id] => 43
								)

						)

				)

		)
	}
	**/
	$today	= new DateTime(); //today
	$today->setTime(0,0);
	$eventDate->setTime(0,0);
	$past	= $eventDate < $today;

	//get coords for the company:
	$coyaddr = $sableDB->getRow('select address.*, company_name
								from company 
								inner join address on address.address_id = company.address_id 
								where company.company_id = '.COMPANY_ID);
	
	/**
	Array
	(
		[0] => Array
			(
				[booking_id] => 1
				[booking_time] => 
				[client_name] => Marietjie van Gerve
				[service_info] => Array
					(
						[0] => Array
							(
								[area_type_name] => Dog
								[area_name] => Yorkshire Terrier
								[building_name] => Noah
								[building_notes] => 2017-01-31
								[building_special_instructions] => 
								[service_name] => Groom (Large Dog)
								[service_price] => 280
								[service_duration] => 30
							)

						[1] => Array
							(
								[area_type_name] => Dog
								[area_name] => Yorkshire Terrier
								[building_name] => Melina
								[building_notes] => 2018-12-10
								[building_special_instructions] => 
								[service_name] => Groom (Large Dog)
								[service_price] => 280
								[service_duration] => 30
							)

						[2] => Array
							(
								[area_type_name] => Dog
								[area_name] => Yorkshire Terrier
								[building_name] => Mitzi
								[building_notes] => 2020-04-09
								[building_special_instructions] => Needs to be lightly sedated.
								[service_name] => Groom (Large Dog)
								[service_price] => 280
								[service_duration] => 30
							)

					)

			)

		[1] => Array
			(
				[booking_id] => 3
				[booking_time] => 
				[client_name] => Jason Pieterse 
				[service_info] => Array
					(
						[0] => Array
							(
								[area_type_name] => Dog
								[area_name] => Yorkshire Terrier
								[building_name] => Noah
								[building_notes] => 2017-01-31
								[building_special_instructions] => 
								[service_name] => Groom (Large Dog)
								[service_price] => 280
								[service_duration] => 30
							)

					)

			)

	)	
	**/
	$html ="<table style='width:100%;' class='calendar_table text-left'>
				<tr><td></td></tr>";
	$x = 0;
	if (empty($rows))
	{
		$html .= "<tr>";
		$html .= "	<td colspan='6'>";
		$html .= "		<h3 class='title'>No events for ".getDisplayDate($eventDate)."</h3>";
		$html .= "	</td>";
		$html .= "</tr>";
	}
	else
	{
		$html .='<tr>
					<td class="booking_heading" style="width:10%">Client</td>
					<td class="booking_heading" style="width:55%">Building</td>
					<td class="booking_heading" style="width:15%">Service</td>
					<td class="booking_heading" style="width:99%">Plan</td>
				</tr>';
		$ci = true;
		
		$origAddressId  = $coyaddr['address_id'];
		$origAddressLat = $coyaddr['address_lat'];
		$origAddressLng = $coyaddr['address_lng'];
		$origPlace		= $coyaddr['company_name'];
		
		foreach($rows as $row)
		{
			foreach($row as $teamid=>$planner)
			{
				/** PLAN::
				{
					Array
					{
						[last_address] => 42
						[last_service_duration] => 45
						[last_start_hour] => 8
						[last_start_minute] => 0
						[times] => Array
						{
								[08:00] => Array
								{
										[booking_id] => 10
										[client_id] => 63
										[booking_date] => 2021-08-28
										[booking_time] => 
										[team_id] => 
										[client_full_name] => Victor 
										[suburb_name] => Alberton
										[region_name] => Johannesburg
										[sa_description] => Repeats every 2nd week on Saturday.
										[address_id] => 42
										[address_lng] => -26.292679
										[address_lat] => 28.094232
										[client_phone] => 0836447967
										[bs_completed] => 
										[service_info] => Array
										{
												[0] => Array
												{
														[service_id] => 56
														[area_type_name] => Dog
														[area_name] => Chow
														[building_id] => 80
														[building_name] => Zion
														[building_notes] => 
														[building_special_instructions] => 
														[service_name] => Large - Long Hair - Wash & Brush
														[service_price] => 280
														[service_duration] => 45
														[bs_price_override] => 
													}
										}
										[distance_text] => 55 m
										[distance_value] => 55
										[duration_text] => 1 min
										[duration_value] => 9
										[service_duration_text] => 45.0 minutes
										[service_duration_value] => 45
								}
						}
					}
				}
				**/
				if (is_array($planner['times'] ?? 0))
				{
					foreach($planner['times'] as $plan)
					{
						$ic		= true;
						$ci		= !$ci;
						$cls	= $ci ? 'booking_info_alt' : '';						
						if (!$plan['booking_date']) $plan['booking_date'] = $eventDate->format('Y-m-d');

						//get any booking schedule info:
						$sql = 'select * 
								from booking_schedule 
								where (booking_id = '.$plan['booking_id'].') and
								(DATE(booking_time) = "'.$plan['booking_date'].'") and (bs_deleted = 0)';
						$sched = $sableDB->getRow($sql);

						if (!$filterTeamId || ($sched['team_id'] == $filterTeamId))
						{
							$destAddressId = intval($plan['address_id']) ? $plan['address_id'] : $origAddressId;
							
							$coords = [];
							$coords['orig'] = array('address_lat' => $origAddressLat,		'address_lng' => $origAddressLng);
							$coords['dest'] = array('address_lat' => $plan['address_lat'],	'address_lng' => $plan['address_lng']);
							
							$distanceMatrix = SableGeneralFunctions::getDistanceMatrix($origAddressId, $destAddressId, $coords);
							/**
							Array
							(
								[distance] => 8258
								[duration] => 970
								[distance_text] => 8.3 km
								[duration_text] => 16 mins
							)							
							**/
							$distance	= $distanceMatrix['distance_text'] ?? '';
							$travelTime	= $distanceMatrix['duration'] ?? 0; //duration in minutes

							$tt = getHumanDuration($travelTime/60);
							
							if ($sched['booking_time'] ?? 0)
							{
								$bookingTime = new DateTime($sched['booking_time']);
							}
							else
							{
								$bookingTime = new DateTime($plan['booking_date'].' 07:00:00');
							}
							
							$targetid = "div_".($sched['team_id'] ?? 0)."_".$bookingTime->format('H')."_".
										$bookingTime->format('i')."_".$plan['client_id']."_".$plan['booking_id'];
							unset($bookingTime); //gets used later again.

							$html.="<tr id='tr_".$plan['client_id']."_".$teamid."'>
										<td class='".$cls." booking_info'>
											<a href='javascript:showPlanItem(\"".$targetid."\")'>
												<table>
													<tr>
														<td class='service_info_label'>Name:</td>
														<td>".$plan['client_full_name']."</td>
													</tr>
													<tr>
														<td class='service_info_label'>Pattern:</td>
														<td>".$plan['sa_description']."</td>
													</tr>
													<tr>
														<td class='service_info_label'>Area:</td>
														<td>".$plan['suburb_name'].", ".$plan['region_name']."</td>
													</tr>
													<tr>
														<td class='service_info_label'>Distance:</td>
														<td>".$distance."</td>
													</tr>
													<tr>
														<td class='service_info_label'>Travel:</td>
														<td>".$tt." from <br>".$origPlace."</td>
													</tr>
												</table>
											</a>
										</td>
										<td class='".$cls." booking_info'>";

							$origAddressId	= $destAddressId;
							$origPlace		= $plan['client_full_name']; //for the next destination

							if (!empty($plan['service_info']) && isset($plan['service_info']))
							{
								foreach($plan['service_info'] as $serv) //for loop for the building info
								{
									$ic = !$ic;
									$cli = $ic ? 'service_info_alt' : 'service_info';

									$html.="	<table>
													<tr>
														<td class='".$cli." service_info_label'>Name:</td>
														<td class='".$cli."'>".$serv['building_name']." (".$serv['area_type_name'].")</td>
													</tr>
													<tr>
														<td class='".$cli." service_info_label'>Area:</td>
														<td class='".$cli."'>".$serv['area_name']."</td>
													</tr>";
									if ($serv['building_special_instructions'])
									{
										$html .= "	<tr>
														<td class='".$cli." service_info_label'>Needs:</td>
														<td class='".$cli."'>".$serv['building_special_instructions']."</td>
													</tr>";
									}
									else
									{
										$html .= "	<tr>
														<td class='".$cli." service_info_label'></td>
														<td class='".$cli."'></td>
													</tr>";
									}
									$html.="	</table>";

								} //for loop for the building info

								$html.="</td>
										<td class='".$cls." booking_info'>";

								$ic				= true;
								$totalDuration	= 0;
								$totamt			= 0;

								foreach($plan['service_info'] as $serv) //for loop for the service info
								{
									$ic = !$ic;
									$cli = $ic ? 'service_info_alt' : 'service_info';

									$svcPrice		= $serv['bs_price_override'] ? $serv['bs_price_override'] : $serv['service_price'];					
									$rand			= number_format(floatval($svcPrice), 2);
									$dur			= getHumanDuration($serv['service_duration']);
									$totalDuration += $serv['service_duration'];
									$totamt += floatval($svcPrice);
									$class			= $past || ($sched['bs_completed'] ?? 0) ? 'readonly' : 'mod';
									$disabled		= $past || ($sched['bs_completed'] ?? 0) ? 'readonly' : '';

									$html.="	<table>
													<tr>
														<td class='".$cli." service_info_label'>Service:</td>
														<td class='".$cli."'>".$serv['service_name']."</td>
													</tr>
													<tr>
														<td class='".$cli." service_info_label'>Price:</td>
														<td class='".$cli."'>
															<input class='".$class."' ".$disabled." type='number' step='0.01' id='edtServicePrice".$plan['booking_id']."_".$serv['building_id']."' 
															 name='edtServicePrice".$plan['booking_id']."' 
															 value='".$svcPrice."' service-id='".$serv['service_id']."' building-id='".$serv['building_id']."'>
														</td>
													</tr>
													<tr>
														<td class='".$cli." service_info_label'>Duration:</td>
														<td class='".$cli."'>".$dur."</td>
													</tr>						
												</table>";


								} //for loop for the service info

							}
							else
							{
								$html.="<td></td>";
							}

							$totdur = getHumanDuration($totalDuration);

							$bookingTime	= empty($sched['booking_time']) ? '' : new DateTime($sched['booking_time']);
							$scheduleTime	= empty($sched['booking_time']) ? '' : $bookingTime->format('H:i');
							$scheduleDate	= empty($sched['booking_time']) ? $eventDate->format('Y-m-d') : $bookingTime->format('Y-m-d');

							/**
							if (($sched['team_id']) || ($sched['booking_time']))
								$scheduleActive = (intval($sched['bs_active'])) ? "checked" : "";
							else
								$scheduleActive = "checked";
							**/
							$tmp = (($sched['bs_active'] ?? 0) === null) ? 1 : intval($sched['bs_active'] ?? 1);
							$scheduleActive = $tmp ? "checked" : "";

							$saveParams = [];
							$saveParams['booking_id']		= $plan['booking_id'];
							$saveParams['schedule_date']	= $scheduleDate;
							$saveParams['service_duration']	= $totalDuration;
							$saveParams['travel_time']		= ($travelTime/60);
							$jsParams = json_encode($saveParams);

							$disabled	= $past || ($sched['bs_completed'] ?? 0) ? "disabled class='readonly noArrow' " : "";
							$class		= $past || ($sched['bs_completed'] ?? 0) ? "class='readonly'" : '';
							$switch		= $past || ($sched['bs_completed'] ?? 0) ? "" : "class='switch'";
							
							$bookNote	= '';
							
							if ((!empty($plan['client_booking_note'])) || !empty($plan['booking_note']))
							{
								$bknt = $plan['client_booking_note'].'<br>'.$plan['booking_note'];
								$bookNote = "<tr>
												<td class='{$cls}' colspan='3' style='color:red; font-style:italic;'>
													<i class='fa ".NOTES_ICON."'></i>&nbsp;{$bknt}
												</td>
											</tr>";
							}

							$html.="</td>
									<td class='".$cls." booking_info'>
										<table>
											{$bookNote}
											<tr>
												<td class='service_info_label'>Date:</td>
												<td class='forms-grid' colspan='2'>
													<input type='date' id='edtBookingDate".$plan['booking_id']."' value='".$scheduleDate."' ".$disabled.">
												</td>
											</tr>						
											<tr>
												<td class='service_info_label'>Team:</td>
												<td class='forms-grid' colspan='2'>
													<select id='selTeamId".$plan['booking_id']."' ".$disabled.">
													".getTeamOptions(($sched['team_id'] ?? 0), $eventDate)."
													</select>
												</td>
											</tr>
											<tr>
												<td class='service_info_label'>Time:</td>
												<td class='forms-grid' colspan='2'>
													<input type='time' id='edtBookingTime".$plan['booking_id']."' value='".$scheduleTime."' placeholder='' ".$disabled.">
												</td>
											</tr>";
							
							if (!($sched['bs_completed'] ?? 0))
							{
								if ($past)
								{
									$html .="	<tr>
													<td class='service_info_label' width='15%'>Active:</td>
													<td class='forms-grid' width='70%'>
														<div ".$switch.">
															<input id='cbScheduleActive".$plan['booking_id']."' type='checkbox' 
																	class='form-toggle form-toggle-yes-no' ".$scheduleActive." />
															<label for='cbScheduleActive".$plan['booking_id']."' data-on='Active' data-off='Cancelled'></label>
														</div>	
													</td>
													<td width='15%'>

													</td>
												</tr>";									
								}
								else
								{
									$html .="	<tr>
													<td class='service_info_label' width='15%'>Active:</td>
													<td class='forms-grid' width='70%'>
														<div ".$switch.">
															<input id='cbScheduleActive".$plan['booking_id']."' type='checkbox' 
																	class='form-toggle form-toggle-yes-no' ".$scheduleActive." />
															<label for='cbScheduleActive".$plan['booking_id']."' data-on='Active' data-off='Cancelled'></label>
														</div>	
													</td>
													<td width='15%'>
														<button type='button' onclick='deleteBooking(\"".($plan['booking_id'] ?? 0)."\", \"".trim($plan['client_full_name'])."\", \"".($sched['bs_id'] ?? 0)."\")'>
															<i class='fa fa-trash'></i>
														</button>
													</td>
												</tr>";
								}
							}

							$html .= "		<tr>
												<td class='service_info_label'>Duration:</td>
												<td class='forms-grid' colspan='2'>".$totdur."</td>	
											</tr>
											<tr>
												<td class='service_info_label'>Total:</td>
												<td class='forms-grid' colspan='2'>R".number_format($totamt, 2)."</td>	
											</tr>";

							if (($sched['bs_id'] ?? 0) && ($sched['bs_completed'] ?? 0))
							{
								$payParams					= [];
								$payParams['booking_id']	= $plan['booking_id'];
								$payParams['client_id']		= $plan['client_id'];
								$payParams['bs_id']			= $sched['bs_id'];

								$jsParams = json_encode($payParams);
								$finsql = "select finance_id from finance where (txn_type_id = 3) and (client_id = ".$plan['client_id'].") and 
										(bs_id = ".$sched['bs_id'].")";
								$hastxn = $sableDB->getValue($finsql);
								$payhtml = "	<tr>
												<td colspan='3' class='forms-grid'>
													<div id='btnRegPayment".$plan['booking_id']."'>
														<input type='button' id='btnPayment".$plan['booking_id']."' value='Register Payment' class='submit' onclick='addPayment(".$jsParams.")'>
													</div>
												</td>
											</tr>";
								$html .= $hastxn ? "" : $payhtml;
							}
							else
							{
								if ($past)
								{
									$html .= "	<tr>
													<td colspan='2' class='forms-grid' width='70%'>
														<input type='button' id='btnSave".$plan['booking_id']."' value='Save' class='submit' 
														onclick='saveBooking(".$jsParams.")'>
													</td>
													<td width='15%'>

													</td>
												</tr>";								
								}
								else
								{
									$html .= "	<tr>
													<td colspan='2' class='forms-grid' width='70%'>
														<input type='button' id='btnSave".$plan['booking_id']."' value='Save' class='submit' 
														onclick='saveBooking(".$jsParams.")'>
													</td>
													<td width='15%'>
														<button class='submit' type='button' onclick='sendSingleSMS(".($sched['bs_id'] ?? 0).")'>
															<i class='fa fa-sms'></i>
														</button>
													</td>
												</tr>";
								}
							}

							$html .= "		<tr>
												<td class='service_info_label' colspan='3' >
													<div id='hint_edtBookingTime".$plan['booking_id']."'></div>
												</td>
											</tr>
										</table>
									</td>
								</tr>";
						} //exclude if not the selected team
					}
				}
			}
		} //foreach scheduled item
	}
	$html .= '</table>';
	return($html);
}

function printDayBookings($eventDate, $plan)
{
	$html = getDayBookings($eventDate, $plan);
	echo($html);
}

function getNextOccurrence($dateFrom, $bookingId)
{
	$fromDate = clone $dateFrom; //Otherwise we actually modify the parameter value from the sending function!!
	$occurences = getRecurringEvents($dateFrom, $bookingId);

	$y = $fromDate->format('Y');
	$m = $fromDate->format('m');
	$d = $fromDate->format('d');
	
	//if there's an occurence today, move our date one day forward and get the next occurrence:
	if (isset($occurences[$y][$m][$d]))
	{
		$fromDate->modify('+1 day');
		$occurences = getRecurringEvents($fromDate, $bookingId);
		//SableDebug::debug($occurences);
		$y = $fromDate->format('Y');
		$m = $fromDate->format('m');
		$d = $fromDate->format('d');
	}

	$found = false;
	if (!empty($occurences))
	{
		foreach($occurences as $year=>$ykey)
		{
			foreach($ykey as $month=>$mkey)
			{
				foreach($mkey as $day=>$dkey)
				{
					$found = ($day >= $d) && ($month == $m) && ($year == $y);
					if ($found) break;
				}
				if ($found) break;
			}
			if ($found) break;
		}
		$evtdt = new DateTime();
		if ($year && $month && $day) $evtdt->setDate($year, $month, $day);
		$evtdt->setTime(0,0);

		return $evtdt;
	} else return 0; //nothing
}

function getTeams($header)
{
	global $teams, $sableDB, $width;
	$html = '';
	
	foreach($teams as $team)
	{
		if ($header)
			$html .= '<td width="'.$width.'%">'.$team['team_name'].'</td>';
		else
			$html .= '<td width="'.$width.'%">&nbsp;</td>';
	}
	return $html;
}

function getTimes($plan)
{
/**
Array
(
    [team_id] => Array
        (
            [1] => Array
                (
                    [08:00] => Array
                        (
                            [distance_text] => 3.5 km
                            [distance_value] => 3461
                            [duration_text] => 7 mins
                            [duration_value] => 407
                            [service_duration_text] => 2 hours, 15.0 minutes
                            [service_duration_value] => 135
                            [client_full_name] => Tracy 
                            [client_phone] => 0722204880
                            [address_lat] => 28.0954193
                            [address_lng] => -26.3160887
                            [client_id] => 125
                            [booking_date] => 2021-08-31
                            [address_id] => 101
                        )
**/
	global $timewidth, $teams;
	$currentDate = new DateTime();
	$currentDate->setTime(0, 0);
	$tm = new DateTime('07:00');
	$hr = $tm->format('H');
	$i = 0;
	$html = '';
	
	$desc = '';
	//$maxPerDay = intval(getMaxDailyBookings());
	$data = null;
	$notesIcon = '';
	
	while ($hr != '19:00')
	{
		$hr = $tm->format('H:i');
		$i++;
		if ($i > 300) break; //security to avoid endless loop
		$class = ($i % 2) ? "plan_row_alt" : "plan_row";
		
		$trid = 'tr_'.$tm->format('H').'_'.$tm->format('i');
		$html.='<tr class="'.$class.'">
					<td width="'.$timewidth.'%" style="text-align:center;">'.$hr.'</td>';
		
		$countPerTeam = 0;
		foreach($teams as $team)
		{
			
			$tmid		= $team['team_id'];
			
			$data		= $plan['team_id'][$tmid]['times'][$hr] ?? 0;
			
			$slotin		= isset($data) && ($data['bs_active'] ?? 0);
			
			$clientid	= $data['client_id'] ?? 0;
			$bookngid	= $data['booking_id'] ?? 0;
			
			$bookingDate	= new DateTime($data['booking_date'] ?? '');
			$past			= $bookingDate < $currentDate;
			
			//SableDebug::debug($data);
			$area = ($data['suburb_name'] ?? 'Unknown').', '.($data['region_name'] ?? '');
			$address = '<a href="https://www.google.com/maps/search/?api=1&query='.($data['address_lng'] ?? '0').'%2C'.($data['address_lat'] ?? '0').'" target="new">'.($data['address'] ?? 'Unknown').'</a>';
			//$clnt = $slotin ? $data['client_full_name'].'; '.getHumanDuration($data['total_time']) : '&nbsp;';

			/*
			if (intval($data['bs_id']))
			{
				if (intval($data['bs_completed']))
				{
					$icon = COMPLETED_ICON;
				}
				else
				{
					$icon = intval($data['sa_id']) ? RECURRING_ICON : SINGLE_ICON;
				}
			}
			else
			{
				$icon = UNSCHEDULED_ICON;
			}
			*/
			$notesIcon = '';
			if ((!empty($data['client_booking_note'])) || !empty($data['booking_note']))
			{
				$bknt = $data['client_booking_note'].PHP_EOL.$data['booking_note'];
				$notesIcon = '&nbsp;<i class="fa '.NOTES_ICON.'" style="color: red;" title="'.$bknt.'"></i>';				
			}
			//else
			{
				if (intval($data['bs_completed'] ?? 0))
				{
					$icon = COMPLETED_ICON;
				}
				else
				{
					if (!($data['bs_id'] ?? 0))
						$icon = UNSCHEDULED_ICON;
					else
						$icon = intval($data['sa_id']) ? RECURRING_ICON : SINGLE_ICON;
				}
				$desc = getIconHTML($icon).$notesIcon.'<br><strong>'.($data['client_full_name'] ?? 'Unknown').'</strong> ['.($data['client_phone'] ?? '').']<br>
				<span class="planner_area">'.$address.'</span>';				
			}

			//<br><i>'.$data['sa_description'].'</i>';//<br>'.$data['service_duration_text'];
			
			$clnt = $slotin ? $desc : '&nbsp;';

			$itmid = $tmid.'_'.$tm->format('H').'_'.$tm->format('i').'_'.$clientid.'_'.$bookngid;
			
			//$class = $data['bs_completed'] || $past ? 'clientblock' : 'dragblock'; //marks red if completed OR in the past.
			
			if ($past)
				$class = ($data['bs_completed'] ?? 0) ? 'clientblock'	: 'incompleteblock'; //marks green if completed, red if incomplete
			else
				$class = ($data['bs_completed'] ?? 0) ? 'clientblock'	: 'dragblock'; //marks green only if completed.
			
			$style = ($data['time_team_conflict'] ?? '') ? 'style="border: 3px red solid;"' : '';
			/*
			$sdv = (round($data['service_duration_value'] / 15)+1) * 85;
			$style = 'style="height: '.$sdv.'px;"';
			**/
			
			$dragblock = '<div id="div_'.$itmid.'" class="'.$class.'" name="dragblock" onclick="showDetail(this)" '.$style.'>'.
							$clnt.'
						</div>';
			
			$val  = $slotin?$dragblock:'&nbsp;';
			$class = ($data['bs_completed'] ?? 0)|| $past ? '' : 'plandrop'; //no dragNdrop if completed if in the past.
			$html.= '<td class="'.$class.'" id="td_'.$itmid.'">'.$val.'</td>';
			$countPerTeam++;
		}
		
		$html.='</tr>';
		$tm->modify('+ 15 minutes');
	}
	return $html;
}

function printTeams($header)
{
	echo getTeams($header);
}

function printTimes($plan)
{
	echo getTimes($plan);
}

function addTabs($buttons)
{
	$html = '';
	foreach($buttons as $button)
	{
		$icon = null;
		$but = $button['icon'];
		$sty = "font-size:1.5em;";
		$icon = '<i class="fa '.$but.'" style="'.$sty.'"></i>';

		$html.='<div class="col-xs-2 col-sm-2 col-md-2 col-lg-2 pointer">
					<div class="sable-tab" title="'.$button['title'].'">'.$icon.'&nbsp;'.$button['label'].'</div>
				</div>';
	}
	echo($html);
}

function getDriverScheduleData($nextItemOnly = false)
{
	global $sableDB;
	$sqldt	= 'CURDATE()';
	$teamids = $sableDB->getValue('select group_concat(team_id) from team__user where user_code = '.$_SESSION['user']['user_code']);

	$sql = 'select bs_id, booking_schedule.booking_time, booking.booking_date, 
			concat(client_name, " ", client_surname) as client_full_name, address, 
			COALESCE(client_cell, client_phone) as client_cell, booking.sa_id, standing_appointment.sa_start_date 
			from booking_schedule 
			inner join booking on booking.booking_id = booking_schedule.booking_id 
			inner join client on client.client_id = booking.client_id 
			inner join address on address.address_id = client.address_id 
			inner join team on team.team_id = booking_schedule.team_id 
			left join standing_appointment on standing_appointment.sa_id = booking.sa_id 
			where (booking_deleted = 0) and DATE(booking_schedule.booking_time) = CURDATE()	
			and (booking_schedule.team_id in ('.$teamids.')) and (bs_active = 1) and (bs_completed = 0) and (bs_deleted = 0)
			order by booking_schedule.booking_time';
	if  ($nextItemOnly) $sql .= " limit 0,1";
	$rows = $sableDB->getRows($sql);
	return $rows;
}

// define who may/may not access this page:
$allowedPages = ['index.php', 'calendar.php'];
// define who may/may not access this page:
$loginRequired = true; //set to false if you do not need to be logged in to access this module.
$loggedIn = SableSystem::loggedIn();
$allowModuleAccess = ($loggedIn && $loginRequired) || in_array($_SESSION['current_page'], $allowedPages);
if ($allowModuleAccess)
{
	/** To be here means that the user is logged in, as is required. **/
}
else
{
	/** Add necessary code for restrictions, beyond login requirements, here. **/
	SableGeneralFunctions::revertToLoginPage();
}

$today			= new DateTime();
$calendarDate 	= new DateTime();
$dayDate 		= new DateTime();

$dd = $calendarDate->format('d');
$mm = $calendarDate->format('m');
$yy = $calendarDate->format('Y');		

$tabNo = '1';
$tabs	= [];

if (isset($_SESSION['caller']['args'][4]))
{
	$dd = $_SESSION['caller']['args'][1];
	$mm = $_SESSION['caller']['args'][2];
	$yy = $_SESSION['caller']['args'][3];		
	//$calendarDate->setDate($yy, $mm, $dd);
	$fmt = "Y-m-d";
	$actdt = $yy."-".$mm."-".$dd;

	$calendarDate::createFromFormat($fmt, $actdt);
	$calendarDate->setDate($yy, $mm, $dd);
	//$dayDate->setDate($yy, $mm, $dd);
	$dayDate::createFromFormat($fmt, $actdt);
	$dayDate->setDate($yy, $mm, $dd);
}

$tabId	= 'sable-tab-'.$tabNo;

$fmt = "Y-m-d";
$actdt = $yy."-".$mm."-".$dd;

$prevDate = clone $calendarDate;
$prevDate->setDate($yy, $mm, $dd);

$nextDate = clone $calendarDate;
$nextDate->setDate($yy, $mm, $dd);

$prevDate->modify('-1 month');
$nextDate->modify('+1 month');

//fields used by the planner:
$timewidth = 8;
$teams = $sableDB->getRows('select *
							from team 
							inner join team__dow on team__dow.team_id = team.team_id 
							where (team_active = 1) and (team__dow.dow_id = '.$dayDate->format('N').')');
$width = sizeof($teams) ? intval((100 - $timewidth) / sizeof($teams)) : 0;

$singleBookings	= getEvents($calendarDate);
$tmpDate = clone $calendarDate;
$recurBookings	= getRecurringEvents($tmpDate);