<?php
if (!defined("ROOT_PATH"))
{
	header("HTTP/1.1 403 Forbidden");
	exit;
}
class pjFront extends pjAppController
{
	public $defaultFields = 'fields';
	
	public $defaultCaptcha = 'HBooking_Captcha';
	
	public $defaultLocale = 'HBooking_LocaleId';
	
	public $defaultStore = 'HBooking_Store';
	
	public $defaultVoucher = 'HBooking_Voucher';
	
	public $defaultClient = 'HBooking_Client';
	
	public function __construct()
	{
		$this->setLayout('pjActionFront');
		self::allowCORS();
		
	}
	
	public function afterFilter()
	{
	    if (!$this->_get->check('hide') || ($this->_get->check('hide') && $this->_get->toInt('hide') !== 1) &&
	        in_array($this->_get->toString('action'), array('pjActionSearch', 'pjActionRooms', 'pjActionExtras', 'pjActionCheckout', 'pjActionPreview', 'pjActionBooking', 'pjActionLogin', 'pjActionProfile', 'pjActionForgot', 'pjActionGetExtrasPayments', 'pjActionCancel')))
	    {
	        $locale_arr = pjLocaleModel::factory()->select('t1.*, t2.file, t2.title')
	        ->join('pjBaseLocaleLanguage', 't2.iso=t1.language_iso', 'left')
	        ->where('t2.file IS NOT NULL')
	        ->orderBy('t1.sort ASC')->findAll()->getData();
	        
	        $this->set('locale_arr', $locale_arr);
	    }
	}
	
	public function beforeFilter()
	{
		if ($this->_get->toInt('cid') > 0)
	    {
	        $cid = $this->_get->toInt('cid');
	        $this->models['Option'] = pjBaseOptionModel::factory();
		    $base_option_arr = $this->models['Option']->getPairs($cid);
		    $script_option_arr = pjOptionModel::factory()->getPairs($cid);
		    $this->option_arr = array_merge($base_option_arr, $script_option_arr);
		    $this->set('option_arr', $this->option_arr);
	    }	    
	    if($this->_get->toInt('locale') > 0)
	    {
	        $_SESSION[$this->defaultLocale] = $this->_get->toInt('locale');
	        $this->loadSetFields(true);
	    }
	    return parent::beforeFilter();
	}
	
	public function beforeRender()
	{
		if (isset($_GET['iframe']))
		{
			$this->setLayout('pjActionIframe');
		}
	}
	
	
	public function pjActionCaptcha()
	{
	    $this->setAjax(true);
	    
	    header("Cache-Control: max-age=3600, private");
	    $rand = $this->_get->toInt('rand') ? $this->_get->toInt('rand') : rand(1, 9999);
	    $patterns = 'app/web/img/button.png';
	    if(!empty($this->option_arr['o_captcha_background_front']) && $this->option_arr['o_captcha_background_front'] != 'plain')
	    {
	        $patterns = PJ_INSTALL_PATH . $this->getConstant('pjBase', 'PLUGIN_IMG_PATH') . 'captcha_patterns/' . $this->option_arr['o_captcha_background_front'];
	    }
	    $Captcha = new pjCaptcha(PJ_INSTALL_PATH . $this->getConstant('pjBase', 'PLUGIN_WEB_PATH') . 'obj/arialbd.ttf', $this->defaultCaptcha, (int) $this->option_arr['o_captcha_length_front']);
	    $Captcha->setImage($patterns)->setMode($this->option_arr['o_captcha_mode_front'])->init($rand);
	    exit;
	}
	
	public function pjActionCheckCaptcha()
	{
	    $this->setAjax(true);
	    if (!$this->_get->check('captcha') || !$this->_get->toString('captcha') || !pjCaptcha::validate($this->_get->toString('captcha'), $_SESSION[$this->defaultCaptcha])){
	        echo 'false';
	    }else{
	        echo 'true';
	    }
	    exit;
	}
	
	public function pjActionCheckReCaptcha()
	{
	    $this->setAjax(true);
	    $verifyResponse = file_get_contents('https://www.google.com/recaptcha/api/siteverify?secret='.$this->option_arr['o_captcha_secret_key_front'].'&response='.$this->_get->toString('recaptcha'));
	    $responseData = json_decode($verifyResponse);
	    echo $responseData->success ? 'true': 'false';
	    exit;
	}
	
	public function isFrontLogged()
	{
	    if (isset($_SESSION[$this->defaultClient]) && count($_SESSION[$this->defaultClient]) > 0)
	    {
	        $user = pjAuth::init(array('id' => $this->getClientId()))->getUser();
	        if($user['status'] == 'F')
	        {
	            $this->session->unsetData($this->defaultClient);
	            return false;
	        }
	        return true;
	    }
	    return false;
	}
	
	public function getClientId()
	{
	    return isset($_SESSION[$this->defaultClient]) && array_key_exists('id', $_SESSION[$this->defaultClient]) ? $_SESSION[$this->defaultClient]['id'] : FALSE;
	}
	
	public function pjActionLoad()
	{
	    $this->setAjax(false);
	    $this->setLayout('pjActionFront');
		ob_start();
		header("Content-Type: text/javascript; charset=utf-8");
	}
	
	public function pjActionLoadExtraPayments()
	{
	    $this->setAjax(false);
	    $this->setLayout('pjActionFront');
	    ob_start();
	    header("Content-Type: text/javascript; charset=utf-8");
	}
	
	public function pjActionLoadCancel()
	{
	    $this->setAjax(false);
	    $this->setLayout('pjActionFront');
	    ob_start();
	    header("Content-Type: text/javascript; charset=utf-8");
	}

	public function pjActionLoadCss()
	{
	    $this->setLayout('pjActionEmpty');
		$theme = $this->_get->toInt('theme') ? : (int) $this->option_arr['o_theme'];
		$arr = array();
		
		$arr[] = array('file' => 'bootstrap-datetimepicker.min.css', 'path' => PJ_LIBS_PATH . 'pjQ/bootstrap/css/');
		$arr[] = array('file' => 'jquery.fancybox-1.3.4.min.css', 'path' => PJ_LIBS_PATH . 'pjQ/fancybox/');

		$arr[] = array('file' => 'HotelBooking.css', 'path' => PJ_CSS_PATH);
		
		if ($theme > 0 && $theme <= 10)
		{
			$arr[] = array('file' => sprintf('theme%u.css', $theme), 'path' => PJ_CSS_PATH . 'themes/');
			$arr[] = array('file' => sprintf('theme%u.txt', $theme), 'path' => PJ_CSS_PATH . 'themes/');
		}
		
		header("Content-Type: text/css; charset=utf-8");
		foreach ($arr as $item)
		{
			ob_start();
			@readfile($item['path'] . $item['file']);
			$string = ob_get_contents();
			ob_end_clean();
			
			if ($string !== FALSE)
			{
				echo str_replace(
					array(
						'../fonts/fontawesome-',
						'images/ui-',
						"url('fancybox",
						"url('blank.gif",
						"src='fancybox/",
						"app/web/img/",
						"pjWrapper"
					),
					array(						
						PJ_THIRD_PARTY_PATH . 'font-awesome/fonts/fontawesome-',
						PJ_LIBS_PATH . 'pjQ/css/images/ui-',
						"url('" . PJ_LIBS_PATH . "pjQ/fancybox/fancybox",
						"url('" . PJ_LIBS_PATH . "pjQ/fancybox/blank.gif",
						"src='" . PJ_LIBS_PATH . "pjQ/fancybox/",
						PJ_INSTALL_URL . PJ_IMG_PATH,
						"pjWrapperHotelBooking_" . $theme
					),
					$string) . "\n";
			}
		}
		exit;
	}
	
