<?php
if (!defined("ROOT_PATH"))
{
	header("HTTP/1.1 403 Forbidden");
	exit;
}
class pjAppController extends pjController
{
	public $models = array();

	/**
	 * Generate (or return existing) CSRF token for the current session.
	 */
	public static function getCsrfToken()
	{
		if (empty($_SESSION['csrf_token']))
		{
			$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
		}
		return $_SESSION['csrf_token'];
	}

	/**
	 * Validate CSRF token (admin requests).
	 */
	public static function validateCsrfToken()
	{
		$token = '';
		if (!empty($_POST['csrf_token'])) {
			$token = $_POST['csrf_token'];
		} elseif (!empty($_SERVER['HTTP_X_CSRF_TOKEN'])) {
			$token = $_SERVER['HTTP_X_CSRF_TOKEN'];
		}
		if (empty($_SESSION['csrf_token']) || !hash_equals($_SESSION['csrf_token'], (string) $token))
		{
			header('HTTP/1.1 403 Forbidden');
			exit('Invalid CSRF token.');
		}
	}
	
	public $option_arr = array();

	public $defaultLocale = 'admin_locale_id';
	
	public $allowed_ext = array('png','jpg','jpeg','gif','doc','docx','xls','xlsx','ppt','pptx','pdf','zip','rar','txt','csv');
	
	public $defaultFields = 'fields';
	
	public $defaultFieldsIndex = 'fields_index';
	
	protected function loadSetFields($force=true)
	{
		$registry = pjRegistry::getInstance();
		if ($force
				|| !isset($_SESSION[$this->defaultFieldsIndex])
				|| $_SESSION[$this->defaultFieldsIndex] != $this->option_arr['o_fields_index']
				|| !isset($_SESSION[$this->defaultFields])
				|| empty($_SESSION[$this->defaultFields]))
		{
			pjAppController::setFields($this->getLocaleId());
	
			if ($registry->is('fields'))
			{
				$_SESSION[$this->defaultFields] = $registry->get('fields');
			}
			$_SESSION[$this->defaultFieldsIndex] = $this->option_arr['o_fields_index'];
		}
	
		if (isset($_SESSION[$this->defaultFields]) && !empty($_SESSION[$this->defaultFields]))
		{
			$registry->set('fields', $_SESSION[$this->defaultFields]);
		}
			
		return TRUE;
	}
	
	public function isOneAdminReady()
	{
		return $this->isAdmin();
	}
	public function isCountryReady()
    {
    	return $this->isAdmin();
    }
	
	public static function setTimezone($timezone="UTC")
    {
    	if (in_array(version_compare(phpversion(), '5.1.0'), array(0,1)))
		{
			date_default_timezone_set($timezone);
		} else {
			$safe_mode = ini_get('safe_mode');
			if ($safe_mode)
			{
				putenv("TZ=".$timezone);
			}
		}
    }

	public static function setMySQLServerTime($offset="-0:00")
    {
		pjAppModel::factory()->prepare("SET SESSION time_zone = :offset;")->exec(compact('offset'));
    }
    
	public function setTime()
	{
		if (isset($this->option_arr['o_timezone']))
		{
			$offset = $this->option_arr['o_timezone'] / 3600;
			if ($offset > 0)
			{
				$offset = "-".$offset;
			} elseif ($offset < 0) {
				$offset = "+".abs($offset);
			} elseif ($offset === 0) {
				$offset = "+0";
			}
	
			pjAppController::setTimezone('Etc/GMT' . $offset);
			if (strpos($offset, '-') !== false)
			{
				$offset = str_replace('-', '+', $offset);
			} elseif (strpos($offset, '+') !== false) {
				$offset = str_replace('+', '-', $offset);
			}
			pjAppController::setMySQLServerTime($offset . ":00");
		}
	}
    
