<?php
if (!defined("ROOT_PATH"))
{
	header("HTTP/1.1 403 Forbidden");
	exit;
}
class pjAdminBookings extends pjAdmin
{
	private function pjActionCheck($uuid, $id=NULL)
	{
		$pjBookingModel = pjBookingModel::factory();
		if (!is_null($id))
		{
			$pjBookingModel->where('t1.id!=', $id);
		}
		if (0 == $pjBookingModel->where('t1.uuid', $uuid)->findCount()->getData())
		{
			return TRUE;
		}
		return FALSE;
	}
	
	public function pjActionCheckUID()
	{
		$this->setAjax(true);
		if ($this->isXHR())
		{
			$get = $this->_get->raw();
			if (isset($get['uuid']) && pjValidation::pjActionNotEmpty($get['uuid']))
			{
				if (isset($get['id']) && (int) $get['id'] > 0)
				{
					echo ($this->pjActionCheck($get['uuid'], $get['id']) === TRUE) ? 'true' : 'false';
					exit;
				} else {
					echo ($this->pjActionCheck($get['uuid']) === TRUE) ? 'true' : 'false';
					exit;
				}
			}
			die('false');
		}
		exit;
	}

	public function pjActionIndex()
	{
	    $this->checkLogin();
	    if (!pjAuth::factory()->hasAccess())
	    {
	        $this->sendForbidden();
	        return;
	    }
		
		$this->set('room_arr', pjRoomModel::factory()
			->select('t1.*, t2.content AS name')
			->join('pjMultiLang', "t2.model='pjRoom' AND t2.foreign_id=t1.id AND t2.field='name' AND t2.locale='".$this->getLocaleId()."'", 'left outer')
			->where('t1.calendar_id', $this->getForeignId())
			->orderBy('`name` ASC')
			->findAll()
			->getData()
		);
		$this->set('date_format', pjUtil::toBootstrapDate($this->option_arr['o_date_format']));
			
		$this->appendCss('datepicker3.css', PJ_THIRD_PARTY_PATH . 'bootstrap_datepicker/');
		$this->appendJs('bootstrap-datepicker.js', PJ_THIRD_PARTY_PATH . 'bootstrap_datepicker/');		
		$this->appendJs('jquery.datagrid.js', PJ_FRAMEWORK_LIBS_PATH . 'pj/js/');
		$this->appendJs('pjAdminBookings.js');
	}
	