	public function pjActionLocale()
	{
		$this->setAjax(true);
	
		if ($this->isXHR())
		{
			if ($this->_get->check('locale_id'))
			{
			    $this->pjActionSetLocale($this->_get->toInt('locale_id'));

				$this->loadSetFields(true);
				
				pjAppController::jsonResponse(array('status' => 'OK', 'code' => 200, 'text' => 'Locale have been changed.', 'opts' => array(
					'email_exiting_message' => pjSanitize::clean(__('front_existing_email', true))
				)));
			}
		}
		exit;
	}
	
	private function pjActionSetLocale($locale)
	{
		if ((int) $locale > 0)
		{
			$this->setLocaleId($locale);
		}
		return $this;
	}
	
	public function pjActionGetTerms()
	{
		$this->setAjax(true);
	
		if ($this->isXHR())
		{
		    if ($this->_get->check('cid') && $this->_get->toInt('cid') > 0)
			{
				$this->set('calendar_arr', pjCalendarModel::factory()
					->select('t1.*, t2.content AS terms_url, t3.content AS terms_body')
					->join('pjMultiLang', "t2.model='pjCalendar' AND t2.foreign_id=t1.id AND t2.field='terms_url' AND t2.locale='".$this->getLocaleId()."'", 'left outer')
					->join('pjMultiLang', "t3.model='pjCalendar' AND t3.foreign_id=t1.id AND t3.field='terms_body' AND t3.locale='".$this->getLocaleId()."'", 'left outer')
				    ->find($this->_get->toInt('cid'))
					->getData()
				);
			}
		}
	}

	public function pjActionGetRoom()
	{
		$this->setAjax(true);
	
		if ($this->isXHR())
		{
			if ($this->_get->toInt('room_id') > 0)
			{
			    $room_id = $this->_get->toInt('room_id');
			    if($this->session->has($this->defaultStore))
			    {
			        $STORE = $this->session->getData($this->defaultStore);
    				if (isset($STORE['date_from']) && !empty($STORE['date_from']))
    				{
    					$date_from = $STORE['date_from'];
    					$date_to = $STORE['date_to'];
    					$pjRoomModel = pjRoomModel::factory();
    					if (!$this->_get->check('cnt') || $this->_get->toInt('cnt') === 0)
    					{
    						$arr = $pjRoomModel
    							->select(sprintf("t1.*, t2.content AS `name`, t3.content AS `description`,
    								(SELECT `medium_path` FROM `%1\$s` WHERE `foreign_id` = `t1`.`id` ORDER BY `sort` ASC LIMIT 1) AS `image`,
    								(SELECT GROUP_CONCAT(COALESCE(`small_path`, '') SEPARATOR '~:~') FROM `%1\$s` WHERE `foreign_id` = `t1`.`id` GROUP BY `foreign_id` LIMIT 3) AS `gallery`,
    								(SELECT GROUP_CONCAT(COALESCE(`medium_path`, '') SEPARATOR '~:~') FROM `%1\$s` WHERE `foreign_id` = `t1`.`id` GROUP BY `foreign_id` LIMIT 3) AS `medium`,
    								(SELECT GROUP_CONCAT(COALESCE(`large_path`, '') SEPARATOR '~:~') FROM `%1\$s` WHERE `foreign_id` = `t1`.`id` GROUP BY `foreign_id` LIMIT 3) AS `large`,
    								(SELECT GROUP_CONCAT(COALESCE(`alt`, '') SEPARATOR '~:~') FROM `%1\$s` WHERE `foreign_id` = `t1`.`id` GROUP BY `foreign_id` LIMIT 3) AS `alt`,
    								(SELECT MIN(LEAST(`mon`, `tue`, `wed`, `thu`, `fri`, `sat`, `sun`)) FROM `%2\$s` AS `TP` WHERE `foreign_id` = `t1`.`id` AND ((`TP`.date_from <= '$date_to' ANd `TP`.date_to >= '$date_from') OR ( (`TP`.date_from IS NULL) OR (`TP`.date_to IS NULL) )) LIMIT 1) AS `price_from`
    								",
    								pjGalleryModel::factory()->getTable(),
    								pjPriceModel::factory()->getTable()
    							))
    							->join('pjMultiLang', "t2.model='pjRoom' AND t2.foreign_id=t1.id AND t2.field='name' AND t2.locale='".$this->getLocaleId()."'", 'left outer')
    							->join('pjMultiLang', "t3.model='pjRoom' AND t3.foreign_id=t1.id AND t3.field='description' AND t3.locale='".$this->getLocaleId()."'", 'left outer')
    							->find($room_id)
    							->toArray('gallery', '~:~')
    							->toArray('medium', '~:~')
    							->toArray('large', '~:~')
    							->toArray('alt', '~:~')
    							->getData();
    					} else {
    						$arr = $pjRoomModel
    							->select(sprintf("t1.*, t2.content AS `name`, t3.content AS `description`,								
    								(SELECT MIN(LEAST(`mon`, `tue`, `wed`, `thu`, `fri`, `sat`, `sun`)) FROM `%1\$s` AS `TP` WHERE `foreign_id` = `t1`.`id` AND ((`TP`.date_from <= '$date_to' ANd `TP`.date_to >= '$date_from') OR ( (`TP`.date_from IS NULL) OR (`TP`.date_to IS NULL) )) LIMIT 1) AS `price_from`
    								",
    								pjPriceModel::factory()->getTable()
    							))
    							->join('pjMultiLang', "t2.model='pjRoom' AND t2.foreign_id=t1.id AND t2.field='name' AND t2.locale='".$this->getLocaleId()."'", 'left outer')
    							->join('pjMultiLang', "t3.model='pjRoom' AND t3.foreign_id=t1.id AND t3.field='description' AND t3.locale='".$this->getLocaleId()."'", 'left outer')
    							->find($room_id)
    							->getData();
    					}
    					
    					# --
    					if (!empty($arr))
    					{
    						$pjBookingRoomModel = pjBookingRoomModel::factory();
    						$nightMode = $this->option_arr['o_price_based_on'] == "nights";
    						
    						if ($this->option_arr['o_allow_pending_time'] == 1) {
								$hours = $this->option_arr['o_pending_time'] / 60;
								$remainder = $this->option_arr['o_pending_time'] % 60;
								if ($remainder === 0)
								{
									$pending_time = sprintf("%u:00:00", $hours);
								} else {
									$pending_time = sprintf("%u:%u:00", $hours, $remainder);
								}
								$cond = "t2.status = 'pending' AND t2.created >= SUBTIME(NOW(), '".$pjBookingRoomModel->escapeStr($pending_time)."')";
							} else {
								$cond = "t2.status = 'pending'";
							}
    					
    						$tmp = $pjBookingRoomModel
    							->select('t1.*, t2.date_from, t2.date_to')
    							->join('pjBooking', sprintf("t2.id=t1.booking_id AND (t2.status = 'confirmed' OR (%5\$s)) AND t2.date_from %3\$s '%2\$s' AND t2.date_to %4\$s '%1\$s'",
    								$pjRoomModel->escapeStr($STORE['date_from']),
    								$pjRoomModel->escapeStr($STORE['date_to']),
    								$nightMode ? "<" : "<=",
    								$nightMode ? ">" : ">=",
    								$cond), 'inner')
    							->where('t1.room_id', $room_id)
    							->findAll()
    							->getData();
    							
    						$sum = array();
    						$dt_from = strtotime($STORE['date_from']);
    						$dt_to = strtotime($STORE['date_to']);
    						
    						$date_iso = $STORE['date_from'];
    						while ($date_iso <= $STORE['date_to'])
    						{
    						    $sum[$date_iso] = 0;
    						    $date_iso = date('Y-m-d', strtotime($date_iso . ' +1 day'));
    						}
						    foreach ($tmp as $value)
						    {
						        $from = strtotime($value["date_from"]);
						        $to = strtotime($value["date_to"]);
						        for ($z = $from; $z <= $to; $z += 86400)
						        {
						            if (($z >= $dt_from && $z < $dt_to) === FALSE)
						            {
						                continue;
						            }
						            $iso = date("Y-m-d", $z);
						            if ($z == $to && $nightMode)
						            {
						                continue;
						            }
						            $sum[$iso] += 1;
						        }
						    }
    						$arr['max_bookings'] = isset($sum) && !empty($sum) ? ceil(max($sum)) : 0;
    						
    						# Restrictions
    						$restrictions = pjRestrictionRoomModel::factory()
    							->select('t3.room_id, COUNT(t3.room_id) AS `cnt`')
    							->join('pjRestriction', "t2.id=t1.restriction_id", 'inner')
    							->join('pjRoomNumber', "t3.id=t1.room_number_id", 'inner')
    							->join('pjRoom', "t4.id=t3.room_id", 'inner')
    							->where(sprintf('t2.date_from %s', $nightMode ? "<" : "<="), $STORE['date_to'])
    							->where(sprintf('t2.date_to %s', $nightMode ? ">" : ">="), $STORE['date_from'])
    							->where('t3.room_id', $arr['id'])
    							->groupBy('t3.room_id')
    							->findAll()
    							->getDataPair('room_id', 'cnt');
    							# Restrictions
    						
    						$arr['unavailable_cnt'] = isset($restrictions[$arr['id']]) ? (int) $restrictions[$arr['id']] : 0;
    						$arr['real_price_from'] = $this->getRoomPrice(
    								$arr['id'],
    								$STORE['date_from'],
    								$STORE['date_to'],
    								($this->option_arr['o_price_based_on'] == 'nights'),
    								@$STORE['adults'],
    								@$STORE['children']
    						);
    					}
    					# --
    					
    					$this->set('room_arr', $arr);
    					
    					if (!isset($_SESSION[$this->defaultStore]))
    					{
    						$_SESSION[$this->defaultStore] = array();
    					}
    					if (!isset($_SESSION[$this->defaultStore]['rooms']))
    					{
    						$_SESSION[$this->defaultStore]['rooms'] = array();
    					}
    					if (!isset($_SESSION[$this->defaultStore]['rooms'][$room_id]))
    					{
    						$_SESSION[$this->defaultStore]['rooms'][$room_id] = array();
    					}
    	                $adults = @$this->_get->toInt('adults');
    	                $children = @$this->_get->toInt('children');
    					$price = $this->getRoomPrice(
    						$room_id,
    						$_SESSION[$this->defaultStore]['date_from'],
    						$_SESSION[$this->defaultStore]['date_to'],
    						($this->option_arr['o_price_based_on'] == 'nights'),
    					    $adults,
    					    $children
    					);
    					
    					for ($i = 1; $i <= @$this->_get->toInt('cnt'); $i++)
    					{
    						$_SESSION[$this->defaultStore]['rooms'][$room_id][$i] = array(
    							//'price' => $price
    							'price' => isset($_SESSION[$this->defaultStore]['content'][$room_id][$i]['raw_price']) ? $_SESSION[$this->defaultStore]['content'][$room_id][$i]['raw_price'] : $price
    						);
    					}
    					
    					if ($this->_get->check('cnt') && $this->_get->toInt('cnt') === 0 && $this->_get->check('adults') && $this->_get->check('children'))
    					{
    						if (isset($_SESSION[$this->defaultStore]['all_rooms']) && isset($_SESSION[$this->defaultStore]['all_rooms'][$room_id]))
    						{
    							$_SESSION[$this->defaultStore]['all_rooms'][$room_id] = NULL;
    							unset($_SESSION[$this->defaultStore]['all_rooms'][$room_id]);
    						}
    						if (isset($_SESSION[$this->defaultStore]['content']) && isset($_SESSION[$this->defaultStore]['content'][$room_id]))
    						{
    							$_SESSION[$this->defaultStore]['content'][$room_id] = NULL;
    							unset($_SESSION[$this->defaultStore]['content'][$room_id]);
    						}
    					}
    					
    					$limit_arr = array();
    					if (!empty($_SESSION[$this->defaultStore]['date_to']) && !empty($_SESSION[$this->defaultStore]['date_from']))
    					{
    						 $limit_arr = pjLimitModel::factory()
    							->where('t1.room_id', $room_id)
    						 	->where('t1.date_from <=', $_SESSION[$this->defaultStore]['date_to'])
    							->where('t1.date_to >=', $_SESSION[$this->defaultStore]['date_from'])
    							->findAll()
    							->getData();
    					}
    					$this->set('limit_arr', $limit_arr);
    				}else{
    					pjAppController::jsonResponse(array('status' => 'ERR', 'code' => 100, 'text' => ''));
    				}
			    }else{
			        pjAppController::jsonResponse(array('status' => 'ERR', 'code' => 100, 'text' => ''));
			    }
			}
		}
	}
	
