<?php

require_once(__DIR__.'/util.php');

/**
 * Syncronizes the data directory with the database, this may take some time.
 */
class Sync extends Vn\Lib\Method {
	private $trashSubdir;
	private $util;

	function __construct($app) {
		parent::__construct($app);
		$this->util = new Util($app);
		$this->dataDir = $this->util->dataDir;
	}

	function run($db) {
		$db = $this->getSysConn();
	
		set_time_limit(0);
		$this->trashSubdir = date('YmdHis');
	
		$deleteCount = 0;
		$dir = opendir($this->dataDir);

		if ($dir)
		while ($collection = readdir($dir))
		if (!in_array($collection, ['.', '..', '.trash'])) {
			$info = $this->util->loadInfo($collection);
			$collectionPath = "{$this->dataDir}/$collection";

			// Deletes unreferenced collections.

			if (!isset($info)) {
				$this->recycle($collection);
				continue;
			}

			// Deletes unreferenced sizes.

			$collectionDir = opendir($collectionPath);

			if ($collectionDir)
			while ($size = readdir($collectionDir))
			if (!in_array($size, ['.', '..', 'full'])
			&& !isset($info['sizes'][$size]))
				$this->recycle("$collection/$size");

			// Deletes unreferenced images.

			try {
				$db->query('START TRANSACTION');
				$res = $db->query(
					'SELECT id, `name`, collectionFk
						FROM `image`
						WHERE nRefs = 0 AND collectionFk = #collection
						FOR UPDATE',
					['collection' => $collection]
				);

				if ($res->num_rows == 0) continue;
				echo "Recycling {$res->num_rows} images from collection '$collection'.\n";

				while ($image = $res->fetch_object())
				if (!empty($image->name) && !in_array($image->name, ['.', '..'])) {
					$deleteCount++;
					$this->recycle("$collection/full/{$image->name}.png");

					foreach ($info['sizes'] as $size => $i)
						$this->recycle("$collection/$size/{$image->name}.png");

					$db->query(
						'DELETE FROM `image`
							WHERE nRefs = 0 AND id = #id',
						['id' => $image->id]
					);
				}

				$res->free();
				$db->query('COMMIT');
			} catch(Exception $e) {
				$db->query('ROLLBACK');
				throw $e;
			}
		}
	
		echo "Total $deleteCount images moved to trash.\n";
		echo "Syncronization finished.\n";
	}
	
	/**
	 * Moves data file to trash.
	 *
	 * @param string $file File or directory to move
	 */
	function recycle($file) {
		$filePath = "{$this->dataDir}/$file";
		if (!file_exists($filePath)) return;

		$trashBasedir = "{$this->dataDir}/.trash/". $this->trashSubdir;
		$trashdir = "$trashBasedir/". dirname($file);
	
		if (!is_dir($trashdir))
			mkdir($trashdir, 0775, TRUE);

		rename(
			"$filePath",
			"$trashBasedir/$file"
		);
	}
}