	public function pjActionGetBooking()
	{
		$this->checkLogin();
		$this->setAjax(true);
	
		if ($this->isXHR())
		{
			$pjBookingModel = pjBookingModel::factory()
			->join('pjClient', "t2.id=t1.client_id", 'left outer')
			->join('pjAuthUser', "t3.id=t2.foreign_id", 'left outer');
			
			if ($q = $this->_get->toString('q'))
			{
			    $q = str_replace(array('_', '%'), array('\_', '\%'), trim($q));
			    $pjBookingModel->where("(t3.name LIKE '%$q%' OR t3.email LIKE '%$q%' OR t3.phone LIKE '%$q%' OR t2.c_company LIKE '%$q%' OR t1.uuid LIKE '%$q%')");
			}
			if ($this->_get->toInt('client_id') > 0)
			{
			    $pjBookingModel->where('t1.client_id',$this->_get->toInt('client_id'));
			}
			if ($this->_get->toString('uuid'))
			{
				$uuid = $this->_get->toString('uuid');
				$pjBookingModel->where('t1.uuid LIKE', "%$uuid%");
			}
			if ($this->_get->toString('voucher'))
			{
			    $voucher = $this->_get->toString('voucher');
			    $pjBookingModel->where('t1.voucher LIKE', "%$voucher%");
			}
			if ($this->_get->toString('c_name'))
			{
			    $c_name = $this->_get->toString('c_name');
			    $pjBookingModel->where("(t3.name LIKE '%$c_name%')");
			}
			if ($this->_get->toString('c_email'))
			{
			    $c_email = $this->_get->toString('c_email');
			    $pjBookingModel->where('t3.email LIKE', "%$c_email%");
			}
			if ($this->_get->toString('status'))
			{
			    $status = $this->_get->toString('status');
			    if(in_array($status, array('confirmed', 'not_confirmed', 'cancelled', 'pending')))
			    {
			        $pjBookingModel->where('t1.status', $status);
			    }
			}
			if ($this->_get->toString('payment_method'))
			{
			    $payment_method = $this->_get->toString('payment_method');
			    $pjBookingModel->where('t1.payment_method', $payment_method);
			}
			if ($this->_get->toString('iso_date'))
			{
			    $iso_date = $this->_get->toString('iso_date');
			    if(preg_match('/^\d{4}-\d{2}-\d{2}$/', $iso_date))
			    {
			        $pjBookingModel->where(sprintf("'%s' BETWEEN t1.date_from AND t1.date_to", $iso_date));
			    }
			}
			if ($this->_get->toString('today'))
			{
			    $today = $this->_get->toString('today');
			    if(preg_match('/^\d{4}-\d{2}-\d{2}$/', $today))
			    {
			        $pjBookingModel->where(sprintf("'%s' BETWEEN t1.date_from AND t1.date_to", $today));
			    }
			}
			if ($this->_get->toString('date_from'))
			{
			    $date_from = $this->_get->toString('date_from');
			    $pjBookingModel->where('t1.date_from', pjDateTime::formatDate($date_from, $this->option_arr['o_date_format']));
			}
			if ($this->_get->toString('date_to'))
			{
			    $date_to = $this->_get->toString('date_to');
			    $pjBookingModel->where('t1.date_to', pjDateTime::formatDate($date_to, $this->option_arr['o_date_format']));
			}
			
			if ($this->_get->toString('arrival_from') && $this->_get->toString('arrival_to'))
			{
			    $arrival_from = $this->_get->toString('arrival_from');
			    $arrival_to = $this->_get->toString('arrival_to');
			    $pjBookingModel->where('t1.date_from <=', pjDateTime::formatDate($arrival_to, $this->option_arr['o_date_format']));
			    $pjBookingModel->where('t1.date_to >=', pjDateTime::formatDate($arrival_from, $this->option_arr['o_date_format']));
			}else{
			    if ($this->_get->toString('arrival_from'))
			    {
			        $arrival_from = $this->_get->toString('arrival_from');
			        $pjBookingModel->where('t1.date_from >=', pjDateTime::formatDate($arrival_from, $this->option_arr['o_date_format']));
			    }
			    if ($this->_get->toString('arrival_to'))
			    {
			        $arrival_to = $this->_get->toString('arrival_to');
			        $pjBookingModel->where('t1.date_to <=', pjDateTime::formatDate($arrival_to, $this->option_arr['o_date_format']));
			    }
			}
			if ($this->_get->toString('departure_from') && $this->_get->toString('departure_to'))
			{
			    $departure_from = $this->_get->toString('departure_from');
			    $departure_to = $this->_get->toString('departure_to');
			    $pjBookingModel->where('t1.date_from <=', pjDateTime::formatDate($departure_to, $this->option_arr['o_date_format']));
			    $pjBookingModel->where('t1.date_to >=', pjDateTime::formatDate($departure_from, $this->option_arr['o_date_format']));
			} else {
			    if ($this->_get->toString('departure_from'))
			    {
			        $departure_from = $this->_get->toString('departure_from');
			        $pjBookingModel->where('t1.date_from >=', pjDateTime::formatDate($departure_from, $this->option_arr['o_date_format']));
				}
				if ($this->_get->toString('departure_to'))
				{
				    $departure_to = $this->_get->toString('departure_to');
				    $pjBookingModel->where('t1.date_to <=', pjDateTime::formatDate($departure_to, $this->option_arr['o_date_format']));
				}
			}
			if ($this->_get->toFloat('total_from'))
			{
			    $pjBookingModel->where('t1.total >=', $this->_get->toFloat('total_from'));
			}
			if ($this->_get->toFloat('total_to'))
			{
			    $pjBookingModel->where('t1.total <=', $this->_get->toFloat('total_to'));
			}
			if ($this->_get->toString('created_from'))
			{
			    $pjBookingModel->where('t1.created >=', pjDateTime::formatDate($this->_get->toString('created_from'), $this->option_arr['o_date_format']));
			}
			if ($this->_get->toString('created_to'))
			{
			    $pjBookingModel->where('t1.created <=', pjDateTime::formatDate($this->_get->toString('created_to'), $this->option_arr['o_date_format']));
			}
			if ($this->_get->toInt('room_id'))
			{
			    $pjBookingModel->where(sprintf("t1.id IN (SELECT `booking_id` FROM `%s` WHERE `room_id` = '%u')", pjBookingRoomModel::factory()->getTable(), $this->_get->toInt('room_id')));
			}
			
			$column = 'created';
			$direction = 'DESC';
			$sort_str = "created DESC";
			if ($this->_get->toString('column') && in_array(strtoupper($this->_get->toString('direction')), array('ASC', 'DESC')))
			{
			    $column = $this->_get->toString('column');
			    $direction = strtoupper($this->_get->toString('direction'));
			    $sort_str = "$column $direction";
			    if($this->_get->toString('column') == 'stay')
			    {
			        $sort_str = "date_from $direction";
			    }
			}

			$total = $pjBookingModel->findCount()->getData();
			$rowCount = $this->_get->toInt('rowCount') ?: 10;
			$pages = ceil($total / $rowCount);
			$page = $this->_get->toInt('page') ?: 1;
			$offset = ((int) $page - 1) * $rowCount;
			if ($page > $pages)
			{
				$page = $pages;
			}

			$pjBookingModel
			->select("t1.id, t1.client_id, t1.uuid, t1.created, t1.date_from, t1.date_to, t3.name as c_name, t3.email as c_email, t1.status")
			->orderBy($sort_str)->limit($rowCount, $offset)->findAll();
				
			$data = $pjBookingModel->getData();
			
			$ids = $pjBookingModel->getDataPair(null, 'id');
			if (!empty($ids))
			{
				$br_arr = pjBookingRoomModel::factory()
					->select("t1.booking_id, COUNT(t1.id) AS `cnt`, t2.content AS name, GROUP_CONCAT(t3.number SEPARATOR ', ') AS `room_number`")
					->join('pjMultiLang', "t2.model='pjRoom' AND t2.foreign_id=t1.room_id AND t2.field='name' AND t2.locale='".$this->getLocaleId()."'", 'left outer')
					->join('pjRoomNumber', 't3.id=t1.room_number_id', 'left outer')
					->whereIn('t1.booking_id', $ids)
					->groupBy('t1.id, t1.booking_id, t1.room_id, t2.content')
					->findAll()
					->getData();
				foreach ($data as $k => $v)
				{
					$created = strtotime($v['created']);
					
					$data[$k]['created'] = date($this->option_arr['o_date_format'] . ', ' . $this->option_arr['o_time_format'], $created);
					$data[$k]['rooms'] = array();
					foreach ($br_arr as $bk => $bv)
					{
						if ($v['id'] == $bv['booking_id'])
						{
							$bv['name'] = pjSanitize::clean($bv['name']);
							$bv['room_number'] = pjSanitize::clean($bv['room_number']);
							$data[$k]['rooms'][] = $bv;
						}
					}
					$client_arr = array();
					if(!empty($v['c_name']))
					{
						$client_arr[] = pjSanitize::clean($v['c_name']);
					}
					if(!empty($v['c_email']))
					{
					    if(pjAuth::factory('pjAdminClients', 'pjActionUpdate')->hasAccess())
					    {
					        $client_arr[] = '<a href="'.$_SERVER['PHP_SELF'].'?controller=pjAdminClients&amp;action=pjActionUpdate&id='.$v['client_id'].'">' . pjSanitize::clean($v['c_email']) . '</a>';
					    }else{
					        $client_arr[] = pjSanitize::clean($v['c_email']);
					    }
					}
					$data[$k]['c_email'] = implode("<br/>", $client_arr);
					$data[$k]['stay'] = date($this->option_arr['o_date_format'], strtotime($v['date_from'])) . ' - ' . date($this->option_arr['o_date_format'], strtotime($v['date_to']));
				}
			}
				
			pjAppController::jsonResponse(compact('data', 'total', 'pages', 'page', 'rowCount', 'column', 'direction'));
		}
		exit;
	}
	