	public function pjActionGetPrice()
	{
		$this->setAjax(true);
	
		if ($this->isXHR())
		{
		    $room_id = $this->_get->toInt('room_id');
			$total = 0;
			$room = $this->getRoomPrice(
			    $room_id,
				$_SESSION[$this->defaultStore]['date_from'],
				$_SESSION[$this->defaultStore]['date_to'],
				($this->option_arr['o_price_based_on'] == 'nights'),
			    $this->_get->toInt('adults'),
			    $this->_get->toInt('children')
			);
			foreach ($_SESSION[$this->defaultStore]['rooms'][$room_id] as $k => $v)
			{
			    if ($this->_get->toString('index') == $k)
				{
				    $_SESSION[$this->defaultStore]['rooms'][$room_id][$k]['price'] = $room;
					$total += $room;
				} else {
					$total += $v['price'];
				}
			}
			$format_total = pjCurrency::formatPrice($total);
			$format_room = pjCurrency::formatPrice($room);
			pjAppController::jsonResponse(compact('total', 'room', 'format_total', 'format_room'));
		}
		exit;
	}
	
	protected function pjActionAdultsChildren()
	{
		$adults = $children = 0;
		$cid = $this->_get->toInt('cid');
		if (isset($_SESSION[$this->defaultStore]) && isset($_SESSION[$this->defaultStore]['all_rooms']) &&
		    !empty($_SESSION[$this->defaultStore]['all_rooms']) && $this->pjActionCheckAvailability($cid))
		{
			foreach ($_SESSION[$this->defaultStore]['all_rooms'] as $room_id => $room_arr)
			{
				foreach ($room_arr as $index => $room_info)
				{
					$adults += $room_info['adults'];
					$children += $room_info['children'];
				}
			}
		}
		
		$text = str_replace(
			array(
				'{XA}',
				'{ADULTS}',
				'{XC}',
				'{CHILDREN}'
			),
			array(
				$adults,
				$adults != 1 ? pjMultibyte::strtolower(__('front_adults', true)) : pjMultibyte::strtolower(__('front_adult', true)),
				$children,
				$children != 1 ? pjMultibyte::strtolower(__('front_children', true)) : pjMultibyte::strtolower(__('front_child', true))
			),
			__('front_rooms_accommodate_text', true)
		);
		
		return compact('adults', 'children', 'text', 'cid');
	}
	
