<?php
/*****************************************************************************
 * Download.php
 * Contains the code to download an album.
 *
 * Kabuki CMS (C) 2013-2019, Aaron van Geffen
 *****************************************************************************/

class Download extends HTMLController
{
	public function __construct()
	{
		// Ensure we're logged in at this point.
		$user = Registry::get('user');
		if (!$user->isLoggedIn())
			throw new NotAllowedException();

		if(!isset($_GET['tag']))
			throw new UnexpectedValueException('Must specify an album to download');

		$tag = (int)$_GET['tag'];
		$album = Tag::fromId($tag);

		if($album->kind !== 'Album')
			throw new UnexpectedValueException('Specified tag does not correspond to an album');

		//Yes TOCTOU but it does not need to be perfect.
		$lock_file = join('/', array(sys_get_temp_dir(), 'pics-export.lock'));
		if(!file_exists($lock_file))
		{
			try
			{
				$fp = fopen($lock_file, 'x');

				if(!$fp)
					throw new UnexpectedValueException('Could not open lock-file');
					
				$this->exportAlbum($album);
			}
			finally
			{
  			fclose($fp);
				unlink($lock_file);
			}
		}
		else
			throw new UnexpectedValueException('Another export is busy, please try again later');

		exit();
	}

	private function exportAlbum($album)
	{
		$files = array();

		$album_ids = array_merge(array($album->id_tag), $this->getChildAlbumIds($album->id_tag));
		foreach($album_ids as $album_id)
		{
			$iterator = AssetIterator::getByOptions(
				array(
					'id_tag' => $album_id
				)
			);
			while($asset = $iterator->Next())
			{
				$files[] = join(DIRECTORY_SEPARATOR, array('.', $asset->getSubdir(), $asset->getFilename()));
			}
		}

		$descriptorspec = array(
			0 => array('pipe', 'r'),
			1 => array('pipe', 'w'),
		);

		$command = 'tar --null -cf - -T -';

		$proc = proc_open($command, $descriptorspec, $pipes, ASSETSDIR);

		if(!$proc)
			throw new UnexpectedValueException('Could not execute TAR command');

		if(!$pipes[0])
			throw new UnexpectedValueException('Could not open pipe for STDIN');

		if(!$pipes[1])
			throw new UnexpectedValueException('Could not open pipe for STDOUT');

		$album_name = $album->tag;

		header('Pragma: no-cache');
		header('Content-Description: File Download');
		header('Content-disposition: attachment; filename="' . $album_name . '.tar"');
		header('Content-Type: application/octet-stream');
		header('Content-Transfer-Encoding: binary');

		foreach($files as $file)
			fwrite($pipes[0], $file . "\0");

		fclose($pipes[0]);

		while($chunk = stream_get_contents($pipes[1], 4096))
			echo $chunk;

		fclose($pipes[1]);

		proc_close($proc);
	}

	private function getChildAlbumIds($parent_id)
	{
		$ids = array();

		$albums = Tag::getAlbums($parent_id, 0, PHP_INT_MAX, 'object');
		foreach($albums as $album)
		{
			$ids[] = $album->id_tag;
			$ids = array_merge($ids, $this->getChildAlbumIds($album->id_tag));
		}

		return $ids;
	}
}