<?php

/**
 * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 * @package clearFusionCMS
 * @copyright Copyright (c) 2012 - 2017 clearFusionCMS. All rights reserved.
 * @link http://clearfusioncms.com
 */

/**
 * cfSiteManager Class
 *
 * Class to provide site management functionality.
 *
 * @package clearFusionCMS
 */
class cfSiteManager {

	/**
	 * The database object.
	 *
	 * @var flDb
	 */
	protected $db;

	/**
	 * Construct the object.
	 *
	 * @param flDb $db The database object.
	 */
	function __construct($db) {
		$this->db = $db;
	}

	/**
	 * Get an array holding the list of sites.
	 *
	 * @param null|array $perms If given an array of permissions to match against the site edit perms.
	 * @return array shortname => displayname
	 */
	function listSites($perms = null) {
		$r = array();
		$result = $this->db->query('SELECT shortname,displayname,editperm FROM cf_sites WHERE redirectto=\'\' ORDER BY displayname');
		while($row = $result->fetch()) {
			if($perms === null || empty($row['editperm']) || isset($perms[$row['editperm']]))
				$r[$row['shortname']] = $row['displayname'];
		}
		return $r;
	}

	/**
	 * Initialise the configuration and content tables for a new site.
	 *
	 * @param string $shortName The name of the new site.
	 */
	function initSite($shortName) {
		$this->db->query("CREATE  TABLE IF NOT EXISTS `cf_config_{$shortName}` (
  `namespace` VARCHAR(32) NOT NULL ,
  `keyname` VARCHAR(32) NOT NULL ,
  `value` TEXT NOT NULL ,
  PRIMARY KEY (`namespace`, `keyname`) )
ENGINE = MyISAM
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_general_ci
");

		$this->db->query("CREATE  TABLE IF NOT EXISTS `cf_content_{$shortName}` (
  `id` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
  `parentid` INT UNSIGNED NOT NULL ,
  `lft` INT UNSIGNED NOT NULL ,
  `rgt` INT UNSIGNED NOT NULL ,
  `lftrgtset` LINESTRING NOT NULL ,
  `contenttype` INT UNSIGNED NOT NULL ,
  `cachetime` INT NOT NULL ,
  `ogimageid` INT UNSIGNED NOT NULL ,
  `twitterimageid` INT UNSIGNED NOT NULL ,
  `publishedat` DATETIME NULL ,
  `lastupdated` DATETIME NOT NULL ,
  `menuhide` TINYINT NOT NULL ,
  `noeditor` TINYINT NOT NULL ,
  `issearchable` TINYINT NOT NULL ,
  `published` TINYINT NOT NULL ,
  `asattachment` TINYINT NOT NULL ,
  `restype` ENUM('doc','link','static','folder') NOT NULL ,
  `accessperm` VARCHAR(32) NOT NULL ,
  `editperm` VARCHAR(32) NOT NULL ,
  `template` VARCHAR(64) NOT NULL ,
  `container` VARCHAR(64) NOT NULL ,
  `slug` VARCHAR(255) NOT NULL ,
  `title` VARCHAR(255) NOT NULL ,
  `subtitle` VARCHAR(255) NOT NULL ,
  `meta_title` VARCHAR(255) NOT NULL ,
  `meta_description` VARCHAR(255) NOT NULL ,
  `meta_keywords` VARCHAR(255) NOT NULL ,
  `menutitle` VARCHAR(255) NOT NULL ,
  `ogtitle` VARCHAR(255) NOT NULL ,
  `ogdesc` VARCHAR(255) NOT NULL ,
  `twittertitle` VARCHAR(255) NOT NULL ,
  `twitterdesc` VARCHAR(255) NOT NULL ,
  `summary` TEXT NOT NULL ,
  `content` MEDIUMTEXT NOT NULL ,
  `draft` MEDIUMTEXT NOT NULL ,
  PRIMARY KEY (`id`) ,
  INDEX `parentid` (`parentid` ASC) ,
  INDEX `lft` (`lft` ASC) ,
  INDEX `rgt` (`rgt` ASC) ,
  UNIQUE INDEX `slug` (`slug` ASC, `parentid` ASC) ,
  INDEX `menuhide` (`menuhide` ASC) ,
  INDEX `publishedat` (`publishedat` ASC) ,
  INDEX `issearchable` (`issearchable` ASC) ,
  INDEX `published` (`published` ASC) ,
  INDEX `container` (`container` ASC) ,
  SPATIAL INDEX `lftrgtset` (`lftrgtset` ASC) )
ENGINE = MyISAM
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_general_ci
");

		$this->db->query("CREATE  TABLE IF NOT EXISTS `cf_customflds_ctnt_{$shortName}` (
  `id` INT UNSIGNED NOT NULL ,
  `placeholder` VARCHAR(32) NOT NULL ,
  `content` MEDIUMTEXT NOT NULL ,
  PRIMARY KEY (`id`, `placeholder`) )
ENGINE = MyISAM
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_general_ci
");

		$this->db->query("CREATE TABLE IF NOT EXISTS `cf_socialimages_{$shortName}` (
  `imageid` INT UNSIGNED NOT NULL AUTO_INCREMENT,
  `ext` VARCHAR(4) NOT NULL ,
  `title` VARCHAR(255) NOT NULL ,
  INDEX `uid` (`imageid` ASC) )
ENGINE = MyISAM
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_general_ci
");

		$this->db->query("CREATE TABLE IF NOT EXISTS `cf_auditlog_{$shortName}` (
  `auditid` INT UNSIGNED NOT NULL AUTO_INCREMENT,
  `action` INT UNSIGNED NOT NULL ,
  `module` VARCHAR(64) NOT NULL ,
  `cid` INT UNSIGNED NOT NULL ,
  `uid` INT UNSIGNED NOT NULL ,
  `loggedat` DATETIME NOT NULL ,
  `ip` VARCHAR(64) NOT NULL ,
  `params` MEDIUMTEXT NOT NULL ,
  `previous` MEDIUMTEXT NOT NULL ,
  PRIMARY KEY (`auditid`) ,
  INDEX `uid` (`uid` ASC) ,
  INDEX `modulecid` (`module`, `cid` ASC) ,
  INDEX `loggedat` (`loggedat` ASC))
ENGINE = MyISAM
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_general_ci
");
	}