	protected function pjActionCheckAvailability($cid)
	{
	    $STORE =& $_SESSION[$this->defaultStore];
	    if (is_null($STORE) || empty($STORE) || !isset($STORE['date_from'], $STORE['date_to'], $STORE['guests'], $STORE['all_rooms']))
	    {
	        return FALSE;
	    }
     	$pjRoomModel = pjRoomModel::factory();
	    $nightMode = $this->option_arr['o_price_based_on'] == "nights";
		if ($this->option_arr['o_allow_pending_time'] == 1) {
			$hours = $this->option_arr['o_pending_time'] / 60;
			$remainder = $this->option_arr['o_pending_time'] % 60;
			if ($remainder === 0)
			{
				$pending_time = sprintf("%u:00:00", $hours);
			} else {
				$pending_time = sprintf("%u:%u:00", $hours, $remainder);
			}
			$cond = "`TB`.status = 'pending' AND `TB`.created >= SUBTIME(NOW(), '".$pjRoomModel->escapeStr($pending_time)."')";
		} else {
			$cond = "`TB`.status = 'pending'";
		}
	    
	    $arr = pjRoomModel::factory()
	    ->select(sprintf("t1.*,
				(SELECT COUNT(*)
					FROM `%1\$s` AS `TBR`
					INNER JOIN `%2\$s` AS `TB` ON
						`TB`.`id` = `TBR`.`booking_id` AND
						(`TB`.`status` = 'confirmed' OR (%7\$s)) AND
						`TB`.`date_from` %5\$s '%4\$s' AND
						`TB`.`date_to` %6\$s '%3\$s'
					WHERE `TBR`.`room_id` = `t1`.`id`
					LIMIT 1) AS `bookings`
				",
	        pjBookingRoomModel::factory()->getTable(),
	        pjBookingModel::factory()->getTable(),
	        $pjRoomModel->escapeStr($STORE['date_from']),
	        $pjRoomModel->escapeStr($STORE['date_to']),
	        $nightMode ? "<" : "<=",
	        $nightMode ? ">" : ">=",
	        $cond
	        ))
        ->where('t1.id > 0')
        ->where('t1.calendar_id', $cid)
        ->where('t1.max_people * t1.cnt >=', $STORE['guests'])
        ->findAll()
        ->getDataPair('id');
	        # --
	        
		if ($this->option_arr['o_allow_pending_time'] == 1) {
			$hours = $this->option_arr['o_pending_time'] / 60;
			$remainder = $this->option_arr['o_pending_time'] % 60;
			if ($remainder === 0)
			{
				$pending_time = sprintf("%u:00:00", $hours);
			} else {
				$pending_time = sprintf("%u:%u:00", $hours, $remainder);
			}
			$cond = "t2.status = 'pending' AND t2.created >= SUBTIME(NOW(), '".$pjRoomModel->escapeStr($pending_time)."')";
		} else {
			$cond = "t2.status = 'pending'";
		}
        $tmp = pjBookingRoomModel::factory()
        ->select('t1.*, t2.date_from, t2.date_to')
        ->join('pjBooking', sprintf("t2.id=t1.booking_id AND (t2.status = 'confirmed' OR (%5\$s)) AND t2.date_from %3\$s '%2\$s' AND t2.date_to %4\$s '%1\$s'",
            $pjRoomModel->escapeStr($STORE['date_from']),
            $pjRoomModel->escapeStr($STORE['date_to']),
            $nightMode ? "<" : "<=",
            $nightMode ? ">" : ">=",
            $cond), 'inner')
        ->findAll()
        ->getData();
        $sum = array();
        $init = array();
        $dt_from = strtotime($STORE['date_from']);
        $dt_to = strtotime($STORE['date_to']);
        for ($i = $dt_from; $i <= $dt_to; $i += 86400)
        {
            $init[date("Y-m-d", $i)] = 0;
        }
        
        foreach ($tmp as $value)
        {
            if (!isset($sum[$value["room_id"]]))
            {
                $sum[$value["room_id"]] = $init;
            }
            $from = strtotime($value["date_from"]);
            $to = strtotime($value["date_to"]);
            for ($z = $from; $z <= $to; $z += 86400)
            {
                if (($z >= $dt_from && $z < $dt_to) === FALSE)
                {
                    continue;
                }
                $iso = date("Y-m-d", $z);
                if ($z == $to && $nightMode)
                {
                    continue;
                }
                $sum[$value["room_id"]][$iso] += 1;
            }
        }
        
        foreach ($arr as $k => $room)
        {
            $arr[$k]['max_bookings'] = isset($sum[$room['id']]) && !empty($sum[$room['id']]) ? ceil(max($sum[$room['id']])) : 0;
        }
        # --
        
        foreach ($STORE['all_rooms'] as $room_id => $rooms)
        {
            if (!isset($arr[$room_id]) || $arr[$room_id]['cnt'] - $arr[$room_id]['max_bookings'] < count($rooms))
            {
                return FALSE;
            }
        }
        return TRUE;
	}
	
	public function pjActionSetPrice()
	{
		$this->setAjax(true);
	
		if ($this->isXHR())
		{
		    $room_id = $this->_post->toInt('room_id');
			if (!isset($_SESSION[$this->defaultStore]['all_rooms']))
			{
				$_SESSION[$this->defaultStore]['all_rooms'] = array();
			}
			$_SESSION[$this->defaultStore]['all_rooms'][$room_id] = array();
			$i = 1;
			if ($this->_post->check('adults'))
			{
			    $adults = $this->_post->toArray('adults');
			    $children = $this->_post->toArray('children');
			    foreach ($adults as $k => $v)
				{
				    $_SESSION[$this->defaultStore]['all_rooms'][$room_id][$i] = array(
					    'adults' => $adults[$k],
					    'children' => $children[$k]
					);
					$i++;
				}
			} else {
			    unset($_SESSION[$this->defaultStore]['all_rooms'][$room_id]);
			}
			# addition
			$content = isset($_SESSION[$this->defaultStore]['all_rooms'][$room_id]) ? $_SESSION[$this->defaultStore]['all_rooms'][$room_id] : array();
			if ($this->_post->check('adults'))
			{
			    $adults = $this->_post->toArray('adults');
			    $children = $this->_post->toArray('children');
				$i = 1;
				foreach ($adults as $k => $v)
				{
					$price = $this->getRoomPrice(
					    $room_id,
						$_SESSION[$this->defaultStore]['date_from'],
						$_SESSION[$this->defaultStore]['date_to'],
						($this->option_arr['o_price_based_on'] == 'nights'),
					    $adults[$k],
					    $children[$k]
					);
					$content[$i]['price'] = pjCurrency::formatPrice($price);
					$content[$i]['raw_price'] = $price;
					$i++;
				}
			}
			$_SESSION[$this->defaultStore]['content'][$room_id] = $content;
			
			$ac_arr = $this->pjActionAdultsChildren();

			pjAppController::jsonResponse(array('status' => 'OK', 'code' => 200, 'text' => '',
			    'id' => $room_id,
				'content' => $content,
				'persons' => $ac_arr['text']
			));
		}
		exit;
	}
	
	public function pjActionHandleExtras()
	{
		$this->setAjax(true);
	
		if ($this->isXHR())
		{
		    if (!$this->_post->check('extra_id') || !$this->_post->check('checked'))
			{
				pjAppController::jsonResponse(array('status' => 'ERR', 'code' => 100, 'text' => 'Missing parameters.'));
			}
			$extra_id = $this->_post->toInt('extra_id');
			if ($this->_post->toInt('checked') === 1)
			{
				// Add
				if (!isset($_SESSION[$this->defaultStore]))
				{
					$_SESSION[$this->defaultStore] = array();
				}
				if (!isset($_SESSION[$this->defaultStore]['extras']))
				{
					$_SESSION[$this->defaultStore]['extras'] = array();
				}
				if (!array_key_exists($extra_id, $_SESSION[$this->defaultStore]['extras']))
				{
					$arr = pjExtraModel::factory()
						->select('t1.*, t2.content AS `name`')
						->join('pjMultiLang', sprintf("t2.model='pjExtra' AND t2.foreign_id=t1.id AND t2.field='name' AND t2.locale='%u'", $this->getLocaleId()), 'left outer')
						->find($extra_id)->getData();
					if (!empty($arr))
					{
					    $_SESSION[$this->defaultStore]['extras'][$extra_id] = $arr;
						pjAppController::jsonResponse(array('status' => 'OK', 'code' => 200, 'text' => 'Extra has been added.'));
					}
				}
			} elseif ($this->_post->toInt('checked') === 0) {
				// Remove
				if (isset($_SESSION[$this->defaultStore]) && is_array($_SESSION[$this->defaultStore]) &&
					isset($_SESSION[$this->defaultStore]['extras']) && is_array($_SESSION[$this->defaultStore]['extras']) &&
				    array_key_exists($extra_id, $_SESSION[$this->defaultStore]['extras']))
				{
				    $_SESSION[$this->defaultStore]['extras'][$extra_id] = NULL;
				    unset($_SESSION[$this->defaultStore]['extras'][$extra_id]);
					pjAppController::jsonResponse(array('status' => 'OK', 'code' => 201, 'text' => 'Extra has been removed.'));
				}
			}
			
			pjAppController::jsonResponse(array('status' => 'ERR', 'code' => 101, 'text' => 'Error'));
		}
		exit;
	}

