<?php
/**
 * Bitrix Framework
 * @package bitrix
 * @subpackage main
 * @copyright 2001-2012 Bitrix
 */
namespace Bitrix\Main;

/**
 * Base class for any application.
 */
abstract class Application
{
	/**
	 * Execution context.
	 *
	 * @var Context
	 */
	protected $context;

	/**
	 * Backreference to server.
	 *
	 * @var Server
	 */
	protected $server;

	/**
	 * Pool of database connections.
	 *
	 * @var \Bitrix\Main\DB\DbConnectionPool
	 */
	protected $dbConnectionPool;

	/**
	 * Managed cache instance.
	 *
	 * @var \Bitrix\Main\Data\ManagedCache
	 */
	protected $managedCache;

	/**
	 * LRU cache instance.
	 *
	 * @var \Bitrix\Main\Data\LruCache
	 */
	protected $lruCache;

	private $isKernelInitialized = false;

	/**
	 * Creates new application instance.
	 *
	 * @param Server $server
	 */
	public function __construct(Server $server)
	{
		$this->server = $server;
		$this->isKernelInitialized = false;
	}

	/**
	 * Initializes application. Should be called before start() method.
	 *
	 * @param System\IApplicationStrategy $initStrategy
	 */
	final public function initialize(\Bitrix\Main\System\IApplicationStrategy $initStrategy = null)
	{
		if ($initStrategy != null)
			$initStrategy->preInitialize();

		$this->initializeKernel($initStrategy);
		$this->initializeShell($initStrategy);

		if ($initStrategy != null)
			$initStrategy->postInitialize();
	}

	/**
	 * Initializes application kernel.
	 * Шаблонный метод определяет основу алгоритма и позволяет наследникам переопределять
	 * некоторые шаги алгоритма, не изменяя его структуру в целом.
	 *
	 * @param System\IApplicationStrategy $initStrategy
	 */
	final protected function initializeKernel(\Bitrix\Main\System\IApplicationStrategy $initStrategy = null)
	{
		if ($this->isKernelInitialized)
			return;

		/*** Базовая инициализация, без которой нельзя ***/

		//<start.php>
		// подключение конфига
		// константы
		// соединение
		$this->createDatabaseConnection();

		if ($initStrategy != null)
			$initStrategy->createDatabaseConnection();

		// в проактивной защите нужно делать поддержку контекста
		$this->initializeContext();

		if ($initStrategy != null)
			$initStrategy->initializeContext();
		//</start.php>

		//<include.php>
		//error_reporting(\COption::GetOptionInt("main", "error_reporting", E_COMPILE_ERROR|E_ERROR|E_CORE_ERROR|E_PARSE) & ~E_STRICT);

		// это видимо на страницу, но нужно до апдейтера
		//if(!defined("BX_COMP_MANAGED_CACHE") && \COption::GetOptionString("main", "component_managed_cache_on", "Y") <> "N")
		//	define("BX_COMP_MANAGED_CACHE", true);

		// определяется сайт и язык
		// видимо, определение языка нужно куда-то отдельно
		// и там еще $APPLICATION->reinitPath
		$this->initializeCulture();

		$this->initializeBasicKernel();

		if ($initStrategy != null)
			$initStrategy->initializeBasicCore();

		/*** Лицензии и обновления ***/

		/*patchvalidationmutatormark1*/			//Do not remove this

		$this->updateMainDb();
		$this->updateModulesDB();

		/*** Расширенная инициализация ***/

		// выполнение кастомных скриптов инициализации и определение констант после init.php
		$this->runInitScripts();

		// ключ
		$this->getLicenseInfo();

		$this->initializeExtendedKernel();

		if ($initStrategy != null)
			$initStrategy->initializeExtendedCore();

		$this->isKernelInitialized = true;
	}

	/**
	 * Initializes context of the current request.
	 * Should be implemented in subclass.
	 */
	abstract protected function initializeContext();

	/**
	 * Initializes default culture of the current request.
	 * Should be implemented in subclass.
	 */
	abstract protected function initializeCulture();

	/**
	 * Initializes basic part of kernel. It is called before update system call.
	 * Should be implemented in subclass.
	 */
	abstract protected function initializeBasicKernel();

	/**
	 * Initializes extended part of kernel. It is called after update system call.
	 * Should be implemented in subclass.
	 */
	abstract protected function initializeExtendedKernel();