    public function beforeFilter()
    {
		if (strtoupper(@$_SERVER['REQUEST_METHOD']) === 'POST')
		{
			$_csrf_ctrl = isset($_GET['controller']) ? $_GET['controller'] : '';
			$_csrf_act = isset($_GET['action']) ? $_GET['action'] : '';
			if (strpos($_csrf_ctrl, 'pjAdmin') === 0
				&& !in_array($_csrf_act, array('pjActionLogin', 'pjActionForgot', 'pjActionLogout'), true)) {
				pjAppController::validateCsrfToken();
			}
		}

    	$this->appendJs('jquery.min.js', PJ_THIRD_PARTY_PATH . 'jquery/');
		$baseDir = defined("PJ_INSTALL_PATH") ? PJ_INSTALL_PATH : null;
		$dm = new pjDependencyManager($baseDir, PJ_THIRD_PARTY_PATH);
		$dm->load(PJ_CONFIG_PATH . 'dependencies.php')->resolve();
		$this->appendJs('jquery-migrate.min.js', $dm->getPath('jquery_migrate'), FALSE, FALSE);
		$this->appendJs('pjAdminCore.js');
		$this->appendCss('reset.css');
		 
		$this->appendJs('js/jquery-ui.custom.min.js', PJ_THIRD_PARTY_PATH . 'jquery_ui/');
		$this->appendCss('css/smoothness/jquery-ui.min.css', PJ_THIRD_PARTY_PATH . 'jquery_ui/');
				
		$this->appendCss('pj-all.css', PJ_FRAMEWORK_LIBS_PATH . 'pj/css/');
		$this->appendCss('admin.css');
		
   	 	if ($_GET['controller'] != 'pjInstaller')
		{
			$this->models['Option'] = pjOptionModel::factory();
			$this->option_arr = $this->models['Option']->getPairs($this->getForeignId());
			$this->set('option_arr', $this->option_arr);
			$this->setTime();
			
			if (!isset($_SESSION[$this->defaultLocale]))
			{
				$locale_arr = pjLocaleModel::factory()->where('is_default', 1)->limit(1)->findAll()->getData();
				if (count($locale_arr) === 1)
				{
					$this->setLocaleId($locale_arr[0]['id']);
				}
			}
			$this->loadSetFields();
		}
    }
    
	public function pjActionCheckInstall()
	{
		$this->setLayout('pjActionEmpty');
	
		$result = array('status' => 'OK', 'code' => 200, 'text' => 'Operation succeeded', 'info' => array());
		$folders = array(
				'app/web/upload',
				'app/web/upload/files',
				'app/web/upload/files/tickets',
				'app/web/upload/files/replies'
		);
		foreach ($folders as $dir)
		{
			if (!is_writable($dir))
			{
				$result['status'] = 'ERR';
				$result['code'] = 101;
				$result['text'] = 'Permission requirement';
				$result['info'][] = sprintf('Folder \'<span class="bold">%1$s</span>\' is not writable. You need to set write permissions (chmod 777) to directory located at \'<span class="bold">%1$s</span>\'', $dir);
			}
		}
	
		return $result;
	}
    
    public function getForeignId()
    {
    	return 1;
    }
    
    public static function getTokens($booking_arr, $option_arr)
    {
    	$search = array(
			'{Name}', '{Email}', '{Phone}', '{Notes}',
			'{CCType}', '{CCNum}', '{CCExp}', '{CCSec}',
			'{PaymentMethod}', '{ListingID}',
			'{StartDate}', '{EndDate}', '{ReservationID}',
			'{Deposit}', '{Price}', '{Tax}', '{Security}', '{Total}');
		$replace = array(
			$booking_arr['name'], $booking_arr['email'], $booking_arr['phone'], $booking_arr['notes'],
			$booking_arr['cc_type'], $booking_arr['cc_num'], ($booking_arr['payment_method'] == 'creditcard' ? $booking_arr['cc_exp'] : NULL), $booking_arr['cc_code'],
			$booking_arr['payment_method'], $booking_arr['listing_id'],
			$booking_arr['date_from'], $booking_arr['date_to'], $booking_arr['id'],
			$booking_arr['deposit'] . " " . $option_arr['currency'], $booking_arr['amount'] . " " . $option_arr['currency'], $booking_arr['tax'] . " " . $option_arr['currency'], $booking_arr['security'] . " " . $option_arr['currency'], ($booking_arr['amount'] + $booking_arr['security'] + $booking_arr['tax']) . " " . $option_arr['currency']
		);
		return compact('search', 'replace');
    }
    