	public function pjActionApplyCode()
	{
		$this->setAjax(true);
		
		if ($this->isXHR())
		{
		    if (!$this->_post->check('code') || $this->_post->isEmpty('code'))
			{
				pjAppController::jsonResponse(array('status' => 'ERR', 'code' => 104, 'text' => __('system_104', true)));
			}
			
			$pre = array(
				'date_from' => $_SESSION[$this->defaultStore]['date_from'],
				'date_to' => $_SESSION[$this->defaultStore]['date_to']
			);
			$room_ids = array_keys($_SESSION[$this->defaultStore]['all_rooms']);
			$post = $this->_post->raw();
			$response = pjAppController::getDiscount(array_merge($post, $pre), $room_ids);
			if ($response['status'] == 'OK')
			{
				$intersect = array_intersect(array_keys($response['voucher_rooms']), $room_ids);
				if (empty($response['voucher_room']) || !empty($intersect))
				{
					$_SESSION[$this->defaultVoucher] = array(
						'voucher_code' => $response['voucher_code'],
						'voucher_rooms' => $response['voucher_rooms']
					);
				}
			}
			pjAppController::jsonResponse($response);
		}
		exit;
	}
	
	public function pjActionRemoveCode()
	{
		$this->setAjax(true);
		
		if ($this->isXHR())
		{
			if (isset($_SESSION[$this->defaultVoucher]) && !empty($_SESSION[$this->defaultVoucher]))
			{
				$_SESSION[$this->defaultVoucher] = NULL;
				unset($_SESSION[$this->defaultVoucher]);
			}
			pjAppController::jsonResponse(array('status' => 'OK', 'code' => 205, 'text' => __('system_205', true)));
		}
		exit;
	}
	
	public function pjActionGetAdultsChildren()
	{
		$this->setAjax(true);
	
		if ($this->isXHR())
		{
			pjAppController::jsonResponse($this->pjActionAdultsChildren());
		}
		exit;
	}

	public function pjActionProcessOrder()
	{
	    $this->setAjax(true);
	    
	    if ($this->isXHR())
	    {
	        if (!$this->_post->check('step_preview') || !isset($_SESSION[$this->defaultStore]) || empty($_SESSION[$this->defaultStore]))
	        {
	            pjAppController::jsonResponse(array('status' => 'ERR', 'code' => 104, 'text' => __('system_104', true)));
	        }
	        
	        $STORE = $_SESSION[$this->defaultStore];
	        if ((int) $this->option_arr['o_bf_captcha'] === 3 && $this->option_arr['o_captcha_type_front'] == 'system' && (!isset($STORE['form']) || !isset($STORE['form']['captcha']) || !pjCaptcha::validate(strtoupper($STORE['form']['captcha']), $_SESSION[$this->defaultCaptcha])))
	        {
	            pjAppController::jsonResponse(array('status' => 'ERR', 'code' => 105, 'text' => __('system_105', true)));
	        }
	        $_SESSION[$this->defaultCaptcha] = NULL;
	        unset($_SESSION[$this->defaultCaptcha]);
	        
	        $cid = $this->_get->toInt('cid');
	        if (!$this->pjActionCheckAvailability($cid))
	        {
	            pjAppController::jsonResponse(array('status' => 'ERR', 'code' => 108, 'text' => __('system_108', true)));
	        }
	        
	        $FORM = $STORE['form'];
	        
	        $data = array();
	        $data['date_from'] = $STORE['date_from'];
	        $data['date_to'] = $STORE['date_to'];
	        $data['calendar_id'] = $cid;
	        $data['uuid'] = pjUtil::uuid();
	        $data['status'] = $this->option_arr['o_status_if_not_paid'];
	        $data['ip'] = pjUtil::getClientIp();
	        $data['locale_id'] = $this->getLocaleId();
	        
	        if ((int) $this->option_arr['o_bf_arrival'] !== 1 && !empty($FORM['c_arrival']))
	        {
	            $iso_time = pjDateTime::formatTime($FORM['c_arrival'], $this->option_arr['o_time_format']);
	            $data['c_arrival'] = $iso_time;
	        }
	        
	        /* Client section */
	        $is_new_client = false;
	        $update_client = false;
	        $pjClientModel = pjClientModel::factory();
	        $data['client_id'] = ':NULL';
	        if($this->isFrontLogged())
	        {
	            $cnt = $pjClientModel->where('t1.foreign_id', $this->getClientId())->findCount()->getData();
	            if($cnt == 0)
	            {
	                $is_new_client = true;
	            }else{
	                $update_client = true;
	            }
	        }else{
	            $is_new_client = true;
	        }
	        if($is_new_client == true)
	        {
	            $client_by_email = pjFrontClient::init(array('email' => $FORM['c_email']))->getClientByEmail();
	            
	            if($client_by_email == false)
	            {
                    $clientData = $FORM;
    	            $clientData['status'] = 'T';
    	            $clientData['locale_id'] = $this->getLocaleId();
    	            $clientData['calendar_id'] = $this->getForeignId();
					if (!empty($clientData['c_notes'])) {
                        unset($clientData['c_notes']);
					}
    	            $response = pjFrontClient::init($clientData)->createClient();
    	            if(isset($response['client_id']) && (int) $response['client_id'] > 0)
    	            {
    	                $data['client_id'] = $response['client_id'];
    	            }
	            }else{
	                $update_client = true;
	            }
	        }else{
	            $client = $pjClientModel->reset()->where('foreign_id', $this->getClientId())->findAll()->getDataIndex(0);
	            $data['client_id'] = $client['id'];
	        }
	        if($update_client == true)
	        {
	            $c_data = array();
	            $auth_data = array();
	            if(isset($FORM['c_address']))
	            {
	                $c_data['c_address'] = $FORM['c_address'];
	            }
	            if(isset($FORM['c_country']))
	            {
	                $c_data['c_country'] = $FORM['c_country'];
	            }
	            if(isset($FORM['c_state']))
	            {
	                $c_data['c_state'] = $FORM['c_state'];
	            }
	            if(isset($FORM['c_city']))
	            {
	                $c_data['c_city'] = $FORM['c_city'];
	            }
	            if(isset($FORM['c_zip']))
	            {
	                $c_data['c_zip'] = $FORM['c_zip'];
	            }
	            if(isset($FORM['c_title']))
	            {
	                $c_data['c_title'] = $FORM['c_title'];
	            }
	            if(isset($FORM['c_company']))
	            {
	                $c_data['c_company'] = $FORM['c_company'];
	            }
	            if(isset($FORM['c_name']))
	            {
	                $auth_data['name'] = $FORM['c_name'];
	            }
	            if(isset($FORM['c_email']))
	            {
	                $auth_data['email'] = $FORM['c_email'];
	            }
	            if(isset($FORM['c_phone']))
	            {
	                $auth_data['phone'] = $FORM['c_phone'];
	            }
	            $foreign_id = $this->getClientId();
	            if(isset($client_by_email))
	            {
	                $foreign_id = $client_by_email['id'];
	            }
	            if(!empty($auth_data))
	            {
	                pjAuthUserModel::factory()->set('id', $foreign_id)->modify($auth_data);
	            }
	            $pjClientModel->reset()->where('foreign_id', $foreign_id)->limit(1)->modifyAll($c_data);
	            $client = $pjClientModel->reset()->where('foreign_id', $foreign_id)->findAll()->getDataIndex(0);
	            pjFrontClient::init(array('id' => $foreign_id))->setClientSession();
	            $data['client_id'] = $client['id'];
	        }
	        /* End client section */
	       
	        $data = array_merge($FORM, $data);
	        
	        $session_prices = $this->calPrices($STORE['all_rooms'], $STORE['date_from'], $STORE['date_to'], @$_SESSION[$this->defaultVoucher], isset($STORE['extras']) ? $STORE['extras'] : array(), $STORE['_nights'], $this->option_arr, 'front');
	        $data = array_merge($data, $session_prices);
	        
	        if (isset($_SESSION[$this->defaultVoucher], $_SESSION[$this->defaultVoucher]['voucher_code']))
	        {
	            $data['voucher'] = $_SESSION[$this->defaultVoucher]['voucher_code'];
	        }
	        
	        $pjBookingModel = pjBookingModel::factory();
	        if (!$pjBookingModel->validates($data))
	        {
	            pjAppController::jsonResponse(array('status' => 'ERR', 'code' => 106, 'text' => __('system_106', true)));
	        }
	        
	        $booking_id = $pjBookingModel->setAttributes($data)->insert()->getInsertId();
	        if ($booking_id === false || (int) $booking_id <= 0)
	        {
	            pjAppController::jsonResponse(array('status' => 'ERR', 'code' => 107, 'text' => __('system_107', true)));
	        }
	        
	        $pjRoomNumberModel = pjRoomNumberModel::factory();
	        $pjBookingRoomModel = pjBookingRoomModel::factory();
	        $pjRoomModel = pjRoomModel::factory();
	        $nightMode = $this->option_arr['o_price_based_on'] == "nights";
	        if ($nightMode)
	        {
	            $pjRoomModel->select(sprintf("t1.*, (SELECT GROUP_CONCAT(`TRN`.id SEPARATOR '~:~')
					FROM `%5\$s` AS `TRN`
					WHERE `TRN`.`room_id` = `t1`.`id` AND `TRN`.id NOT IN (SELECT `TBR`.`room_number_id`
					FROM `%1\$s` AS `TBR`
					INNER JOIN `%2\$s` AS `TB` ON
						`TB`.`id` = `TBR`.`booking_id` AND
						`TB`.`status` IN ('confirmed', 'pending') AND
						TB.date_from < '%4\$s' AND TB.date_to > '%3\$s'
					WHERE `TBR`.`room_id` = `t1`.`id`)) AS `room_number_ids`",
	                $pjBookingRoomModel->getTable(), $pjBookingModel->getTable(), $pjRoomModel->escapeStr($STORE['date_from']), $pjRoomModel->escapeStr($STORE['date_to']), $pjRoomNumberModel->getTable()));
	        } else {
	            $pjRoomModel->select(sprintf("t1.*, (SELECT GROUP_CONCAT(`TRN`.id SEPARATOR '~:~')
					FROM `%5\$s` AS `TRN`
					WHERE `TRN`.`room_id` = `t1`.`id` AND `TRN`.id NOT IN (SELECT `TBR`.`room_number_id`
					FROM `%1\$s` AS `TBR`
					INNER JOIN `%2\$s` AS `TB` ON
						`TB`.`id` = `TBR`.`booking_id` AND
						`TB`.`status` IN ('confirmed', 'pending') AND
						TB.date_from <= '%4\$s' AND TB.date_to >= '%3\$s'
					WHERE `TBR`.`room_id` = `t1`.`id`)) AS `room_number_ids`",
	                $pjBookingRoomModel->getTable(), $pjBookingModel->getTable(), $pjRoomModel->escapeStr($STORE['date_from']), $pjRoomModel->escapeStr($STORE['date_to']), $pjRoomNumberModel->getTable()));
	        }
	        $avail_room_number_arr = $pjRoomModel->whereIn('t1.id', array_keys($STORE['content']))->findAll()->toArray('room_number_ids', '~:~')->getDataPair('id');
	        