	public function pjActionCreate()
	{
	    $this->checkLogin();
	    if (!pjAuth::factory()->hasAccess())
	    {
	        $this->sendForbidden();
	        return;
	    }
		if ($this->_post->check('booking_create'))
		{
			$post = $this->_post->raw();
			if (!$this->pjActionCheck($post['uuid']))
			{
				pjUtil::redirect(PJ_INSTALL_URL . "index.php?controller=pjAdminBookings&action=pjActionIndex&err=ABK17");
			}

			$data = array();
			$data['locale_id'] = $this->getLocaleId();
			$data['calendar_id'] = $this->getForeignId();
			$data['date_from'] = pjDateTime::formatDate($this->_post->toString('date_from'), $this->option_arr['o_date_format']);
			$data['date_to'] = pjDateTime::formatDate($this->_post->toString('date_to'), $this->option_arr['o_date_format']);
			$data['c_arrival'] = sprintf("%s:%s:00", $this->_post->toString('hour'), $this->_post->toString('minute'));
			$data['c_departure'] = sprintf("%s:%s:00", $this->_post->toString('d_hour'), $this->_post->toString('d_minute'));
			
			# Check room availability
			$pjBookingRoomModel = pjBookingRoomModel::factory();
			$pjBookingRoomTempModel = pjBookingRoomTempModel::factory();
			
			$nightMode = $this->option_arr['o_price_based_on'] == "nights";
			if ($nightMode)
			{
				$condition = sprintf(" AND b.date_from < '%s' AND b.date_to > '%s' ", $data['date_to'], $data['date_from']);
			} else {
				$condition = sprintf(" AND b.date_from <= '%s' AND b.date_to >= '%s' ", $data['date_to'], $data['date_from']);
			}
			
			$tmp_arr = $pjBookingRoomTempModel
				->select(sprintf("t1.room_id, COUNT(*) AS `current_booking_cnt`, t2.cnt AS `total_cnt`,
					(SELECT COUNT(*)
					FROM `%1\$s` AS `br`
					INNER JOIN `%2\$s` AS `b` ON b.id = br.booking_id
						AND b.status = 'confirmed'
						%3\$s
					WHERE br.room_id = t1.room_id
					LIMIT 1) AS `other_booking_cnt`
				", $pjBookingRoomModel->getTable(), pjBookingModel::factory()->getTable(), $condition))
				->join('pjRoom', 't1.room_id=t2.id', 'inner')
				->where('t1.hash', $this->_post->toString('hash'))
				->where('t1.booking_id IS NULL')
				->groupBy('t1.room_id, t1.hash, t2.cnt')
				->findAll()
				->getData();
			
			# Check room availability
			
			$date_from = $data['date_from'];
			$date_to = $data['date_to'];
			$pjRoomModel = pjRoomModel::factory();
			# --
			$tmp = pjBookingRoomModel::factory()
				->select('t1.*, t2.date_from, t2.date_to')
				->join('pjBooking', sprintf("t2.id=t1.booking_id AND (t2.status = 'confirmed' OR (t2.status = 'pending' AND t2.created >= SUBTIME(NOW(), '01:00:00'))) AND t2.date_from %3\$s '%2\$s' AND t2.date_to %4\$s '%1\$s'",
				$pjRoomModel->escapeStr($date_from),
				$pjRoomModel->escapeStr($date_to),
				$nightMode ? "<" : "<=",
				$nightMode ? ">" : ">="), 'inner')
				->findAll()
				->getData();
				
			$sum = array();
			$init = array();
			$dt_from = strtotime($date_from);
			$dt_to = strtotime($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 ($tmp_arr as $item)
			{
				$max_bookings = isset($sum[$item['room_id']]) && !empty($sum[$item['room_id']]) ? ceil(max($sum[$item['room_id']])) : 0;
				if ($max_bookings > (int) $item['total_cnt'])
				{
					$pjBookingRoomTempModel
						->reset()
						->where('`hash`', $this->_post->toString('hash'))
						->where('`booking_id` IS NULL')
						->eraseAll();
						
					pjUtil::redirect($_SERVER['PHP_SELF'] . '?controller=pjAdminBookings&action=pjActionIndex&err=ABK10');
					break;
				}
			}
			unset($tmp_arr);
			# Check room availability			
			if($this->_post->check('new_client'))
			{
			    $c_data = array();
			    $c_data['c_title'] = !$this->_post->isEmpty('c_title') ? $this->_post->toString('c_title') : ':NULL';
			    $c_data['c_name'] = !$this->_post->isEmpty('c_name') ? $this->_post->toString('c_name') : ':NULL';
			    $c_data['c_email'] = !$this->_post->isEmpty('c_email') ? $this->_post->toString('c_email') : ':NULL';
			    $c_data['c_phone'] = !$this->_post->isEmpty('c_phone') ? $this->_post->toString('c_phone') : ':NULL';
			    $c_data['c_company'] = !$this->_post->isEmpty('c_company') ? $this->_post->toString('c_company') : ':NULL';
			    $c_data['c_address'] = !$this->_post->isEmpty('c_address') ? $this->_post->toString('c_address') : ':NULL';
			    $c_data['c_city'] = !$this->_post->isEmpty('c_city') ? $this->_post->toString('c_city') : ':NULL';
			    $c_data['c_state'] = !$this->_post->isEmpty('c_state') ? $this->_post->toString('c_state') : ':NULL';
			    $c_data['c_zip'] = !$this->_post->isEmpty('c_zip') ? $this->_post->toString('c_zip') : ':NULL';
			    $c_data['c_country'] = $this->_post->toInt('c_country');
			    $c_data['status'] = 'T';
			    $c_data['locale_id'] = $this->getLocaleId();
			    $c_data['calendar_id'] = $this->getForeignId();
			    $response = pjFrontClient::init($c_data)->createClient();
			    if(isset($response['client_id']) && (int) $response['client_id'] > 0)
			    {
			        $data['client_id'] = $response['client_id'];
			    }
			}
			
			$id = pjBookingModel::factory(array_merge($post, $data))->insert()->getInsertId();
			if ($id !== false && (int) $id > 0)
			{
				$err = 'ABK03';
				if ($this->_post->check('i18n'))
				{
				    pjMultiLangModel::factory()->saveMultiLang($post['i18n'], $id, 'pjBooking');
				}
				
				$statement = sprintf("INSERT INTO `%s` (`booking_id`, `room_id`, `room_number_id`, `adults`, `children`, `price`)
					SELECT :booking_id, `room_id`, `room_number_id`, `adults`, `children`, `price` FROM `%s` WHERE `booking_id` IS NULL AND `hash` = :hash",
					$pjBookingRoomModel->getTable(), $pjBookingRoomTempModel->getTable()
				);
				$pjBookingRoomModel->reset()->prepare($statement)->exec(array('booking_id' => $id, 'hash' => $this->_post->toString('hash')));
					
				$pjBookingRoomTempModel
					->reset()
					->where('`hash`', $this->_post->toString('hash'))
					->where('`booking_id` IS NULL')
					->eraseAll();
					
				if ($this->_post->check('extra_id'))
				{
					$pjBookingExtraModel = pjBookingExtraModel::factory();
					foreach ($post['extra_id'] as $extra_id => $extra)
					{
						list(, $price) = explode("|", $extra);
						$pjBookingExtraModel->addBatchRow(array($id, $extra_id, $price));
					}
					$pjBookingExtraModel
						->setBatchFields(array('booking_id', 'extra_id', 'price'))
						->insertBatch();
				}
				
			} else {
				$err = 'ABK04';
			}
			pjUtil::redirect($_SERVER['PHP_SELF'] . "?controller=pjAdminBookings&action=pjActionIndex&err=$err");
		} else {
			$this
				->set('country_arr', pjBaseCountryModel::factory()
					->select('t1.id, t2.content AS name')
					->join('pjMultiLang', "t2.model='pjBaseCountry' AND t2.foreign_id=t1.id AND t2.field='name' AND t2.locale='".$this->getLocaleId()."'", 'left outer')
					->where('t1.status', 'T')
					->orderBy('`name` ASC')->findAll()->getData()
				)
				->set('extra_arr', pjExtraModel::factory()
					->select('t1.*, t2.content AS name')
					->join('pjMultiLang', "t2.model='pjExtra' AND t2.foreign_id=t1.id AND t2.field='name' AND t2.locale='".$this->getLocaleId()."'", 'left outer')
					->where('t1.calendar_id', $this->getForeignId())
					->orderBy('`name` ASC')
					->findAll()
					->getData()
				);
				
			$this->set('date_format', pjUtil::toBootstrapDate($this->option_arr['o_date_format']));
			$this->set('uuid', pjUtil::uuid());
			
			$client_arr = pjClientModel::factory()
			->select("t1.*, t2.email as c_email, t2.name as c_name, t2.phone as c_phone")
			->join("pjAuthUser", "t2.id=t1.foreign_id", 'left outer')
			->where('t2.status', 'T')
			->orderBy('t2.name ASC')
			->findAll()
			->getData();
			$this->set('client_arr', pjSanitize::clean($client_arr));
			
			if(pjObject::getPlugin('pjPayments') !== NULL)
			{
			    $this->set('payment_option_arr', pjPaymentOptionModel::factory()->getOptions($this->getForeignId()));
			    $this->set('payment_titles', pjPayments::getPaymentTitles($this->getForeignId(), $this->getLocaleId()));
			}else{
			    $this->set('payment_titles', __('payment_methods', true));
			}
			
			$this->appendCss('css/select2.min.css', PJ_THIRD_PARTY_PATH . 'select2/');
			$this->appendJs('js/select2.full.min.js', PJ_THIRD_PARTY_PATH . 'select2/');
			$this->appendCss('datepicker3.css', PJ_THIRD_PARTY_PATH . 'bootstrap_datepicker/');
			$this->appendJs('bootstrap-datepicker.js', PJ_THIRD_PARTY_PATH . 'bootstrap_datepicker/');		
			$this->appendJs('pjAdminBookings.js');
		}
	}
	
	public function pjActionGetBookingRooms()
	{
		$this->checkLogin();
		$this->setAjax(true);
	
		if ($this->isXHR())
		{
			$is_bid = $this->_get->toInt('booking_id') > 0;
			$is_hash = $this->_get->toString('hash');
			if ($is_bid || $is_hash)
			{
				$pjBookingRoomTempModel = pjBookingRoomTempModel::factory();
				if ($is_bid)
				{
				    $pjBookingRoomTempModel->where('t1.booking_id', $this->_get->toInt('booking_id') );
				} elseif ($is_hash)	{
				    $pjBookingRoomTempModel->where('t1.hash', $this->_get->toString('hash'));
				}
				$arr = $pjBookingRoomTempModel
					->select('t1.*, t2.content AS name, t3.number')
					->join('pjMultiLang', "t2.model='pjRoom' AND t2.foreign_id=t1.room_id AND t2.field='name' AND t2.locale='".$this->getLocaleId()."'", 'left outer')
					->join('pjRoomNumber', 't3.id=t1.room_number_id', 'left outer')
					->orderBy("`name` ASC")->findAll()->getData();
				
				$this->set('arr', $arr);
			}
		}
	}
	
	public function pjActionAddBookingRoom() {
		$this->checkLogin();
		$this->setAjax(true);
	
		if ($this->isXHR())
		{
			$pjBookingRoomTempModel = pjBookingRoomTempModel::factory();
			
			if ($this->_get->check('add_room'))
			{
			    if ($this->_post->toInt('add_room_id') > 0 && $this->_post->toInt('add_adults') > 0 && $this->_post->toInt('add_room_number_id') > 0)
			    {
			        $date_from = pjDateTime::formatDate($this->_post->toString('date_from'), $this->option_arr['o_date_format']);
			        $date_to = pjDateTime::formatDate($this->_post->toString('date_to'), $this->option_arr['o_date_format']);
			        if ($this->_post->toInt('booking_room_id') > 0) 
			        {
			            $pjBookingRoomTempModel->set('id', $this->_post->toInt('booking_room_id'))->erase();
					}
					$data = array();
					$data['room_id'] = $this->_post->toInt('add_room_id');
					$data['adults'] = $this->_post->toInt('add_adults');
					$data['children'] = $this->_post->toInt('add_children');
					$data['room_number_id'] = $this->_post->toInt('add_room_number_id');
					$data['booking_id'] = $this->_post->toInt('id') ?: ":NULL";
					$data['hash'] = $this->_post->toString('hash') ?: ":NULL";
					$data['price'] = $this->getRoomPrice($data['room_id'], $date_from, $date_to, ($this->option_arr['o_price_based_on'] == 'nights'), $data['adults'], $data['children']);
					
					$insert_id = $pjBookingRoomTempModel->reset()->setAttributes($data)->insert()->getInsertId();
					if ($insert_id !== false && (int) $insert_id > 0)
					{
						pjAppController::jsonResponse(array('status' => 'OK', 'code' => 200, 'text' => ''));
					}
					pjAppController::jsonResponse(array('status' => 'ERR', 'code' => 100, 'text' => ''));
				} else {
					pjAppController::jsonResponse(array('status' => 'ERR', 'code' => 100, 'text' => ''));
				}
			}
			
			$nightMode = $this->option_arr['o_price_based_on'] == "nights";
			$condition1 = $condition2 = $condition3 = NULL;
			if ($this->_get->toInt('booking_id') > 0)
			{
			    $condition1 = sprintf(" AND `booking_id` = '%u'", $this->_get->toInt('booking_id') );
			    $condition3 = sprintf(" AND br.booking_id != '%u'", $this->_get->toInt('booking_id') );
			} elseif ($this->_get->toString('hash')) {
			    $hash = $this->_get->toString('hash');
			    if(!empty($hash))
			    {
    			    $condition1 = sprintf(" AND `hash` = '%s'", $this->_get->toString('hash'));
    				$condition3 = " AND `booking_id` IS NOT NULL";
			    }
			}
			
			$pjRoomModel = pjRoomModel::factory();
			
			$isDateCorrect = $this->_get->check('date_from') && $this->_get->check('date_to') && !$this->_get->isEmpty('date_from') && !$this->_get->isEmpty('date_to');
			if ($isDateCorrect)
			{
			    $date_from = pjDateTime::formatDate($this->_get->toString('date_from'), $this->option_arr['o_date_format']);
			    $date_to = pjDateTime::formatDate($this->_get->toString('date_to'), $this->option_arr['o_date_format']);
				
				if ($nightMode)
				{
					$condition2 = sprintf(" AND b.date_from < '%s' AND b.date_to > '%s' ", $date_to, $date_from);
				} else {
					$condition2 = sprintf(" AND b.date_from <= '%s' AND b.date_to >= '%s' ", $date_to, $date_from);
				}
			} else {
				$pjRoomModel->where('t1.id', -99);
				$this->set('dates_not_set', 1);
			}
			
			$room_arr = $pjRoomModel
				->select(sprintf("t1.*, t2.content AS name,
					(SELECT COUNT(*)
						FROM `%6\$s` AS `br`
						INNER JOIN `%2\$s` AS `b` ON b.id = br.booking_id
							AND b.status = 'confirmed'
							%4\$s
						WHERE br.room_id = t1.id
						%5\$s
						LIMIT 1) AS `other_booking_cnt`,
					(SELECT COUNT(*)
						FROM `%1\$s`
						WHERE `room_id` = t1.id
						%3\$s
						LIMIT 1) AS `current_booking_cnt`",
					$pjBookingRoomTempModel->getTable(), pjBookingModel::factory()->getTable(), $condition1, $condition2, $condition3, pjBookingRoomModel::factory()->getTable()))
				->join('pjMultiLang', "t2.model='pjRoom' AND t2.foreign_id=t1.id AND t2.field='name' AND t2.locale='".$this->getLocaleId()."'", 'left outer')
				->where('t1.calendar_id', $this->getForeignId())
				->orderBy('`name` ASC')
				->findAll()
				->getData();
			# --
			$sum = array();
			if ($isDateCorrect)
			{
				$tmp = pjBookingRoomModel::factory()
					->select('t1.*, t2.date_from, t2.date_to')
					->join('pjBooking', sprintf("t2.id=t1.booking_id AND (t2.status = 'confirmed' OR (t2.status = 'pending' AND t2.created >= SUBTIME(NOW(), '01:00:00'))) AND t2.date_from %3\$s '%2\$s' AND t2.date_to %4\$s '%1\$s'",
						$pjRoomModel->escapeStr($date_from),
						$pjRoomModel->escapeStr($date_to),
						$nightMode ? "<" : "<=",
						$nightMode ? ">" : ">="), 'inner')
					->findAll()
					->getData();
				
				if (!empty($tmp))
				{
					$init = array();
					$dt_from = strtotime($date_from);
					$dt_to = strtotime($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($room_arr as $k => $room)
			{
				$room_arr[$k]['max_bookings'] = isset($sum[$room['id']]) && !empty($sum[$room['id']]) ? ceil(max($sum[$room['id']])) : 0;
			}
				
			$this->set('room_arr', $room_arr);
			$this->set('cnt_rooms', $pjRoomModel->reset()->findCount()->getData());
			
			if ($this->_get->toInt('booking_room_id') > 0) {
			    $br_arr = $pjBookingRoomTempModel->find($this->_get->toInt('booking_room_id'))->getData();
				$this->set('br_arr', $br_arr);
				$this->set('room_number_arr', $this->getRoomNumbers($br_arr['room_id'], $this->_get->toString('date_from'), $this->_get->toString('date_to'), @$this->_get->toInt('booking_id'), @$this->_get->toString('hash'), $this->_get->toInt('booking_room_id')));
			} else {
			    if ($this->_get->toInt('room_id') > 0 && $isDateCorrect)
				{
				    $this->set('room_number_arr', $this->getRoomNumbers($this->_get->toInt('room_id'), $this->_get->toString('date_from'), $this->_get->toString('date_to'), @$this->_get->toInt('booking_id'), @$this->_get->toString('hash')));
				}
			}
		}
	}
	
	private function getRoomNumbers($room_id, $date_from, $date_to, $booking_id, $hash, $booking_room_id=0)
	{
		$date_from = pjDateTime::formatDate($date_from, $this->option_arr['o_date_format']);
		$date_to = pjDateTime::formatDate($date_to, $this->option_arr['o_date_format']);
		
		$pjRoomNumberModel = pjRoomNumberModel::factory();
		
		$rr_arr = pjRestrictionRoomModel::factory()
			->select('t1.room_number_id')
			->join('pjRestriction', "t2.id=t1.restriction_id AND t2.restriction_type != 'web'", 'inner')
			->where('t2.date_from <=', $date_to)
			->where('t2.date_to >=', $date_from)
			->findAll()
			->getDataPair(null, 'room_number_id');
		if (!empty($rr_arr))
		{
			$pjRoomNumberModel->whereNotIn('t1.id', $rr_arr);
		}
	
		$is_bid = (int) $booking_id > 0;
		$is_hash = !empty($hash);
		
		$room_number_id_arr = array();
		if ($is_bid || $is_hash || (int)$booking_room_id > 0)
		{
			$pjBookingRoomTempModel = pjBookingRoomTempModel::factory();
			if ($is_bid)
			{
			    $nightMode = $this->option_arr['o_price_based_on'] == "nights";
			   
			    $pjBookingRoomTempModel->join('pjBooking', sprintf("t2.id=t1.booking_id AND t2.date_from %3\$s '%2\$s' AND t2.date_to %4\$s '%1\$s'", $pjBookingRoomTempModel->escapeStr($date_from), $pjBookingRoomTempModel->escapeStr($date_to), $nightMode ? "<" : "<=",$nightMode ? ">" : ">="), 'inner');
				
				$pjBookingRoomTempModel->where('t1.booking_id <>', $booking_id)->where('t2.status', 'confirmed');
			} elseif ($is_hash)	{
				$pjBookingRoomTempModel->where('t1.hash', $hash);
			}
			if ((int)$booking_room_id > 0) {
				$pjBookingRoomTempModel->where('t1.id <>', $booking_room_id);
			}
			$room_number_id_arr = $pjBookingRoomTempModel->findAll()->getDataPair('id', 'room_number_id');
		}
		
		if (!empty($room_number_id_arr))
		{
			$pjRoomNumberModel->whereNotIn('t1.id', $room_number_id_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'";
		}
		if ($is_bid)
		{
		    $pjBookingRoomModel->where('t1.booking_id <>', $booking_id);
		}
		$booking_rooms = $pjBookingRoomModel
		->join('pjBooking', sprintf("t2.id=t1.booking_id AND (t2.status = 'confirmed'".  ($is_bid ? " OR t2.id='".$booking_id."'" : NULL) ." OR (%5\$s)) AND t2.date_from %3\$s '%2\$s' AND t2.date_to %4\$s '%1\$s'",
				$pjBookingRoomModel->escapeStr($date_from),
				$pjBookingRoomModel->escapeStr($date_to),
				$nightMode ? "<" : "<=",
				$nightMode ? ">" : ">=",
				$cond), 'inner')
		->findAll()
		->getDataPair(null, 'room_number_id');
		
		if (!empty($booking_rooms))
		{
			$pjRoomNumberModel->whereNotIn('t1.id', $booking_rooms);
		} 
		
		return $pjRoomNumberModel->where('t1.room_id', $room_id)->orderBy('t1.id ASC')->findAll()->getData();
	}
	
	public function pjActionGetRoomNumbers()
	{
		$this->checkLogin();
		$this->setAjax(true);
		
		if ($this->isXHR())
		{
			if ($this->_get->check('room_id'))
			{
				$room_number_arr = $this->getRoomNumbers($this->_get->toInt('room_id'), $this->_get->toString('date_from'), $this->_get->toString('date_to'), @$this->_get->toInt('booking_id'), @$this->_get->toString('hash'), @$this->_get->toInt('booking_room_id'));
				$this->set('room_number_arr', $room_number_arr);
				if ($this->_get->toInt('booking_room_id') > 0) 
				{
				    $br_arr = pjBookingRoomTempModel::factory()->find($this->_get->toInt('booking_room_id'))->getData();
					$this->set('br_arr', $br_arr);
				}
			}
		}
	}
	
	public function pjActionRecalcPrice()
	{
		$this->checkLogin();
		$this->setAjax(true);
	
		if ($this->isXHR())
		{
		    $post = $this->_post->raw();
		    pjAppController::jsonResponse($this->getPrice($post));
		}
		exit;
	}
	
	private function getPrice($data)
	{
		if (!isset($data['date_from']) || !isset($data['date_to']) || empty($data['date_from']) || empty($data['date_to']))
		{
			return array('status' => 'ERR', 'code' => 100, 'text' => 'Not enough data.');
		}
			
		$room_price = $extra_price = $total = $security = $tax = $deposit = $discount = 0;
			
		$date_from = pjDateTime::formatDate($data['date_from'], $this->option_arr['o_date_format']);
		$date_to = pjDateTime::formatDate($data['date_to'], $this->option_arr['o_date_format']);
		
		$dateFrom = new DateTime($date_from);
		$dateTo = new DateTime($date_to);
		$_nights= $dateTo->diff($dateFrom)->format("%a");
		
		if ($this->option_arr['o_price_based_on'] == 'days')
		{
			$_nights += 1;
		}			
		$pjBookingRoomTempModel = pjBookingRoomTempModel::factory();
		if (isset($data['id']) && (int) $data['id'] > 0)
		{
			$pjBookingRoomTempModel->where('t1.booking_id', $data['id']);
		} elseif (isset($data['hash']) && !empty($data['hash'])) {
			$pjBookingRoomTempModel->where('t1.hash', $data['hash']);
		}
		$pjBookingRoomTempModel->findAll();
			
		$room_ids = $pjBookingRoomTempModel->getDataPair(null, 'room_id');
		$room_ids = array_unique($room_ids);
			
		if (empty($room_ids))
		{
			return array('status' => 'OK', 'code' => 201, 'text' => 'Rooms no found. All the prices equals to zero.', 'data' => 
				compact('total', 'tax', 'security', 'deposit', 'room_price', 'extra_price', 'discount'));
			//return array('status' => 'ERR', 'code' => 101, 'text' => 'No rooms found.');
		}
			
		$voucher_arr = array();
		if (!empty($data['voucher']))
		{
			$code = $data['voucher'];
			$response = $this->getDiscount(compact('date_from', 'date_to', 'code'), $room_ids);
			if ($response['status'] == 'OK')
			{
				$intersect = array_intersect(array_keys($response['voucher_rooms']), $room_ids);
				if (empty($response['voucher_room']) || !empty($intersect))
				{
					$voucher_arr = array(
						'voucher_code' => $response['voucher_code'],
						'voucher_rooms' => $response['voucher_rooms']
					);
				}
			}
		}
			
		$booking_rooms = $pjBookingRoomTempModel->getData();
		$session_prices = $this->calPrices($booking_rooms, $date_from, $date_to, $voucher_arr, $data, $_nights, $this->option_arr, 'back');
			
		return array('status' => 'OK', 'code' => 200, 'text' => 'Booking price has been retrieved.', 'data' =>$session_prices);
	}
	
	public function pjActionDeleteBooking()
	{
		$this->setAjax(true);

		if (!pjAuth::factory()->hasAccess())
		{
		    self::jsonResponse(array('status' => 'ERR', 'code' => 103, 'text' => 'Access denied.'));
		}
		
		if (!$this->isXHR())
		{
		    self::jsonResponse(array('status' => 'ERR', 'code' => 100, 'text' => 'Missing headers.'));
		}
		
		if (!self::isGet() && !$this->_get->check('id') && $this->_get->toInt('id') < 0)
		{
		    self::jsonResponse(array('status' => 'ERR', 'code' => 101, 'text' => 'HTTP method not allowed.'));
		}
		
		if ($this->_get->toInt('id') > 0)
		{
		    $id = $this->_get->toInt('id');
		    if (pjBookingModel::factory()->set('id', $id)->erase()->getAffectedRows() == 1)
		    {
		        pjBookingExtraModel::factory()->where('booking_id', $id)->eraseAll();
		        pjBookingRoomModel::factory()->where('booking_id', $id)->eraseAll();
		        pjBookingRoomTempModel::factory()->where('booking_id', $id)->eraseAll();
		        pjMultiLangModel::factory()->where('model', 'pjBooking')->where('foreign_id', $id)->eraseAll();
		        
		        pjAppController::jsonResponse(array('status' => 'OK', 'code' => 200, 'text' => 'Booking has been deleted.'));
		    } else {
		        pjAppController::jsonResponse(array('status' => 'ERR', 'code' => 100, 'text' => 'Booking has not been deleted.'));
		    }
		}
		pjAppController::jsonResponse(array('status' => 'ERR', 'code' => 101, 'text' => 'Missing or empty parameters.'));
		
		exit;
	}
	
	public function pjActionDeleteBookingBulk()
	{
		$this->setAjax(true);
		
		if (!pjAuth::factory()->hasAccess())
		{
		    self::jsonResponse(array('status' => 'ERR', 'code' => 103, 'text' => 'Access denied.'));
		}
		if (!$this->isXHR())
		{
		    self::jsonResponse(array('status' => 'ERR', 'code' => 100, 'text' => 'Missing headers.'));
		}
		
		if (!self::isPost())
		{
		    self::jsonResponse(array('status' => 'ERR', 'code' => 101, 'text' => 'HTTP method not allowed.'));
		}
	
		$record = $this->_post->toArray('record');
		if (!empty($record))
		{
		    pjBookingModel::factory()->whereIn('id', $record)->limit(count($record))->eraseAll();
		    pjBookingExtraModel::factory()->whereIn('booking_id', $record)->eraseAll();
		    pjBookingRoomModel::factory()->whereIn('booking_id', $record)->eraseAll();
		    pjBookingRoomTempModel::factory()->whereIn('booking_id', $record)->eraseAll();
		    pjMultiLangModel::factory()->where('model', 'pjBooking')->whereIn('foreign_id', $record)->eraseAll();
		    
		    self::jsonResponse(array('status' => 'OK', 'code' => 200, 'text' => 'Booking(s) has been deleted.'));
		}
		self::jsonResponse(array('status' => 'ERR', 'code' => 100, 'text' => 'Missing or empty parameters.'));
		
		exit;
	}
	
	public function pjActionDeleteBookingRoom()
	{
		$this->setAjax(true);
		
		if (!pjAuth::factory('pjAdminBookings', 'pjActionCreate')->hasAccess() || !pjAuth::factory('pjAdminBookings', 'pjActionUpdate')->hasAccess())
		{
		    self::jsonResponse(array('status' => 'ERR', 'code' => 103, 'text' => 'Access denied.'));
		}
		if (!$this->isXHR())
		{
		    self::jsonResponse(array('status' => 'ERR', 'code' => 100, 'text' => 'Missing headers.'));
		}
		
		if (!self::isPost())
		{
		    self::jsonResponse(array('status' => 'ERR', 'code' => 101, 'text' => 'HTTP method not allowed.'));
		}
		if ($this->_post->toInt('id') > 0)
		{
		    if (pjBookingRoomTempModel::factory()->set('id', $this->_post->toInt('id'))->erase()->getAffectedRows() == 1)
		    {
		        pjAppController::jsonResponse(array('status' => 'OK', 'code' => 200, 'text' => ''));
		    }
		}
		pjAppController::jsonResponse(array('status' => 'ERR', 'code' => 100, 'text' => ''));
		exit;
	}
	
	public function pjActionUpdate()
	{
	    $this->checkLogin();
	    if (!pjAuth::factory()->hasAccess())
	    {
	        $this->sendForbidden();
	        return;
	    }
		$pjBookingModel = pjBookingModel::factory();
		if (isset($_REQUEST['id']) && (int) $_REQUEST['id'] > 0)
		{
			$pjBookingModel->where('t1.id', $_REQUEST['id']);
		} elseif ($this->_get->check('uuid') && !$this->_get->isEmpty('uuid')) {
		    $pjBookingModel->where('t1.uuid', $this->_get->toString('uuid'));
		}
		$arr = $pjBookingModel
			->limit(1)
			->findAll()
			->getData();
			
		if (empty($arr))
		{
			pjUtil::redirect($_SERVER['PHP_SELF'] . "?controller=pjAdminBookings&action=pjActionIndex&err=ABK08");
		}
		$arr = $arr[0];
		
		if ($this->_post->check('booking_update'))
		{
			$post = $this->_post->raw();
			if (!$this->pjActionCheck($post['uuid'], $post['id']))
			{
				pjUtil::redirect(PJ_INSTALL_URL . "index.php?controller=pjAdminBookings&action=pjActionUpdate&id=".$post['id']."&err=ABK18");
			}

		    $new_client_id = NULL;
		    if($this->_post->check('new_client'))
		    {
		        $c_data = array();
		        $c_data['c_title'] = $this->_post->toString('c_title');
		        $c_data['c_name'] = $this->_post->toString('c_name');
		        $c_data['c_email'] = $this->_post->toString('c_email');
		        $c_data['c_phone'] = $this->_post->toString('c_phone');
		        $c_data['c_company'] = $this->_post->toString('c_company');
		        $c_data['c_address'] = $this->_post->toString('c_address');
		        $c_data['c_city'] = $this->_post->toString('c_city');
		        $c_data['c_state'] = $this->_post->toString('c_state');
		        $c_data['c_zip'] = $this->_post->toString('c_zip');
		        $c_data['c_country'] = $this->_post->toInt('c_country');
		        $c_data['status'] = 'T';
		        $c_data['locale_id'] = $this->getLocaleId();
		        $c_data['calendar_id'] = $this->getForeignId();
		        $response = pjFrontClient::init($c_data)->createClient();
		        if(isset($response['client_id']) && (int) $response['client_id'] > 0)
		        {
		            $new_client_id = $response['client_id'];
		        }
		    }else{
		        $new_client_id = $this->_post->toInt('client_id');
		    }
		    
			$data = array();
			$data['client_id'] = $new_client_id;
			$data['date_from'] = pjDateTime::formatDate($this->_post->toString('date_from'), $this->option_arr['o_date_format']);
			$data['date_to'] = pjDateTime::formatDate($this->_post->toString('date_to'), $this->option_arr['o_date_format']);
			$data['c_arrival'] = sprintf("%s:%s:00", $this->_post->toString('hour'), $this->_post->toString('minute'));
			$data['c_departure'] = sprintf("%s:%s:00", $this->_post->toString('d_hour'), $this->_post->toString('d_minute'));
			
			# Check room availability
			$pjBookingRoomTempModel = pjBookingRoomTempModel::factory();
			$pjBookingRoomModel = pjBookingRoomModel::factory();
			$nightMode = $this->option_arr['o_price_based_on'] == "nights";
			if ($nightMode)
			{
				$condition = sprintf(" AND b.date_from < '%s' AND b.date_to > '%s' ", $data['date_to'], $data['date_from']);
			} else {
				$condition = sprintf(" AND b.date_from <= '%s' AND b.date_to >= '%s' ", $data['date_to'], $data['date_from']);
			}
			
			$tmp_arr = $pjBookingRoomTempModel
				->select(sprintf("t1.room_id, t1.room_number_id, COUNT(*) AS `current_booking_cnt`, t2.cnt AS `total_cnt`,
					(SELECT COUNT(*)
					FROM `%1\$s` AS `br`
					INNER JOIN `%2\$s` AS `b` ON b.id = br.booking_id
						AND b.status = 'confirmed'
						%4\$s
					WHERE br.room_id = t1.room_id
					AND br.booking_id != '%3\$u'
					LIMIT 1) AS `other_booking_cnt`
				", $pjBookingRoomModel->getTable(), pjBookingModel::factory()->getTable(), $arr['id'], $condition))
				->join('pjRoom', 't1.room_id=t2.id', 'inner')
				->where('t1.booking_id', $arr['id'])
				->where('t1.hash IS NULL')
				->groupBy('t1.room_id, t1.room_number_id, t1.hash, t2.cnt')
				->findAll()
				->getData();
            
			$isValid = true;
			
			foreach ($tmp_arr as $item)
			{
			    $room_number_arr = $this->getRoomNumbers($item['room_id'], $this->_post->toString('date_from'), $this->_post->toString('date_to'), $post['id'], NULL, $item['room_number_id']);
			    
			    $found = false;
			    foreach($room_number_arr as $rn)
			    {
			        if($item['room_number_id'] == $rn['id'])
			        {
			            $found = true;
			            break;
			        }
			    }
			    if ($found == false)
			    {
			        $isValid = false;
			        break;
			    }
			    
			}
			unset($tmp_arr);
			if (!$isValid)
			{
				$pjBookingRoomTempModel->reset()->where('booking_id', $arr['id'])->eraseAll();
				pjUtil::redirect($_SERVER['PHP_SELF'] . '?controller=pjAdminBookings&action=pjActionIndex&err=ABK10');
			}
			# Check room availability
			
			# Temp
			$pjBookingRoomModel->where('booking_id', $arr['id'])->eraseAll();
			
			$statement = sprintf("INSERT INTO `%s` (`booking_id`, `room_id`, `room_number_id`, `adults`, `children`, `price`)
				SELECT `booking_id`, `room_id`, `room_number_id`, `adults`, `children`, `price` FROM `%s` WHERE `booking_id` = :booking_id",
				$pjBookingRoomModel->getTable(), $pjBookingRoomTempModel->getTable()
			);
			$pjBookingRoomModel->reset()->prepare($statement)->exec(array('booking_id' => $arr['id']));
			$pjBookingRoomTempModel->reset()->where('booking_id', $arr['id'])->eraseAll();
			# Temp
			$pjBookingModel->reset()->set('id', $arr['id'])->modify(array_merge($post, $data));
			pjUtil::redirect(sprintf(
                "%s?controller=pjAdminBookings&action=pjActionUpdate&id=%u&err=ABK01",
                $_SERVER['PHP_SELF'],
                $arr['id']
            ));
			if (isset($post['i18n']))
			{
			    pjMultiLangModel::factory()->updateMultiLang($post['i18n'], $arr['id'], 'pjBooking');
			}
			
			$pjBookingExtraModel = pjBookingExtraModel::factory();
			$pjBookingExtraModel->where('booking_id', $arr['id'])->eraseAll()->reset();
			if (isset($post['extra_id']) && !empty($post['extra_id']))
			{
			    foreach ($post['extra_id'] as $extra_id => $extra)
				{
					list(, $price) = explode("|", $extra);
					$pjBookingExtraModel->addBatchRow(array($arr['id'], $extra_id, $price));
				}
				$pjBookingExtraModel
					->setBatchFields(array('booking_id', 'extra_id', 'price'))
					->insertBatch();
			}
			
			pjUtil::redirect(sprintf("%s?controller=pjAdminBookings&action=pjActionUpdate&id=%u&err=ABK01", $_SERVER['PHP_SELF'], $arr['id']));
			
		} else {
			$arr['i18n'] = pjMultiLangModel::factory()->getMultiLang($arr['id'], 'pjBooking');
			
			$pjBookingRoomTempModel = pjBookingRoomTempModel::factory();
			# Temp 1. Delete rooms from tmp
			$pjBookingRoomTempModel->where('booking_id', $arr['id'])->eraseAll();
			# Temp 2. Copy rooms to tmp
			$statement = sprintf("INSERT INTO `%s` (`booking_id`, `room_id`, `room_number_id`, `adults`, `children`, `price`)
				SELECT `booking_id`, `room_id`, `room_number_id`, `adults`, `children`, `price` FROM `%s` WHERE `booking_id` = :booking_id",
				$pjBookingRoomTempModel->getTable(),
				pjBookingRoomModel::factory()->getTable()
			);
			$pjBookingRoomTempModel->reset()->prepare($statement)->exec(array('booking_id' => $arr['id']));
			$this
				->set('arr', $arr)
				->set('country_arr', pjBaseCountryModel::factory()
					->select('t1.id, t2.content AS name')
					->join('pjMultiLang', "t2.model='pjBaseCountry' AND t2.foreign_id=t1.id AND t2.field='name' AND t2.locale='".$this->getLocaleId()."'", 'left outer')
					->orderBy('`name` ASC')->findAll()->getData()
				)
				->set('extra_arr', pjExtraModel::factory()
					->select('t1.*, t2.content AS name')
					->join('pjMultiLang', "t2.model='pjExtra' AND t2.foreign_id=t1.id AND t2.field='name' AND t2.locale='".$this->getLocaleId()."'", 'left outer')
					->where('t1.calendar_id', $this->getForeignId())
					->orderBy('`name` ASC')
					->findAll()
					->getData()
				)
				->set('be_arr', pjBookingExtraModel::factory()->where('t1.booking_id', $arr['id'])->findAll()->getDataPair('extra_id', 'price'));
				
			$this->set('date_format', pjUtil::toBootstrapDate($this->option_arr['o_date_format']));
			
			$client_arr = pjClientModel::factory()
			->select("t1.*, t2.email as c_email, t2.name as c_name, t2.phone as c_phone")
			->join("pjAuthUser", "t2.id=t1.foreign_id", 'left outer')
			->orderBy('t2.name ASC')
			->findAll()
			->getData();
			$this->set('client_arr',$client_arr);
			
			if(pjObject::getPlugin('pjPayments') !== NULL)
			{
			    $this->set('payment_option_arr', pjPaymentOptionModel::factory()->getOptions($this->getForeignId()));
			    $this->set('payment_titles', pjPayments::getPaymentTitles($this->getForeignId(), $this->getLocaleId()));
			}else{
			    $this->set('payment_titles', __('payment_methods', true));
			}
			
			$this->appendJs('tinymce.min.js', PJ_THIRD_PARTY_PATH . 'tinymce/');
			$this->appendCss('css/select2.min.css', PJ_THIRD_PARTY_PATH . 'select2/');
			$this->appendJs('js/select2.full.min.js', PJ_THIRD_PARTY_PATH . 'select2/');
			$this->appendCss('datepicker3.css', PJ_THIRD_PARTY_PATH . 'bootstrap_datepicker/');
			$this->appendJs('bootstrap-datepicker.js', PJ_THIRD_PARTY_PATH . 'bootstrap_datepicker/');
			$this->appendJs('pjExtraPayments.js', pjObject::getConstant('pjExtraPayments', 'PLUGIN_JS_PATH'));
			$this->appendJs('pjAdminBookings.js');
		}
	}
	
	public function pjActionExportBooking()
	{
	    $this->checkLogin();
	    if (!pjAuth::factory('pjAdminBookings', 'pjActionExportBooking')->hasAccess())
	    {
	        $this->sendForbidden();
	        return;
	    }
		$record = $this->_post->toArray('record');
		if (!empty($record))
		{
		    $arr = pjBookingModel::factory()->whereIn('id', $record)->findAll()->getData();
		    foreach($arr as $k => $v)
		    {
		        unset($v['ip']);
		        $arr[$k] = $v;
		    }
			$csv = new pjCSV();
			$csv
				->setHeader(true)
				->setName("Bookings-".time().".csv")
				->process($arr)
				->download();
		}
		exit;
	}
	
	public function pjActionUpdateBookingRoom()
	{
	    $this->setAjax(true);
	    
	    if ($this->_post->check('room_update'))
	    {
	        $post = $this->_post->raw();
	        
	        $room_price = $this->getRoomPrice(
			    $this->_post->toInt('room_id'),
				pjDateTime::formatDate($this->_post->toString('date_from'), $this->option_arr['o_date_format']),
				pjDateTime::formatDate($this->_post->toString('date_to'), $this->option_arr['o_date_format']),
				($this->option_arr['o_price_based_on'] == 'nights'),
			    $this->_post->toInt('adults'),
			    $this->_post->toInt('children')
			);
			$post['price'] = $room_price;
	        if (pjBookingRoomTempModel::factory()->set('id', $this->_post->toInt('id'))->modify($post)->getAffectedRows() == 1)
	        {
	            pjAppController::jsonResponse(array('status' => 'OK', 'code' => 200, 'text' => '', 'hash' => @$post['hash']));
	        }
	        pjAppController::jsonResponse(array('status' => 'ERR', 'code' => 100, 'text' => ''));
	    }
	    
	    $arr = pjBookingRoomTempModel::factory()
	    ->select('t1.*, t2.adults AS max_adults, t2.children AS max_children, t3.content AS `name`')
	    ->join('pjRoom', 't1.room_id=t2.id', 'left outer')
	    ->join('pjMultiLang', "t3.model='pjRoom' AND t3.foreign_id=t1.room_id AND t3.field='name' AND t3.locale='".$this->getLocaleId()."'", 'left outer')
	    ->find($this->_get->toInt('id'))->getData();
	    $this->set('arr', $arr);
	    
	    $room_number_arr = $this->getRoomNumbers($arr['room_id'], $this->_get->toString('date_from'), $this->_get->toString('date_to'), @$this->_get->toInt('booking_id'), @$this->_get->toString('hash'), 0);
	    $this->set('room_number_arr', $room_number_arr);
	}
	
	public function pjActionConfirmation()
	{
	    $this->setAjax(true);
	    
	    if ($this->isXHR())
	    {
	        if (self::isPost())
	        {
	            if($this->_post->toInt('send_email') && $this->_post->toString('to') && $this->_post->toString('subject') && $this->_post->toString('message') && $this->_post->toInt('id'))
	            {
	                $Email = self::getMailer($this->option_arr);
	                $r = $Email
	                ->setTo($this->_post->toString('to'))
	                ->setSubject($this->_post->toString('subject'))
	                ->send($this->_post->toString('message'));
	                if (isset($r) && $r)
	                {
	                    pjAppController::jsonResponse(array('status' => 'OK', 'code' => 200, 'text' => ''));
	                }
	                pjAppController::jsonResponse(array('status' => 'ERR', 'code' => 100, 'text' => ''));
	            }
	        }
	        if (self::isGet())
	        {
	            if($booking_id = $this->_get->toInt('booking_id'))
	            {
	                $pjBookingModel = pjBookingModel::factory();
	                $pjBookingRoomModel = pjBookingRoomModel::factory();
	                $pjNotificationModel = pjNotificationModel::factory();
	                # Email --
	                $booking_arr = $pjBookingModel
	                ->reset()
	                ->select("t1.*, t2.content AS country, t4.email AS c_email")
					->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();
					}
					$tokens = pjAppController::getTokens($booking_arr, $this->option_arr);
					$notification = $pjNotificationModel->reset()->where('recipient', 'client')->where('transport', 'email')->where('variant', 'confirmation')->findAll()->getDataIndex(0);
					if((int) $notification['id'] > 0 && $notification['is_active'] == 1)
					{
					    $locale_id = isset($booking_arr['locale_id']) && (int) $booking_arr['locale_id'] > 0 ? (int) $booking_arr['locale_id'] : $this->getLocaleId();
					    $resp = pjFront::pjActionGetSubjectMessage($notification, $locale_id, $booking_arr['calendar_id']);
					    $lang_message = $resp['lang_message'];
					    $lang_subject = $resp['lang_subject'];
					   
					    $subject_client = str_replace($tokens['search'], $tokens['replace'], $lang_subject[0]['content']);
					    $message_client = str_replace($tokens['search'], $tokens['replace'], $lang_message[0]['content']);
					    
					    $this->set('arr', array(
					        'id' => $booking_id,
					        'to' => $booking_arr['c_email'],
					        'message' => $message_client,
					        'subject' => $subject_client
					    ));
					}
					
	            }
	        }
	    }
	}
}
?>