    public static function setFields($locale)
    {
    	if(isset($_SESSION['lang_show_id']) && (int) $_SESSION['lang_show_id'] == 1)
		{
			$fields = pjMultiLangModel::factory()
				->select('CONCAT(t1.content, CONCAT(":", t2.id, ":")) AS content, t2.key')
				->join('pjField', "t2.id=t1.foreign_id", 'inner')
				->where('t1.locale', $locale)
				->where('t1.model', 'pjField')
				->where('t1.field', 'title')
				->findAll()
				->getDataPair('key', 'content');
		}else{
			$fields = pjMultiLangModel::factory()
				->select('t1.content, t2.key')
				->join('pjField', "t2.id=t1.foreign_id", 'inner')
				->where('t1.locale', $locale)
				->where('t1.model', 'pjField')
				->where('t1.field', 'title')
				->findAll()
				->getDataPair('key', 'content');
		}
		$registry = pjRegistry::getInstance();
		$tmp = array();
		if ($registry->is('fields'))
		{
			$tmp = $registry->get('fields');
		}
		$arrays = array();
		foreach ($fields as $key => $value)
		{
			if (strpos($key, '_ARRAY_') !== false)
			{
				list($prefix, $suffix) = explode("_ARRAY_", $key);
				if (!isset($arrays[$prefix]))
				{
					$arrays[$prefix] = array();
				}
				$arrays[$prefix][$suffix] = $value;
			}
		}
		require PJ_CONFIG_PATH . 'settings.inc.php';
		$fields = array_merge($tmp, $fields, $settings, $arrays);
		$registry->set('fields', $fields);
    }

    public static function jsonDecode($str)
	{
		$Services_JSON = new pjServices_JSON();
		return $Services_JSON->decode($str);
	}
	
	public static function jsonEncode($arr)
	{
		$Services_JSON = new pjServices_JSON();
		return $Services_JSON->encode($arr);
	}
	
	public static function jsonResponse($arr)
	{
		header("Content-Type: application/json; charset=utf-8");
		echo pjAppController::jsonEncode($arr);
		exit;
	}

	public function isOperator()
	{
		return $this->getRoleId() == 2;
	}

	public function isOwner()
	{
		return $this->getRoleId() == 3;
	}

	public function getLocaleId()
	{
		return isset($_SESSION[$this->defaultLocale]) && (int) $_SESSION[$this->defaultLocale] > 0 ? (int) $_SESSION[$this->defaultLocale] : false;
	}
	
	public function setLocaleId($locale_id)
	{
		$_SESSION[$this->defaultLocale] = (int) $locale_id;
	}
	
	public function friendlyURL($str, $divider='-')
	{
		$str = mb_strtolower($str, mb_detect_encoding($str));
		$str = trim($str);
		$str = preg_replace('/[_|\s]+/', $divider, $str); 
		$str = preg_replace('/\x{00C5}/u', 'AA', $str);
		$str = preg_replace('/\x{00C6}/u', 'AE', $str);
		$str = preg_replace('/\x{00D8}/u', 'OE', $str);
		$str = preg_replace('/\x{00E5}/u', 'aa', $str);
		$str = preg_replace('/\x{00E6}/u', 'ae', $str);
		$str = preg_replace('/\x{00F8}/u', 'oe', $str);
		$str = preg_replace('/[^a-z\x{0400}-\x{04FF}0-9-]+/u', '', $str);
		$str = preg_replace('/[-]+/', $divider, $str);
		$str = preg_replace('/^-+|-+$/', '', $str);
		return $str;
	}
	