	        $restrictions = pjRestrictionRoomModel::factory()
	        ->select("t3.room_id, GROUP_CONCAT(`t3`.id SEPARATOR '~:~') AS `unavail_ids`")
	        ->join('pjRestriction', "t2.id=t1.restriction_id", 'inner')
	        ->join('pjRoomNumber', "t3.id=t1.room_number_id", 'inner')
	        ->join('pjRoom', "t4.id=t3.room_id", 'inner')
	        ->where(sprintf('t2.date_from %s', $nightMode ? "<" : "<="), $STORE['date_to'])
	        ->where(sprintf('t2.date_to %s', $nightMode ? ">" : ">="), $STORE['date_from'])
	        ->groupBy('t3.room_id')
	        ->findAll()
	        ->toArray('unavail_ids', '~:~')
	        ->getDataPair('room_id', 'unavail_ids');
	        
	        $pjBookingRoomModel->setBatchFields(array('booking_id', 'room_id', 'room_number_id', 'adults', 'children', 'price'));
	        foreach ($STORE['content'] as $room_id => $rooms_arr)
	        {
	            $_arr_diff = $avail_room_number_arr[$room_id]['room_number_ids'];
	            if(isset($restrictions[$room_id]) && count($restrictions[$room_id]) > 0)
	            {
	                $_arr_diff = array_diff($avail_room_number_arr[$room_id]['room_number_ids'], $restrictions[$room_id]);
	            }
	            $arr_diff = array_values($_arr_diff);
	            $i = 0;
	            foreach ($rooms_arr as $index => $room)
	            {
	                $pjBookingRoomModel->addBatchRow(array($booking_id, (int) $room_id, $arr_diff[$i], (int) $room['adults'], (int) $room['children'], (float) $room['raw_price']));
	                $i += 1;
	            }
	        }
	        $pjBookingRoomModel->insertBatch();
	        
	        if (isset($STORE['extras']) && is_array($STORE['extras']))
	        {
	            $pjBookingExtraModel = pjBookingExtraModel::factory()->setBatchFields(array('booking_id', 'extra_id', 'price'));
	            foreach ($STORE['extras'] as $extra)
	            {
	                $pjBookingExtraModel->addBatchRow(array($booking_id, $extra['id'], $extra['price']));
	            }
	            $pjBookingExtraModel->insertBatch();
	        }
	        
	        # Email --
	        $booking_arr = $pjBookingModel
	        ->reset()
	        ->select("t1.*, t2.content AS country, t4.name as c_name, t4.email as c_email, t4.phone as c_phone")
			->join('pjMultiLang', "t2.model='pjBaseCountry' AND t2.foreign_id=t1.c_country AND t2.locale=t1.locale_id AND t2.field='name'", 'left outer')
			->join('pjClient', "t3.id=t1.client_id", 'left outer')
			->join('pjAuthUser', "t4.id=t3.foreign_id", 'left outer')
			->find($booking_id)
			->getData();
			