	/**
	 * Create a new site.
	 *
	 * @param string $shortName The short name of the site.
	 * @param string $domain The domain name.
	 * @param string $displayName The display name for the site.
	 * @param string $clone The site to clone the configuration from.
	 * @param string $locale The locale for the site.
	 * @param string $twitterUsername The twitter username associated with the site.
	 * @param string $editPerm The permission required to edit the site.
	 * @param array $aliases Array of domains that map to the site as well.
	 * @param bool $sslOnly Flags if the site can only be accessed via SSL.
	 * @return bool true if the site was created; else false.
	 */
	function createSite($shortName, $domain, $displayName, $clone, $locale = 'en_US', $twitterUsername = '', $editPerm = '', $aliases = array(), $sslOnly = false) {
		if(!$this->db->insert('cf_sites', array(
			'shortname' => $shortName,
			'domain' => $domain,
			'displayname' => $displayName,
			'redirectto' => '',
			'locale' => $locale,
			'editperm' => '',
			'twitterusername' => $twitterUsername,
			'editperm' => $editPerm,
			'puressl' => $sslOnly ? 1 : 0
		)))
			return false;

		// Create new aliases
		foreach($aliases as $d) {
			$d = trim($d);
			if(!empty($d)) {
				$this->db->insert('cf_sites', array(
					'shortname' => $shortName,
					'domain' => $d,
					'displayname' => '',
					'locale' => '',
					'editperm' => ''
				));
			}
		}

		$this->initSite($shortName);

		// Clone the config table
		$this->db->query("INSERT INTO cf_config_{$shortName} SELECT * FROM cf_config_{$clone}");

		// Tell installed modules to create the new site
		$mm = new flModuleMgr($this->db);
		$inst = $mm->getInstalled();
		foreach($inst as $name => $ver) {
			if($instObj = $mm->getModuleInstaller($name))
				$instObj->createSite($this->db, $shortName);
		}

		return true;
	}

