<?php
/**
* @version	$Id: skin_helper.php 15137 2012-03-04 08:06:21Z alex $
* @package	In-Portal
* @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license      GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/

	defined('FULL_PATH') or die('restricted access!');

	class SkinHelper extends kHelper {

		/**
		 * Regular expression, used to detect admin skin file among others
		 */
		const SKIN_REGEXP = '/admin-(.*)-([\d]+).css/';

		/**
		 * Allows to read some skin fields and build link to admin skin file.
		 * Will automatically compile skin file, when missing.
		 *
		 * @param Array $params
		 * @return string
		 */
		function AdminSkinTag($params)
		{
			if (array_key_exists('type', $params)) {
				// returns given field of skin
				return $this->_getStyleField( $params['type'] );
			}

			$style_info = $this->_getStyleInfo();

			if (file_exists( $this->getSkinPath() )) {
				// returns last compiled skin
				$ret = $this->getSkinPath(true);
			}
			else {
				// search for previously compiled skin
				$last_compiled = $this->_getLastCompiled( mb_strtolower($style_info['Name']) );
				if ($last_compiled) {
					// found
					$ret = $this->getSkinPath(true, $last_compiled);
				}
				else {
					// not found (try to compile on the fly)
					$skin = $this->Application->recallObject('skin.-item', null, Array ('skip_autoload' => true));
					/* @var $skin kDBItem */

					$skin->Load(1, 'IsPrimary');
					$last_compiled = $this->compile($skin);
					$ret = $last_compiled ? $this->getSkinPath(true, $last_compiled) : '';
				}
			}

			if (array_key_exists('file_only', $params) && $params['file_only']) {
				return $ret;
			}

			return '<link rel="stylesheet" rev="stylesheet" href="' . $ret . '" type="text/css" media="screen"/>';
		}

		/**
		 * Compiles given skin object
		 *
		 * @param kDBItem $object
		 */
		function compile(&$object)
		{
			$ret = $object->GetDBField('CSS');
			$options = $object->GetDBField('Options');
			$options = unserialize($options);
			$options['base_url'] = Array ('Value' => rtrim(BASE_PATH, '/'));

			foreach ($options as $key => $row) {
				$ret = str_replace('@@' . $key . '@@', $row['Value'], $ret);
			}

			$compile_ts = adodb_mktime();
			$css_file = $this->_getStylesheetPath() . DIRECTORY_SEPARATOR . 'admin-' . mb_strtolower($object->GetDBField('Name')) . '-' . $compile_ts . '.css';

			$fp = fopen($css_file, 'w');
			if (!$fp) {
				return false;
			}

			$prev_css = $this->_getStylesheetPath() . '/admin-' . mb_strtolower($object->GetDBField('Name')) . '-' . $object->GetDBField('LastCompiled') . '.css';
			if (file_exists($prev_css)) {
				unlink($prev_css);
			}

			fwrite($fp, $ret);
			fclose($fp);

			$sql = 'UPDATE ' . $object->TableName . '
					SET LastCompiled = ' . $compile_ts . '
					WHERE ' . $object->IDField . ' = ' . $object->GetID();
			$this->Conn->Query($sql);

			$this->Application->incrementCacheSerial('skin');
			$this->Application->incrementCacheSerial('skin', $object->GetID());

			return $compile_ts;
		}

		/**
		 * Returns fields of primary admin skin
		 *
		 * @return Array
		 * @access protected
		 */
		protected function _getStyleInfo()
		{
			$cache_key = 'primary_skin_info[%SkinSerial%]';
			$ret = $this->Application->getCache($cache_key);

			if ($ret === false) {
				$this->Conn->nextQueryCachable = true;
				$sql = 'SELECT *
						FROM ' . TABLE_PREFIX . 'AdminSkins
						WHERE IsPrimary = 1';
				$ret = $this->Conn->GetRow($sql);

				$this->Application->setCache($cache_key, $ret);
			}

			return $ret;
		}

		/**
		 * Returns requested field value of primary admin skin
		 *
		 * @param string $field
		 * @return string
		 */
		function _getStyleField($field)
		{
			if ($field == 'logo') {
				// old style method of calling
				$field = 'Logo';
			}

			$style_info = $this->_getStyleInfo();

			if (!$style_info[$field]) {
				return '';
			}

			$image_fields = Array ('Logo', 'LogoBottom', 'LogoLogin');
			if (in_array($field, $image_fields)) {
				return $this->_getStylesheetPath(true) . '/' . $style_info[$field];
			}

			return $style_info[$field];
		}

		/**
		 * Returns path, where compiled skin and it's image files are stored
		 *
		 * @param bool $url
		 * @return string
		 * @access protected
		 */
		protected function _getStylesheetPath($url = false)
		{
			if ($url) {
				return $this->Application->BaseURL( str_replace(DIRECTORY_SEPARATOR, '/', WRITEBALE_BASE) ) . 'user_files';
			}

			return WRITEABLE . DIRECTORY_SEPARATOR . 'user_files';
		}

		/**
		 * Returns full path to primary admin skin using given or last compiled date
		 *
		 * @param string|bool $url
		 * @param int $compile_date
		 * @return string
		 * @access public
		 */
		public function getSkinPath($url = false, $compile_date = null)
		{
			$style_info = $this->_getStyleInfo();

			if ( !isset($compile_date) ) {
				$compile_date = $style_info['LastCompiled'];
			}

			$style_name = 'admin-' . mb_strtolower($style_info['Name']) . '-' . $compile_date . '.css';

			return $this->_getStylesheetPath($url) . ($url ? '/' : DIRECTORY_SEPARATOR) . $style_name;
		}

		/**
		 * Returns maximal compilation date for given skin name
		 *
		 * @param string $style_name
		 * @return int
		 */
		function _getLastCompiled($style_name)
		{
			$last_compiled = 0;

			$iterator = new DirectoryIterator( $this->_getStylesheetPath() . DIRECTORY_SEPARATOR );
			/* @var $file_info DirectoryIterator */

			foreach ($iterator as $file_info) {
				if ( !$file_info->isFile() ) {
					continue;
				}

				$regs = $this->isSkinFile( $file_info->getFilename() );

				if ( $regs && $regs[1] == $style_name && $regs[2] > $last_compiled ) {
					$last_compiled = max($last_compiled, $regs[2]);
				}
			}

			return $last_compiled;
		}

		/**
		 * Deletes all compiled versions of all skins
		 *
		 */
		function deleteCompiled()
		{
			$iterator = new DirectoryIterator( $this->_getStylesheetPath() . DIRECTORY_SEPARATOR );
			/* @var $file_info DirectoryIterator */

			foreach ($iterator as $file_info) {
				if ( $file_info->isFile() && $this->isSkinFile( $file_info->getFilename() ) ) {
					unlink( $file_info->getPathname() );
				}
			}
		}

		/**
		 * Determines if given file is admin skin file
		 *
		 * @param string $filename
		 * @return array|bool
		 * @access protected
		 */
		protected function isSkinFile($filename)
		{
			if ( preg_match(self::SKIN_REGEXP, $filename, $regs) ) {
				return $regs;
			}

			return false;
		}
	}