			if (!empty($booking_arr))
			{
			    if (isset($pjBookingExtraModel))
			    {
			        $pjBookingExtraModel->reset();
			    } else {
			        $pjBookingExtraModel = pjBookingExtraModel::factory();
			    }
			    
			    $booking_arr['extras'] = $pjBookingExtraModel
			    ->select('t1.*, t2.content AS `name`')
			    ->join('pjMultiLang', "t2.model='pjExtra' AND t2.foreign_id=t1.extra_id AND t2.field='name' AND t2.locale='".$booking_arr['locale_id']."'", 'left join')
			    ->where('t1.booking_id', $booking_id)
			    ->findAll()
			    ->getData();
			    
			    $booking_arr['rooms'] = $pjBookingRoomModel
			    ->reset()
			    ->select('t1.*, (SELECT COUNT(*) FROM `'.$pjBookingRoomModel->getTable().'` WHERE `booking_id`=t1.booking_id) AS `cnt`, t2.content AS `name`')
			    ->join('pjMultiLang', "t2.model='pjRoom' AND t2.foreign_id=t1.room_id AND t2.field='name' AND t2.locale='".$booking_arr['locale_id']."'", 'left join')
			    ->where('t1.booking_id', $booking_id)
			    ->findAll()
			    ->getData();
			}
			pjFront::pjActionConfirmSend($this->option_arr, $booking_arr, 'confirmation', $this->getLocaleId());
			# Email ---
			
			$_SESSION[$this->defaultStore] = NULL;
			unset($_SESSION[$this->defaultStore]);
			
			$_SESSION[$this->defaultVoucher] = NULL;
			unset($_SESSION[$this->defaultVoucher]);
			