	/**
	 * Delete a site.
	 *
	 * @param string $shortName The name of the site to delete.
	 * @return bool true if the site was deleted; else false.
	 */
	function deleteSite($shortName) {
		if($shortName == 'default_site')
			return false;

		// Tell installed modules to delete the site
		$mm = new flModuleMgr($this->db);
		$inst = $mm->getInstalled();
		foreach($inst as $name => $ver) {
			if($instObj = $mm->getModuleInstaller($name))
				$instObj->deleteSite($this->db, $shortName);
		}

		$this->db->delete('cf_sites', 'shortname=?', $shortName);
		$this->db->query("DROP TABLE IF EXISTS cf_content_{$shortName}, cf_config_{$shortName}, cf_customflds_ctnt_{$shortName}, cf_socialimages_{$shortName}, cf_auditlog_{$shortName}");

		return true;
	}

	/**
	 * Update the information for a site.
	 *
	 * @param string $shortName The short name of the site.
	 * @param string $domain The new domain name.
	 * @param string $displayName The mew display name for the site.
	 * @param array $aliases Array of domains that map to the site as well.
	 * @param string $locale The locale for the site.
	 * @param string $editPerm The permission required to edit the site.
	 * @param string $twitterUsername Then optional twitter username to attribute the site to.
	 * @param bool $sslOnly Flags if the site can only be accessed via SSL.
	 * @return bool true if the site was updated; else false.
	 */
	function updateSite($shortName, $domain, $displayName, $aliases, $locale = 'en_US', $editPerm = '', $twitterUsername = '', $sslOnly = false) {
		if($this->db->update('cf_sites', array(
			'domain' => $domain,
			'displayname' => $displayName,
			'locale' => $locale,
			'editperm' => $editPerm,
			'twitterusername' => str_replace('@', '', $twitterUsername),
			'puressl' => $sslOnly ? 1 : 0
		), 'shortname=? && redirectto=\'\'', $shortName)) {
			// Drop the old aliases
			$this->db->delete('cf_sites', 'shortname=? && redirectto != \'\'', $shortName);

			// Create new aliases
			foreach($aliases as $d) {
				$d = trim($d);
				if(!empty($d)) {
					$this->db->insert('cf_sites', array(
						'shortname' => $shortName,
						'domain' => $d,
						'displayname' => '',
						'locale' => '',
						'editperm' => '',
						'redirectto' => ($sslOnly ? 'https://' : 'http://') . $domain
					));
				}
			}

			// Tell installed modules site locale changed
			$mm = new flModuleMgr($this->db);
			$inst = $mm->getInstalled();
			foreach($inst as $name => $ver) {
				if(($instObj = $mm->getModuleInstaller($name)) && $instObj instanceof cfInstallUpdInterface)
					$instObj->updateSite($this->db, $shortName);
			}

			return true;
		}

		return false;
	}

	/**
	 * Get a configuration object for the namespace within the site.
	 *
	 * @param string $namespace Name of the configuration data to load.
	 * @param string $site The name short name of the site.
	 * @return flConfig The configuration object.
	 */
	function getSiteCfg($namespace, $site) {
		return new flConfigDb($namespace, $this->db, "cf_config_{$site}");
	}

	/**
	 * Get the locale of a site.
	 *
	 * @param string $shortName The name of the site to get the locale of.
	 * @return string The site locale.
	 */
	function getLocale($shortName) {
		return $this->db->fetchOne('SELECT locale FROM cf_sites WHERE shortname=? && redirectto=\'\'', $shortName);
	}
}
