<?php
/*
 * Copyright (c) 2013, 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
 */

/**
 * @defgroup external  Externe, öffentliche API
 * @defgroup internal  Interne API
 * @defgroup system    systemnahe Funktionen
 * @defgroup objects   Objekt-Abstraktion
 */

/**
 * Hilfsklasse für das Addon
 *
 * Diese Klasse stellt eine Hand voll Methoden für die einzelnen Module dieses
 * Addons zur Verfügung.
 *
 * Diese Klasse ist nicht als öffentliche API gedacht, dafür gibt es
 * WV2_MetaProvider. Außerhalb des AddOns sollte sie daher *nicht* verwendet
 * werden. Die hier definierten Konstanten sind natürlich für jeden da, der ein
 * Interesse an ihnen hat ;-)
 *
 * @ingroup external
 */
abstract class WV2_Metainfo {
	const TYPE_ARTICLE  = 0; ///< int  Metainfo-Typ für Artikel
	const TYPE_CATEGORY = 1; ///< int  Metainfo-Typ für Kategorien
	const TYPE_MEDIUM   = 2; ///< int  Metainfo-Typ für Medien
	const TYPE_USER     = 3; ///< int  Metainfo-Typ für Benutzer

	public static function clearDataCache() {
		sly_Core::cache()->flush('metainfo', true);
	}

	public static function clearAllCaches() {
		self::clearDataCache();
	}

	/**
	 * Hilfsmethode zu den Benutzerrechten
	 *
	 * Diese Methode ermittelt, ob der aktuelle Benutzer das angegebene Recht
	 * hat.
	 *
	 * @param  string $right  das Benutzerrecht (nur MetaInfo-Rechte!)
	 * @return bool           true, wenn das Recht vorhanden ist, sonst false
	 */
	public static function isAllowed($right) {
		return _WV2_Metainfo::isAllowed($right);
	}

	/**
	 * Ermitteln einer Objekt-ID
	 *
	 * Diese Methode ermittelt zu einem Objekt die dazugehörige ID.
	 *
	 * @param  mixed $object     int, null, sly_Model_Article, sly_Model_Category, sly_Model_Medium, sly_Model_User
	 * @param  bool  $allowNull  wenn true, wird für $object = null auch null zurückgegeben
	 * @return int               die ID oder -1 falls keine gefunden wurde
	 */
	public static function getIDForObject($object, $allowNull = true) {
		if ($object === null && $allowNull) return null; /* <- bedeutet im MetaProvider: "gib mir alle Metainfos!" */
		if (sly_Util_String::isInteger($object)) return (int) $object; /* <- Artikel, Kategorie, Medium, Benutzer? Keine Ahnung. */
		if ($object instanceof sly_Model_Article) return (int) $object->getId();
		if ($object instanceof sly_Model_Category) return (int) $object->getId();
		if ($object instanceof sly_Model_Medium) return (int) $object->getId();
		if ($object instanceof sly_Model_User) return (int) $object->getId();
		trigger_error(t('metainfo_cant_identify_object', $object, gettype($object)), E_USER_WARNING);
		return -1;
	}

	/**
	 * Objekt erzeugen
	 *
	 * Diese Methode erzeugt für eine ID, eine Sprache und einen bestimmten Typ
	 * das dazugehörige Objekt (sly_Model_Article, sly_Model_Category oder
	 * OOMedia). Damit sind alle Methoden des AddOns von der lästigen Arbeit, ein
	 * 5-Zeilen-switch zu schreiben, befreit.
	 *
	 * @see    getTypeForObject
	 * @throws WV2_Exception falls der Typ nicht erkannt wurde
	 *
	 * @param  int $id     die ID des Objekts
	 * @param  int $clang  die Sprache des Objekts (für OOMedia irrelevant)
	 * @param  int $type   der Typ des Objekts
	 * @return object      ein passendes Objekt
	 */
	public static function getObject($id, $clang = null, $type = self::TYPE_ARTICLE) {
		$id    = (int) $id;
		$clang = WV_Sally::clang($clang);

		switch ($type) {
			case self::TYPE_ARTICLE:  return sly_Util_Article::findById($id, $clang);
			case self::TYPE_CATEGORY: return sly_Util_Category::findById($id, $clang);
			case self::TYPE_MEDIUM:   return sly_Util_Medium::findById($id);
			case self::TYPE_USER:     return sly_Util_User::findById($id);
		}

		throw new WV2_Exception(t('metainfo_unkown_object_type', $type));
	}

	/**
	 * Typ ermitteln
	 *
	 * Diese Methode ermittelt für ein bestehendes Objekt die entsprechende
	 * Typ-Konstante.
	 *
	 * Wird das Objekt nicht erkannt, wird mit einem E_USER_ERROR die Ausführung
	 * des Scripts angehalten.
	 *
	 * @see    getObject
	 * @throws WV2_Exception  falls das Objekt nicht erkannt wurde
	 *
	 * @param  object $obj  das Objekt, dessen Typ ermittelt werden soll
	 * @return int          die Typ-ID des Objekts
	 */
	public static function getTypeForObject($obj) {
		if ($obj instanceof sly_Model_Article)  return self::TYPE_ARTICLE;
		if ($obj instanceof sly_Model_Category) return self::TYPE_CATEGORY;
		if ($obj instanceof sly_Model_Medium)   return self::TYPE_MEDIUM;
		if ($obj instanceof sly_Model_User)     return self::TYPE_USER;

		throw new WV2_Exception(t('metainfo_unkown_object'));
	}

	/**
	 * @deprecated since 5.9, use WV_Sally::clang()
	 */
	public static function resolveClang($clang) {
		return WV_Sally::clang($clang);
	}

	public static function loadAll($forceRefresh = false) {
		static $properties = null;

		if ($properties === null || $forceRefresh) {
			$config    = sly_Core::config();
			$metainfos = $config->get('metainfo', array());
			$cacheFile = sly_Util_AddOn::internalDirectory('webvariants/metainfo').'/metainfos.php';
			$oldState  = null;

			if (file_exists($cacheFile)) {
				include $cacheFile;
				$oldState = $known;
			}

			$service    = new _WV2_Service_Property();
			$properties = $service->loadFromArray($metainfos, $oldState);

			if ($oldState !== $metainfos) {
				file_put_contents($cacheFile, '<?php $known = '.var_export($metainfos, true).';');
			}
		}

		return $properties;
	}

	public static function getMetainfo($name, $type) {
		$all = WV2_MetaProvider::getAllObjectMetaInfos((int) $type);

		if (!isset($all[$name])) {
			throw new WV2_Exception(t('metainfo_not_found', $name));
		}

		return $all[$name];
	}
}
