<?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
 */

/**
 * Deployer-Basisklasse
 *
 * Diese Klasse kapselt einige allgemeine Eigenschaften der beiden Deployer.
 *
 * @author Christoph
 * @since  2.0
 */
abstract class WV5_Deployer_Base {
	protected $files = array();  ///< array  Liste der zu verarbeitenden Dateien

	/**
	 * Konstruktor
	 *
	 * Legt einen neuen Deployer an. Dabei können direkt die zu verarbeitenden
	 * Dateien angeben werden.
	 *
	 * @param mixed $files  ein array von Dateien oder eine einzelne Datei (string)
	 */
	public function __construct($files) {
		$this->files = array_unique(sly_makeArray($files));
	}

	/**
	 * Datei hinzufügen
	 *
	 * Fügt der internen Dateiliste eine weitere Datei hinzu.
	 *
	 * @param  string $filename  der Dateiname
	 * @return int               die Anzahl der nun enthaltenen Dateien
	 */
	public function addFile($filename) {
		return $this->addFiles($filename);
	}

	/**
	 * Dateien hinzufügen
	 *
	 * Fügt der internen Dateiliste weitere Dateien hinzu.
	 *
	 * @param  array $files  die Dateinamen
	 * @return int           die Anzahl der nun enthaltenen Dateien
	 */
	public function addFiles($files) {
		$files = sly_makeArray($files);
		foreach ($files as $file) $this->files[] = $file;
		$this->files = array_unique($this->files);
		return count($this->files);
	}

	/**
	 * Cache auf Aktualität prüfen
	 *
	 * Diese Methode klappert alle Dateien der internen Liste ab und prüft, ob
	 * sie sich seit dem letzten Aufruf geändert haben. Sollte dies der Fall
	 * sein, wird der Cache von dem jeweiligen Deployer dann neu aufgebaut.
	 *
	 * Im Ergebnis-Array sind folgende Elemente enthalten:
	 *
	 * - ok (boolean; true, wenn der Cache aktuell ist, sonst false)
	 * - mtime (int; Unix-Timestamp der neuesten Datei)
	 *
	 * @param  string $hash  der Dateihash, mit dem eine Gruppe von Dateien identifiziert wird
	 * @return array         ein Array mit den Elementen 'ok' und 'mtime' (siehe Beschreibung)
	 */
	public function checkFileStatus($hash) {
		$type           = $this->getTypeString();
		$cache          = sly_Core::cache();
		$lastCompressed = $cache->get('wv5', $type.'_'.$hash, array());
		$cacheFile      = WV5_Deployment::getCacheFolder().'/compressed_'.$hash.'.'.$type;
		$everythingOK   = file_exists($cacheFile);
		$maxTimestamp   = -1;

		// Auf Änderungen prüfen und jüngste Datei ermitteln

		foreach ($this->files as $filename) {
			if (!isset($lastCompressed[$filename]) || filemtime($filename) > $lastCompressed[$filename]) {
				$everythingOK = false;
			}

			$maxTimestamp = max(filemtime($filename), $maxTimestamp);
		}

		if (!$everythingOK) {
			WV5_Deployment::setFilesChanged();
		}

		return array('ok' => $everythingOK, 'mtime' => $maxTimestamp);
	}

	/**
	 * Dateien komprimieren
	 *
	 * Diese Methode läuft über alle Dateien und ruft die entsprechende
	 * Komprimierungs-Methode des Deployers auf. Sie kapselt also die
	 * Iterator-Logik, da diese netterweise für CSS und JS identisch sein kann.
	 *
	 * @param  string  $hash   der Dateihash, mit dem eine Gruppe von Dateien identifiziert wird
	 * @param  boolean $debug  wenn true, werden die Namen der Dateien als Kommentare eingefügt
	 * @return string          der fertig komprimierte Code
	 */
	protected function compressFiles($hash, $sep = "\n", $debug = false) {
		$compressed = '';
		$filelist   = array();
		$type       = $this->getTypeString();

		foreach ($this->files as $filename) {
			if ($debug) {
				$compressed .= "\n/* $filename */\n";
			}

			if (WV5_Deployment::isMinified($filename, $type)) {
				$content = file_get_contents($filename);
			}
			else {
				$content = $this->minify($filename, $debug);
			}

			$compressed         .= trim($content).$sep;
			$filelist[$filename] = filemtime($filename);
		}

		// Änderungen merken, fertig.
		$cache = sly_Core::cache();
		$cache->set('wv5', $type.'_'.$hash, $filelist);
		return $compressed;
	}

	/**
	 * Dateien zusammenfügen und komprimieren
	 *
	 * Diese Methode führt die Verarbeitung der Dateien durch und gibt danach
	 * ein Array mit Status-Infos zurück. Eine implementierende Klasse sollte der
	 * Einfachheit halber die Methoden compressFiles() und checkFileStatus()
	 * wiederverwenden.
	 *
	 * Im Ergebnis-Array sollen folgende Elemente enthalten sein:
	 *
	 * - file (string; der Dateiname der generierten Datei)
	 * - mtime (int; Unix-Timestamp der letzten Aktualisierung)
	 * - mtime_hex (string; wie mtime, nur in lower hex)
	 * - hash (string; ein 6-stelliger Hash über die enthaltenen Dateien)
	 *
	 * @param  boolean $debug  wenn true, sollen die Namen der Dateien als Kommentare eingefügt werden
	 * @return mixed           ein Array mit den Ergebnisdaten oder false im Fehlerfalle
	 */
	abstract public function create($debug = false);

	/**
	 * Datei komprimieren
	 *
	 * Diese Methode dient dazu, eine einzelne Datei zu komprimieren. Eine
	 * Implementierung darf das Ergebnis gern cachen, um Rechenzeit zu sparen.
	 *
	 * @param  string  $filename  der Dateiname
	 * @param  boolean $debug     wenn true, sollen die Namen der Dateien als Kommentare eingefügt werden
	 * @return string             der fertig komprimierte Code
	 */
	abstract protected function minify($filename, $debug = false);

	/**
	 * @since  3.5
	 * @return string  a identifier, should be the file extension
	 */
	abstract protected function getTypeString();
}
