<?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');
	
		$checkCount = 0;
		$query = 'SELECT DISTINCT `%3$s` FROM `%1$s`.`%2$s`
			WHERE `%3$s` IS NOT NULL AND `%3$s` != \'\'';

		$dir = opendir($this->dataDir);
		
		if ($dir)
		while ($schema = readdir($dir))
		if (!in_array($schema, ['.', '..'])) {
			$info = $this->util->loadInfo($schema);
			$schemaPath = "{$this->dataDir}/$schema";
			
			// Deletes unreferenced schemas.
			
			if (!isset($info)) {
				$this->moveTrash($schema);
				continue;
			}

			// Deletes unreferenced sizes.

			$schemaDir = opendir($schemaPath);

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

			// Gets a list of referenced images from the database.

			$result = $db->query(sprintf($query
				,$info['schema']
				,$info['table']
				,$info['column']
			));
			
			if (!$result)
				continue;

			$map = [];

			while ($row = $result->fetch_row()) {
				$map[$row[0]] = TRUE;
				$checkCount++;
			}

			$result->free();

			// Deletes unreferenced images.
			
			$this->cleanImages($schema, 'full', $map);

			foreach ($info['sizes'] as $size => $i)
				$this->cleanImages($schema, $size, $map);
		}

		echo "Syncronization finished.\n";
	}
	
	function cleanImages($schema, $size, &$map) {
		$sizePath = "{$this->dataDir}/$schema/$size";
		
		if (!is_dir($sizePath))
			return;
		
		$iter = new DirectoryIterator($sizePath);

		for (; $iter->valid(); $iter->next())
		if (!$iter->isDir() && strripos($iter->getFilename(), '.png', -4) !== FALSE) {
			$name = substr($iter->getFilename(), 0, -4);

			if (!isset($map[$name]))
				$this->moveTrash("$schema/$size/". $iter->getFilename());
		}
	}
	
	/**
	 * Moves a data directory to the trash.
	 *
	 * @param string $file The file to move to the trash
	 */
	function moveTrash($file) {
		$trashBasedir = "{$this->dataDir}/.trash/". $this->trashSubdir;
		$trashdir = "$trashBasedir/". dirname($file);
	
		if (!is_dir($trashdir))
			mkdir($trashdir, 0775, TRUE);

		rename(
			"{$this->dataDir}/$file",
			"$trashBasedir/$file"
		);
	}
}