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

class sly_Controller_Devutilslogviewer extends sly_Controller_System {
	private $isPermaLink = false;

	const MAX_SIZE = 5242880; // 5 MB

	protected function init() {
		parent::init();

		if (isset($_GET['get'])) {
			$encoded = sly_get('get', 'string');
			$encoded = @gzuncompress(base64_decode($encoded));

			if (is_string($encoded) && !empty($encoded) && $encoded[0] === '{') {
				$data = json_decode($encoded, true);

				if (is_array($data)) {
					foreach ($data as $key => $value) $_GET[$key] = $value;
					$this->isPermaLink = true;
				}
			}
		}
	}

	protected function getViewFolder() {
		return DEVUTILS_PATH.'views/specials/';
	}

	private function getDirectory() {
		static $directory = null;

		if ($directory === null) {
			$directory = sly_Util_Directory::getRelative(SLY_DYNFOLDER.'/internal/sally/logs');
			$directory = sly_get('directory', 'string', $directory);
			$directory = str_replace(array('../', './', '..\\', '.\\'), '', $directory);
			$directory = sly_Util_Directory::normalize(SLY_BASE.'/'.$directory);

			if (!is_dir($directory)) {
				$directory = false;
			}
		}

		return $directory;
	}

	private function getRelative() {
		$directory = sly_Util_Directory::getRelative($this->getDirectory());
		$directory = str_replace('\\', '/', $directory);

		return $directory;
	}

	public function indexAction() {
		$this->init();

		$directory = $this->getDirectory();

		if (!$directory) {
			print sly_Helper_Message::warn('Konnte Verzeichnis '.$directory.' nicht finden.');
			return;
		}

		$dir      = new sly_Util_Directory($directory);
		$files    = $dir->listPlain(true, false);
		$logfiles = array();

		foreach ($files as $filename) {
			if (!preg_match('#\.log$#', $filename)) continue;
			$logfiles[] = $filename;
		}

		if (empty($logfiles)) {
			print sly_Helper_Message::warn('Es wurden keine Logdateien gefunden.');
			return;
		}

		$logfile = sly_get('logfile', 'string');

		if ($logfile && !in_array($logfile, $logfiles)) {
			print sly_Helper_Message::warn('Die angegebene Logdatei wurde nicht gefunden.');
			return;
		}

		$directory = $this->getRelative();
		$format    = sly_Core::dispatcher()->filter('WV_DEVUTILS_LOG_FORMAT', $logfile);

		if ($format == $logfile) {
			$format = '\[(?P<date>....-..-..) (?P<time>..:..:..)\] (?P<type>.*?): (?P<message>.*)';
		}

		$reverse   = sly_get('reverse', 'boolean');
		$view      = $this->isPermaLink ? 'view.phtml' : 'form.phtml';
		$fullfile  = $logfile ? $dir.'/'.$logfile : '';
		$lines     = $logfile ? $this->getLines($fullfile, $format, 0, 50, $reverse) : array();
		$params    = compact('logfiles', 'dir', 'directory', 'format', 'reverse', 'logfile', 'fullfile', 'lines');

		print $this->render($view, $params);
	}

	public function ajaxAction() {
		$this->init();

		$offset    = sly_get('offset', 'int');
		$logfile   = sly_get('logfile', 'string');
		$directory = $this->getDirectory();
		$fullfile  = $directory.'/'.$logfile;
		$format    = sly_get('format', 'string');
		$reverse   = sly_get('reverse', 'boolean');
		$lines     = $this->getLines($fullfile, $format, $offset, 50, $reverse);

		while (ob_get_level()) ob_end_clean();
		ob_start('ob_gzhandler');

		header('Content-Type: application/json; charset=UTF-8');
		print json_encode($lines);
		die;
	}

	private function getLines($logfile, $format, $offset = 0, $max = 50, $reverse = false) {
		if (filesize($logfile) > self::MAX_SIZE) {
			return filesize($logfile);
		}

		$lines = array();
		$fp    = fopen($logfile, 'r');
		$i     = 0;

		while ($fp && !feof($fp)) {
			$line = fgets($fp, 8192);

			if (!preg_match('#^'.$format.'$#is', $line, $match)) {
				continue;
			}

			foreach ($match as $key => $value) {
				if (is_int($key)) unset($match[$key]);
			}

			if (!$reverse) {
				if ($i >= $offset && $i < ($offset+$max)) {
					$lines[] = $match;
				}

				++$i;

				if ($i === ($offset+$max)) break;
			}
			else {
				$lines[] = $match;
			}
		}

		@fclose($fp);

		if ($reverse) {
			$lines = array_slice(array_reverse($lines), $offset, $max);
		}

		return $lines;
	}
}
