<?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->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"
		);
	}
}