	protected function sendEmail($ticket_id, $status, $reply_arr, $from, $locale_id, $option_arr)
	{
		$pjTicketModel = pjTicketModel::factory();
		$pjClientModel = pjClientModel::factory();
		$pjUserModel = pjUserModel::factory();
		
		$notification_arr = pjNotificationModel::factory()->select('t1.*, t2.content AS subject, t3.content AS message')
					->join('pjMultiLang', "t2.model='pjNotification' AND t2.foreign_id=t1.id AND t2.field='subject' AND t2.locale='".$locale_id."'", 'left')
					->join('pjMultiLang', "t3.model='pjNotification' AND t3.foreign_id=t1.id AND t3.field='message' AND t3.locale='".$locale_id."'", 'left')
					->where("`type`", $status)->orderBy("t1.id DESC")->findAll()->getData();
		foreach($notification_arr as $email_template)
		{
			$to_arr = array();
			$notification_id = $email_template['id'];
			$ticket_arr = $pjTicketModel->reset()->find($ticket_id)->getData();
			$client_arr = $pjClientModel->reset()->find($ticket_arr['client_id'])->getData();
			
			if($email_template['recipient_client'] == 'T')
			{
				$to_arr[] = $client_arr['email'];
			}
			
			if((int) $ticket_arr['department_id'] > 0)
			{
				$user2_arr = $pjUserModel->reset()->select('t1.*')
					->join('pjUserDepartment', "t2.user_id=t1.id AND t2.department_id IN (SELECT t3.department_id FROM `".pjNotificationDepartmentModel::factory()->getTable()."` AS t3 WHERE t3.notification_id = '$notification_id' AND t3.department_id='".$ticket_arr['department_id']."')")
					->where("t1.status", 'T')->findAll()->getData();
				foreach($user2_arr as $v){
					$to_arr[] = $v['email'];
				}
			}else{
				$user1_arr = $pjUserModel->reset()->select('t1.*')
							->join('pjNotificationUser', "t2.user_id=t1.id AND t2.notification_id='$notification_id'")
							->where("t1.status", 'T')->findAll()->getData();
				$user2_arr = $pjUserModel->reset()->select('t1.*')
							->join('pjUserDepartment', "t2.user_id=t1.id AND t2.department_id IN (SELECT t3.department_id FROM `".pjNotificationDepartmentModel::factory()->getTable()."` AS t3 WHERE t3.notification_id = '$notification_id')")
							->where("t1.status", 'T')->findAll()->getData();
				foreach($user1_arr as $v){
					$to_arr[] = $v['email'];
				}
				foreach($user2_arr as $v){
					$to_arr[] = $v['email'];
				}
			}				
			$to_arr = array_unique($to_arr);
			$ticket_date_time = pjUtil::formatDate(date('Y-m-d', strtotime($ticket_arr['created'])), "Y-m-d", $option_arr ['o_date_format']) . ', ' . date('H:i', strtotime($ticket_arr['created']));
			if($reply_arr != null)
			{
				$reply_date_time = pjUtil::formatDate(date('Y-m-d', strtotime($reply_arr['created'])), "Y-m-d", $option_arr ['o_date_format']) . ', ' . date('H:i', strtotime($reply_arr['created']));
			}else{
				$reply_date_time = "";
			}
			
			$search = array('{TicketID}', '{ClientName}', '{ClientEmail}', '{ClientPassword}', '{Date/TimeTicket}','{Date/TimeReply}');
			$replace = array($ticket_arr['ticket_id'], $client_arr['name'], $client_arr['email'], $client_arr['password'], $ticket_date_time, $reply_date_time);
			$tokens = compact('search', 'replace');
			
			$subject = $email_template['subject'];
			$message = str_replace($tokens['search'], $tokens['replace'], $email_template['message']);
			
			$Email = new pjEmail();
			$Email->setContentType('text/html');
			if ($option_arr['o_send_email'] == 'smtp')
			{
				$Email->setTransport('smtp')
						->setSmtpHost($option_arr['o_smtp_host'])
						->setSmtpPort($option_arr['o_smtp_port'])
						->setSmtpUser($option_arr['o_smtp_user'])
						->setSmtpPass($option_arr['o_smtp_pass'])
						->setSender($option_arr['o_smtp_user']);
			}
			foreach($to_arr as $to)
			{
				$Email->setTo($to);
				$Email->setFrom($from);
				$Email->setSubject($subject);
				$Email->send($message);
			}
		}
	}
	