	/**
	 * Initializes application shell. Called after initializeKernel.
	 * Should be implemented in subclass.
	 *
	 * @param System\IApplicationStrategy $initStrategy
	 */
	abstract protected function initializeShell(\Bitrix\Main\System\IApplicationStrategy $initStrategy = null);

	/**
	 * Starts request execution. Should be called after initialize.
	 * Should be implemented in subclass.
	 */
	abstract public function start();

	protected function updateMainDb()
	{
		if (file_exists(($fname = $_SERVER["DOCUMENT_ROOT"].BX_ROOT."/modules/main/classes/general/update_db_updater.php")))
		{
			global $US_HOST_PROCESS_MAIN;
			$US_HOST_PROCESS_MAIN = True;
			include($fname);
		}
	}

	protected function updateModulesDb()
	{
		if(file_exists(($_fname = $_SERVER["DOCUMENT_ROOT"].BX_ROOT."/modules/main/classes/general/update_db_updater.php")))
		{
			$GLOBALS["US_HOST_PROCESS_MAIN"] = False;
			include($_fname);
		}

		include("module_updater.php");
	}

	/**
	 * Creates database connection pool.
	 */
	protected function createDatabaseConnection()
	{
		$this->dbConnectionPool = new \Bitrix\Main\Db\DbConnectionPool();
	}

	protected function getLicenseInfo()
	{
		//license key
		$LICENSE_KEY = "";
		if(file_exists(($_fname = $_SERVER["DOCUMENT_ROOT"].BX_ROOT."/license_key.php")))
			include($_fname);
		if($LICENSE_KEY == "" || strtoupper($LICENSE_KEY) == "DEMO")
			define("LICENSE_KEY", "DEMO");
		else
			define("LICENSE_KEY", $LICENSE_KEY);

		header("X-Powered-CMS: Bitrix Site Manager (".(LICENSE_KEY == "DEMO"? "DEMO" : md5("BITRIX".LICENSE_KEY."LICENCE")).")");
	}

	protected function runInitScripts()
	{
		if (($includePath = Loader::getLocal("init.php")) !== false)
			require_once($includePath);

		if (($includePath = Loader::getPersonal("php_interface/init.php")) !== false)
			require_once($includePath);

		if (($includePath = Loader::getPersonal("php_interface/".SITE_ID."/init.php")) !== false)
			require_once($includePath);

		// константы после init.php
		define("BX_CRONTAB_SUPPORT", defined("BX_CRONTAB"));

		if(!defined("BX_FILE_PERMISSIONS"))
			define("BX_FILE_PERMISSIONS", 0777);
		if(!defined("BX_DIR_PERMISSIONS"))
			define("BX_DIR_PERMISSIONS", 0777);
	}

	/**
	 * Returns database connections pool object.
	 *
	 * @return DB\DbConnectionPool
	 */
	public function getDbConnectionPool()
	{
		return $this->dbConnectionPool;
	}

	/**
	 * Returns context of the current request.
	 *
	 * @return Context
	 */
	public function getContext()
	{
		return $this->context;
	}

	/**
	 * Modifies context of the current request.
	 *
	 * @param Context $context
	 */
	public function setContext(Context $context)
	{
		$this->context = $context;
	}

	/**
	 * Returns backreference to Server.
	 *
	 * @return Server
	 */
	public function getServer()
	{
		return $this->server;
	}

	/**
	 * Static method returns current instance of application.
	 *
	 * @static
	 * @return Application
	 */
	public static function getCurrent()
	{
		$server = Server::getInstance();
		return $server->getApplication();
	}

	/**
	 * Static method returns database connection for the specified name.
	 * If name is empty - default connection is returned.
	 *
	 * @static
	 * @param string $name Name of database connection. If empty - default connection.
	 * @return DB\DbConnection
	 */
	public static function getDbConnection($name = "")
	{
		$server = Server::getInstance();
		$pool = $server->getApplication()->getDbConnectionPool();
		return $pool->getConnection($name);
	}

	/**
	 * Returns new instance of the Cache object.
	 *
	 * @return Data\Cache
	 */
	public function getCache()
	{
		return \Bitrix\Main\Data\Cache::createInstance();
	}

	/**
	 * Returns manager of the managed cache.
	 *
	 * @return Data\ManagedCache
	 */
	public function getManagedCache()
	{
		if ($this->managedCache == null)
			$this->managedCache = new \Bitrix\Main\Data\ManagedCache();
		return $this->managedCache;
	}
}