			pjAppController::jsonResponse(array(
			    'status' => 'OK',
			    'code' => 201,
			    'text' => __('system_201', true),
			    'booking_uuid' => $booking_arr['uuid']
			));
	    }
	    exit;
	}
	
	public static function pjActionConfirmSend($option_arr, $booking_arr, $opt, $locale)
	{
	    $Email = self::getMailer($option_arr);
	    
	    $pjMultiLangModel = pjMultiLangModel::factory();
	    $pjNotificationModel = pjNotificationModel::factory();
	    
	    $locale_id = isset($booking_arr['locale_id']) && (int) $booking_arr['locale_id'] > 0 ? (int) $booking_arr['locale_id'] : $locale;
	    $admin_email = pjAppController::getAdminEmail();
	    $admin_phone = pjAppController::getAdminPhone();
	    
	    $tokens = pjAppController::getTokens($booking_arr, $option_arr);
	   
	    $notification = $pjNotificationModel->reset()->where('recipient', 'client')->where('transport', 'email')->where('variant', $opt)->findAll()->getDataIndex(0);
	    if($notification && (int) $notification['id'] > 0 && $notification['is_active'] == 1)
	    {
	        $resp = pjFront::pjActionGetSubjectMessage($notification, $locale_id, $booking_arr['calendar_id']);
	        $lang_message = $resp['lang_message'];
	        $lang_subject = $resp['lang_subject'];
	        if (count($lang_message) === 1 && count($lang_subject) === 1 && !empty($lang_subject[0]['content']))
	        {
	            $subject = str_replace($tokens['search'], $tokens['replace'], $lang_subject[0]['content']);
	            $message = str_replace($tokens['search'], $tokens['replace'], $lang_message[0]['content']);
	            $Email
	            ->setTo($booking_arr['c_email'])
	            ->setSubject(stripslashes($subject))
	            ->send(pjUtil::textToHtml($message));
	        }
	    }
	    
	    $notification = $pjNotificationModel->reset()->where('recipient', 'admin')->where('transport', 'email')->where('variant', $opt)->findAll()->getDataIndex(0);
	    if($notification && (int) $notification['id'] > 0 && $notification['is_active'] == 1)
	    {
	        $resp = pjFront::pjActionGetSubjectMessage($notification, $locale_id, $booking_arr['calendar_id']);
	        $lang_message = $resp['lang_message'];
	        $lang_subject = $resp['lang_subject'];
	        if (count($lang_message) === 1 && count($lang_subject) === 1 && !empty($lang_subject[0]['content']))
	        {
	            $subject = str_replace($tokens['search'], $tokens['replace'], $lang_subject[0]['content']);
	            $message = str_replace($tokens['search'], $tokens['replace'], $lang_message[0]['content']);
	            
	            $Email
	            ->setTo($admin_email)
	            ->setSubject(stripslashes($subject))
	            ->send(pjUtil::textToHtml($message));
	        }
	    }
	    
	    /*SMS sent to client*/
	    if(!empty($booking_arr['c_phone']))
	    {
	        $notification = $pjNotificationModel->reset()->where('recipient', 'client')->where('transport', 'sms')->where('variant', $opt)->findAll()->getDataIndex(0);
	        if($notification && (int) $notification['id'] > 0 && $notification['is_active'] == 1)
	        {
	            $lang_message = $pjMultiLangModel
	            ->reset()
	            ->select('t1.*')
	            ->where('t1.foreign_id', $booking_arr['calendar_id'])
	            ->where('t1.model','pjCalendar')
	            ->where('t1.locale', $locale_id)
	            ->where('t1.field', 'confirmation_sms_tokens_client')
	            ->limit(0, 1)
	            ->findAll()
	            ->getData();
	            if (count($lang_message) === 1)
	            {
	                $message = str_replace($tokens['search'], $tokens['replace'], $lang_message[0]['content']);
	                $params = array(
	                    'text' => $message,
	                    'type' => 'unicode',
	                    'key' => md5($option_arr['private_key'] . PJ_SALT)
	                );
	                $params['number'] = $booking_arr['c_phone'];
	                pjBaseSms::init($params)->pjActionSend();
	            }
	        }
	    }
	    
		/*SMS sent to admin*/
	    if(!empty($admin_phone))
	    {
	        $notification = $pjNotificationModel->reset()->where('recipient', 'admin')->where('transport', 'sms')->where('variant', $opt)->findAll()->getDataIndex(0);
	        if($notification && (int) $notification['id'] > 0 && $notification['is_active'] == 1)
	        {
	            $lang_message = $pjMultiLangModel
	            ->reset()
	            ->select('t1.*')
	            ->where('t1.foreign_id', $booking_arr['calendar_id'])
	            ->where('t1.model','pjCalendar')
	            ->where('t1.locale', $locale_id)
	            ->where('t1.field', 'payment_sms_tokens_admin')
	            ->limit(0, 1)
	            ->findAll()
	            ->getData();
	            if (count($lang_message) === 1)
	            {
	                $message = str_replace($tokens['search'], $tokens['replace'], $lang_message[0]['content']);
	                $params = array(
	                    'text' => $message,
	                    'type' => 'unicode',
	                    'key' => md5($option_arr['private_key'] . PJ_SALT)
	                );
	                $params['number'] = $admin_phone;
	                pjBaseSms::init($params)->pjActionSend();
	            }
	        }
	    }
	}
	public static function pjActionGetSubjectMessage($notification, $locale_id, $calendar_id)
	{
	    $field = $notification['variant'] . '_tokens_' . $notification['recipient'];
	    $field = str_replace('confirmation', 'confirm', $field);
	    $pjMultiLangModel = pjMultiLangModel::factory();
	    $lang_message = $pjMultiLangModel
	    ->reset()
	    ->select('t1.*')
	    ->where('t1.foreign_id', $calendar_id)
	    ->where('t1.model','pjCalendar')
	    ->where('t1.locale', $locale_id)
	    ->where('t1.field', $field)
	    ->limit(0, 1)
	    ->findAll()
	    ->getData();
	    $field = $notification['variant'] . '_subject_' . $notification['recipient'];
	    $field = str_replace('confirmation', 'confirm', $field);
	    $lang_subject = $pjMultiLangModel
	    ->reset()
	    ->select('t1.*')
	    ->where('t1.foreign_id',  $calendar_id)
	    ->where('t1.model','pjCalendar')
	    ->where('t1.locale', $locale_id)
	    ->where('t1.field', $field)
	    ->limit(0, 1)
	    ->findAll()
	    ->getData();
	    return compact('lang_message', 'lang_subject');
	}
	
	public function pjActionConfirm()
	{
	    $this->setAjax(true);
	    
	    if (pjObject::getPlugin('pjPayments') === NULL)
	    {
	        $this->log('pjPayments plugin not installed');
	        exit;
	    }
	    
	    $pjPayments = new pjPayments();
	    $post = $this->_post->raw();
	    $get = $this->_get->raw();
	    $request = array();
	    if(isset($get['payment_method']))
	    {
	        $request = $get;
	    }
	    if(isset($post['payment_method']))
	    {
	        $request = $post;
	    }
	    if($pjPlugin = $pjPayments->getPaymentPlugin($request))
	    {
	        if($uuid = $this->requestAction(array('controller' => $pjPlugin, 'action' => 'pjActionGetCustom', 'params' => $request), array('return')))
	        {
	            $pjBookingModel= pjBookingModel::factory();
	            
	            $booking_arr = $pjBookingModel
	            ->select("t1.*, t2.content AS country")
				->join('pjMultiLang', "t2.model='pjBaseCountry' AND t2.foreign_id=t1.c_country AND t2.locale=t1.locale_id AND t2.field='name'", 'left outer')
				->where('uuid', $uuid)
				->limit(1)
				->findAll()->getDataIndex(0);
				
				if (!empty($booking_arr))
				{
				    $booking_id = $booking_arr['id'];
				    $locale_id = $this->getLocaleId();
				    if((int) $booking_arr['locale_id'] > 0)
			        {
			            $locale_id = $booking_arr['locale_id'];
			        }
			        
				    $pjBookingExtraModel = pjBookingExtraModel::factory();
				    $pjBookingRoomModel= pjBookingRoomModel::factory();
				    $booking_arr['extras'] = $pjBookingExtraModel
				    ->select('t1.*, t2.content AS `name`')
				    ->join('pjMultiLang', "t2.model='pjExtra' AND t2.foreign_id=t1.extra_id AND t2.field='name' AND t2.locale='".$locale_id."'", 'left join')
				    ->where('t1.booking_id', $booking_id)
				    ->findAll()
				    ->getData();
				    
				    $booking_arr['rooms'] = $pjBookingRoomModel
				    ->reset()
				    ->select('t1.*, (SELECT COUNT(*) FROM `'.$pjBookingRoomModel->getTable().'` WHERE `booking_id`=t1.booking_id) AS `cnt`, t2.content AS `name`')
				    ->join('pjMultiLang', "t2.model='pjRoom' AND t2.foreign_id=t1.room_id AND t2.field='name' AND t2.locale='".$locale_id."'", 'left join')
				    ->where('t1.booking_id', $booking_id)
				    ->findAll()
				    ->getData();
				    
				    $params = array(
				        'request'		=> $request,
				        'payment_method' => $request['payment_method'],
				        'foreign_id'	 => $booking_arr['calendar_id'],
				        'amount'		 => $booking_arr['deposit'],
				        'txn_id'		 => $booking_arr['txn_id'],
				        'order_id'	   => $booking_arr['id'],
				        'cancel_hash'	=> sha1($booking_arr['uuid'].strtotime($booking_arr['created']).PJ_SALT),
				        'key'			=> md5($this->option_arr['private_key'] . PJ_SALT)
				    );
				    $response = $this->requestAction(array('controller' => $pjPlugin, 'action' => 'pjActionConfirm', 'params' => $params), array('return'));
				    if($response['status'] == 'OK')
				    {
				        $this->log("Payments | {$pjPlugin} plugin<br>Order was confirmed. UUID: {$uuid}");
				        $pjBookingModel->reset()->set('id', $booking_arr['id'])->modify(array('status' => $this->option_arr['o_status_if_paid']));
				        pjFront::pjActionConfirmSend($this->option_arr, $booking_arr, 'payment', $locale_id);
				        echo $this->option_arr['o_thankyou_page'];
				        exit;
				    }elseif($response['status'] == 'CANCEL'){
				        $this->log("Payments | {$pjPlugin} plugin<br>Payment was cancelled. UUID: {$uuid}");
				        
				        $pjBookingModel->reset()->set('id', $booking_arr['id'])->modify(array('status' => 'cancelled', 'processed_on' => ':NOW()'));
				        pjFront::pjActionConfirmSend($this->option_arr, $booking_arr, 'cancel', $locale_id);
				        if(isset($response['return_url']) && !empty($response['return_url']))
				        {
				            echo $response['return_url'];
				        }else{
				            echo $this->option_arr['o_thankyou_page'];
				        }
				        exit;
				    }else{
				        $this->log("Payments | {$pjPlugin} plugin<br>Order confirmation was failed. UUID: {$uuid}");
				    }
				    
				    if(isset($response['redirect']) && $response['redirect'] == true)
				    {
				        echo $this->option_arr['o_thankyou_page'];
				        exit;
				    }
				} else {
					# Extra payments --
					$extra_payment = pjExtraPaymentModel::factory()
						->select('t1.id, t2.calendar_id')
						->join('pjBooking', 't2.id=t1.foreign_id', 'left outer')
						->where('t1.uuid', $uuid)
						->limit(1)
						->findAll()
						->getDataIndex(0);
					
					if ($extra_payment)
					{
						$request['foreign_id'] = $extra_payment['calendar_id'];
						$opts = array('http' => array(
							'method'  => 'POST',
							'header'  => 'Content-type: application/x-www-form-urlencoded',
							'follow_location' => 1,
							'content' => http_build_query($request)
						));
						$context = stream_context_create($opts);
						
						echo file_get_contents(PJ_INSTALL_URL."index.php?controller=pjExtraPayments&action=pjActionConfirm&cid=1", false, $context);
						exit;
						# Extra payments --
					} else {
				    	$this->log("Payments | {$pjPlugin} plugin<br>Booking with UUID {$uuid} not found.");
					}
				}
				echo $this->option_arr['o_thankyou_page'];
				exit;
	        }else{
	            $this->log("Payments | {$pjPlugin} plugin<br>Custom parameter not found.");
	        }
	    }
	    echo $this->option_arr['o_thankyou_page'];
	    exit;
	}
	
	
	static protected function setLastUsage($opts, $foreign_id)
	{
		if (is_array($opts)
			&& isset($opts['o_last_usage_time'])
			&& preg_match('/^\d{10}$/', $opts['o_last_usage_time'])
			&& date("Y-m-d") != date("Y-m-d", $opts['o_last_usage_time']))
		{
			# API ->
			$apiLogin = include dirname(dirname(PJ_INSTALL_PATH)) . '/login-api.php';
			if (is_object($apiLogin))
			{
				$apiLogin->setUsage();
			}
			# API <-
	
			# Update option
			pjOptionModel::factory()
				->where('foreign_id', $foreign_id)
				->where('`key`', 'o_last_usage_time')
				->limit(1)
				->modifyAll(array('value' => time()));
			return TRUE;
		}
		return FALSE;
	}
	
	public function isXHR()
	{
		// CORS
		return parent::isXHR() || isset($_SERVER['HTTP_ORIGIN']);
	}
	protected static function allowCORS()
	{
	    $install_url = parse_url(PJ_INSTALL_URL);
	    if($install_url['scheme'] == 'https'){
	        header('Set-Cookie: '.session_name().'='.session_id().'; SameSite=None; Secure');
	    }
	    $origin = isset($_SERVER['HTTP_ORIGIN']) ? $_SERVER['HTTP_ORIGIN'] : '*';
	    header('P3P: CP="ALL DSP COR CUR ADM TAI OUR IND COM NAV INT"');
	    header("Access-Control-Allow-Origin: $origin");
	    header("Access-Control-Allow-Credentials: true");
	    header("Access-Control-Allow-Methods: POST, GET, OPTIONS");
	    header("Access-Control-Allow-Headers: Origin, X-Requested-With");
	    if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS')
	    {
	        exit;
	    }
	}
}
?>