	protected function sendNewClientEmail($client_id, $from, $locale_id, $option_arr)
	{
		
		$pjClientModel = pjClientModel::factory();
		$pjUserModel = pjUserModel::factory();
		
		$notification_arr = pjNotificationModel::factory()->select('t1.*, t2.content AS subject, t3.content AS message')
					->join('pjMultiLang', "t2.model='pjNotification' AND t2.foreign_id=t1.id AND t2.field='subject' AND t2.locale='".$locale_id."'", 'left')
					->join('pjMultiLang', "t3.model='pjNotification' AND t3.foreign_id=t1.id AND t3.field='message' AND t3.locale='".$locale_id."'", 'left')
					->where("`type`", 'NewClient')->orderBy("t1.id DESC")->findAll()->getData();
		foreach($notification_arr as $email_template)
		{
			$to_arr = array();
			$notification_id = $email_template['id'];
			$client_arr = $pjClientModel->reset()->find($client_id)->getData();
			
			if($email_template['recipient_client'] == 'T')
			{
				$to_arr[] = $client_arr['email'];
			}
			$user1_arr = $pjUserModel->reset()->select('t1.*')
						->join('pjNotificationUser', "t2.user_id=t1.id AND t2.notification_id='$notification_id'")
						->where("t1.status", 'T')->findAll()->getData();
			$user2_arr = $pjUserModel->reset()->select('t1.*')
						->join('pjUserDepartment', "t2.user_id=t1.id AND t2.department_id IN (SELECT t3.department_id FROM `".pjNotificationDepartmentModel::factory()->getTable()."` AS t3 WHERE t3.notification_id = '$notification_id')")
						->where("t1.status", 'T')->findAll()->getData();
			foreach($user1_arr as $v){
				$to_arr[] = $v['email'];
			}
			foreach($user2_arr as $v){
				$to_arr[] = $v['email'];
			}
			$to_arr = array_unique($to_arr);
			$ticket_date_time = "";
			$reply_date_time = "";
			$ticket_id = "";
			
			$search = array('{TicketID}', '{ClientName}', '{ClientEmail}', '{ClientPassword}', '{Date/TimeTicket}','{Date/TimeReply}');
			$replace = array($ticket_id, $client_arr['name'], $client_arr['email'], $client_arr['password'], $ticket_date_time, $reply_date_time);
			$tokens = compact('search', 'replace');
			
			$subject = $email_template['subject'];
			$message = str_replace($tokens['search'], $tokens['replace'], $email_template['message']);
			
			$Email = new pjEmail();
			
			if ($option_arr['o_send_email'] == 'smtp')
			{
				$Email->setTransport('smtp')
						->setSmtpHost($option_arr['o_smtp_host'])
						->setSmtpPort($option_arr['o_smtp_port'])
						->setSmtpUser($option_arr['o_smtp_user'])
						->setSmtpPass($option_arr['o_smtp_pass'])
						->setSender($option_arr['o_smtp_user']);
			}
			
			foreach($to_arr as $to)
			{
				$Email->setContentType('text/html');
				$Email->setTo($to);
				$Email->setFrom($from);
				$Email->setSubject($subject);
				$Email->send($message);
			}
		}
	}
	
	static public function getAdminEmail()
	{
		$arr = pjUserModel::factory()
			->findAll()
			->orderBy("t1.id ASC")
			->limit(1)
			->getData();
		return !empty($arr) ? $arr[0]['email'] : null;
	}
}
?>