<?php
/*
 * Copyright (c) 2012, webvariants GbR, http://www.webvariants.de
 *
 * This file is released under the terms of the MIT license. You can find the
 * complete text in the attached LICENSE file or online at:
 *
 * http://www.opensource.org/licenses/mit-license.php
 */

/**
 * Öffentliche API
 *
 * @author Christoph
 * @since  forever
 */
abstract class WV24_RealURL2 {
	protected static $disabledBaseTag = false;  ///< boolean

	const URL_NAMESPACE = 'sally.article';

	/**
	 * URL für einen Artikel ermitteln
	 *
	 * Diese Methode sollte man aufrufen, wenn man für einen Artikel die URL
	 * ermitteln möchte. Sie führt ein entsprechendes Caching durch und wird
	 * automatisch generateURL() aufrufen, sollte die URL noch nicht im Cache
	 * liegen.
	 *
	 * @param  mixed   $article      null für den aktuellen Artikel, ansonsten irgendwas als Artikel identifizierbares
	 * @param  int     $clang        die Sprach-ID
	 * @param  array   $params       GET-Parameter als assoziatives Array
	 * @param  string  $divider      das Trennzeichen für den Query-String
	 * @param  boolean $forceDomain  wenn true, wird immer eine Domain-Angabe ("http://.../") erzeugt (andernfalls nur, wenn nötig)
	 * @return string                die fertige URL für den Artikel (i.d.R. absolut zur Domain)
	 */
	public static function getURL($article = null, $clang = null, $params = array(), $divider = '&amp;', $forceDomain = false) {
		$clang = $clang === null ? sly_Core::getCurrentClang() : (int) $clang;

		if ($article instanceof sly_Model_Base_Article) {
			$articleID = $article->getId();
		}
		else {
			$articleID = (int) $article;
		}

		$ident = $articleID.'_'.$clang;
		$url   = _WV24_Cache::findURL(self::URL_NAMESPACE, $ident);

		if ($url === null) {
			$storage = WV24_Util::getStorage();
			$urls    = $storage->findByIdent(self::URL_NAMESPACE, $ident, false, true);

			if (!empty($urls)) {
				$url = reset($urls);
				_WV24_Cache::cacheURL($url);
			}
		}

		if ($url) {
			return $url->getURL($params, $divider, $forceDomain);
		}

		// nothing found, generate the URL from scratch
		$article = sly_Util_Article::findById($articleID, $clang);

		if ($article === null) {
			throw new Exception('Invalid article '.$articleID.'/'.$clang.' given!');
		}

		$path = $article->getPath();

		// prewarm a cache
		// Since this should only happen in very rare cases, it's okay to use a
		// non-global cache that will not be used for the next ::getURL() call.
		$runtimeCache = new _WV24_RuntimeCache();
		$runtimeCache->prewarmForArticle($articleID, $clang, $article->getPath());

		// get a generator
		$generator = new _WV24_Generator($runtimeCache);
		$url       = $generator->buildUrl($articleID, $clang);

		// store the new URL
		$storage = WV24_Util::getStorage();
		$url     = $storage->setUrl(self::URL_NAMESPACE, $ident, $url, $articleID, $clang, $path);

		// done!
		return $url->getURL($params, $divider, $forceDomain);
	}

	/**
	 * Cache leeren
	 *
	 * Diese Methode leert den gesamten Cache.
	 */
	public static function clearCache() {
		$cache = sly_Core::cache();
		$cache->flush('realurl2', true);
	}

	/**
	 * Finds the list of domains that are managed with realURL2.
	 *
	 * @return array  a list with the domains
	 */
	public static function getDomains($addWwwAlternatives = false) {
		$cache = sly_Core::cache();
		$key   = 'domain_fragments';
		$data  = $cache->get('realurl2.volatile', $key);

		if ($data === null) {
			$sql       = WV_SQL::getInstance();
			$query     = 'SELECT DISTINCT wv24_fragment FROM ~article WHERE wv24_fragment LIKE "//%"';
			$fragments = $sql->getArray($query, null, '~');

			foreach (WV24_Util::getDefaultFragments() as $fragment) {
				$fragments[] = $fragment;
			}

			foreach ($fragments as $fragment) {
				$data[] = WV24_Util::getDomainFromFragment($fragment);
			}

			$data = array_unique($data);
			$cache->set('realurl2.volatile', $key, $data);
		}

		if ($addWwwAlternatives) {
			$result = array();

			foreach ($data as $domain) {
				$result[] = $domain;
				$result[] = self::getWwwAlternative($domain);
			}

			$data = $result;
		}

		return $data;
	}

	/**
	 * URL dekodieren
	 *
	 * Diese Methode versucht zu einer gegebenen URL den dazugehörigen Artikel
	 * zu ermitteln. Ggf. wird statt einer Core-URL auch eine API-erzeugte
	 * Route gefunden. Es wird dabei, falls die URL nicht auf einen Slash endet,
	 * auch noch die Variante mit einem angefügten Slash gesucht.
	 *
	 * Der Rückgabewert ist ein assoziatives Array mit allen Feldern aus der
	 * jeweiligen Cache-Tabelle der Datenbank.
	 *
	 * @param  string $url  die zu dekodierende URL
	 * @return _WV24_URL    null, falls die URL nicht gefunden wurde, sonst eine URL
	 */
	public static function decodeURL($url) {
		$cache    = sly_Core::cache();
		$resolver = new _WV24_Resolver(WV24_Util::getStorage(), $cache);

		return $resolver->resolveUrl($url);
	}

	/**
	 * @param  boolean $xhtml            true to get self-closing tag, else false
	 * @param  boolean $disableAutoTags  true to disable auto insertion of <base> tag in OUTPUT_FILTER
	 * @return string
	 */
	public static function getBaseTag($xhtml = true, $disableAutoTags = true) {
		$base = sly_Util_HTTP::getBaseUrl(true).'/';

		if ($disableAutoTags) {
			self::disableAutoBaseTag();
		}

		return '<base href="'.$base.'"'.($xhtml ? ' /' : '').'>';
	}

	public static function enableAutoBaseTag() {
		self::$disabledBaseTag = false;
	}

	public static function disableAutoBaseTag() {
		self::$disabledBaseTag = true;
	}

	/**
	 * @return boolean
	 */
	public static function doBaseTag() {
		return !self::$disabledBaseTag;
	}
}
