<?php
/*
 * $RCSfile: GalleryAlbumItem.class,v $
 *
 * Gallery - a web based photo album viewer and editor
 * Copyright (C) 2000-2005 Bharat Mediratta
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA  02110-1301, USA.
 */
/**
 * @version $Revision: 1.49 $ $Date: 2005/08/23 03:49:02 $
 * @package GalleryCore
 * @author Bharat Mediratta <bharat@menalto.com>
 */

/**
 * Load the parent class
 */
GalleryCoreApi::relativeRequireOnce('modules/core/classes/GalleryItem.class');

/**
 * A subclass of GalleryItem for containing groups of GalleryItems
 *
 * A GalleryItem that has certain extra properties relating to
 * displaying item groups and is allowed to contain other
 * GalleryItems.
 *
 * @g2 <class-name>GalleryAlbumItem</class-name>
 * @g2 <parent-class-name>GalleryItem</parent-class-name>
 * @g2 <schema>
 * @g2   <schema-major>1</schema-major>
 * @g2   <schema-minor>1</schema-minor>
 * @g2 </schema>
 * @g2 <requires-id/>
 *
 * @package GalleryCore
 * @subpackage Classes
 */
class GalleryAlbumItem_core extends GalleryItem {
    /*
     * ****************************************
     *                 Members
     * ****************************************
     */

    /**
     * The theme to use for this item
     *
     * @g2 <member>
     * @g2   <member-name>theme</member-name>
     * @g2   <member-type>STRING</member-type>
     * @g2   <member-size>SMALL</member-size>
     * @g2 </member>
     *
     * @var string $_theme
     * @access private
     */
    var $_theme;

    /**
     * Specify the name of the field that we're using to order children
     *
     * @g2 <member>
     * @g2   <member-name>orderBy</member-name>
     * @g2   <member-type>STRING</member-type>
     * @g2   <member-size>MEDIUM</member-size>
     * @g2 </member>
     *
     * @var int $_orderBy
     * @access private
     */
    var $_orderBy;

    /**
     * Specify the order direction that we're applying to the orderBy field
     *
     * @g2 <member>
     * @g2   <member-name>orderDirection</member-name>
     * @g2   <member-type>STRING</member-type>
     * @g2   <member-size>SMALL</member-size>
     * @g2 </member>
     *
     * @var int $_orderDirection
     * @access private
     */
    var $_orderDirection;

    /*
     * ****************************************
     *                 Methods
     * ****************************************
     */

    /**
     * Create a new instance of this AlbumItem in the persistent store
     *
     * Also create the album directory on the filesystem
     *
     * @param int the id of the parent of this object
     * @return object GalleryStatus a status code
     */
    function create($parentId, $albumName) {
	global $gallery;

	if (empty($albumName) || empty($parentId)) {
	    return GalleryStatus::error(ERROR_BAD_PARAMETER, __FILE__, __LINE__);
	}

	/* Let our superclass take care of creation in the persistent store */
	$ret = parent::create($parentId, $albumName);
	if ($ret->isError()) {
	    return $ret->wrap(__FILE__, __LINE__);
	}

	$albumName = $this->getPathComponent();

	/* Albums can contain children */
	$this->setCanContainChildren(true);

	list($ret, $parent) = GalleryCoreApi::loadEntitiesById($parentId);
	if ($ret->isError()) {
	    return $ret->wrap(__FILE__, __LINE__);
	}

	list($ret, $parentPath) = $parent->fetchPath();
	if ($ret->isError()) {
	    return $ret->wrap(__FILE__, __LINE__);
	}

	/* Copy over derivative preferences from the parent */
	$ret = GalleryCoreApi::copyDerivativePreferences($parentId, $this->getId());
	if ($ret->isError()) {
	    return $ret->wrap(__FILE__, __LINE__);
	}

	list ($ret, $useDefaults) =
	    GalleryCoreApi::getPluginParameter('module', 'core', 'default.newAlbumsUseDefaults');
	if ($ret->isError()) {
	    return $ret->wrap(__FILE__, __LINE__);
	}

	if ($useDefaults != 'true') {
	    /* Use parent's settings */
	    $this->setTheme($parent->getTheme());
	    $this->setOrderBy($parent->getOrderBy());
	    $this->setOrderDirection($parent->getOrderDirection());
	}

	$ret = $this->_createDir($parentPath . $albumName);
	if ($ret->isError()) {
	    return $ret->wrap(__FILE__, __LINE__);
	}

	return GalleryStatus::success();
    }

    /**
     * Create a new root level album
     *
     * @return object GalleryStatus a status code
     */
    function createRoot() {
	global $gallery;

	/* See if we already have a root */
	list ($ret, $rootId) = GalleryCoreApi::getPluginParameter('module', 'core', 'id.rootAlbum');
	if ($ret->isError()) {
	    return $ret->wrap(__FILE__, __LINE__);
	}

	if (!empty($rootId)) {
	    return GalleryStatus::error(ERROR_COLLISION, __FILE__, __LINE__);
	}

	/* Let our superclass take care of creation in the persistent store */
	$ret = parent::createRoot();
	if ($ret->isError()) {
	    return $ret->wrap(__FILE__, __LINE__);
	}

	/* Root album can contain children */
	$this->setCanContainChildren(true);

	/* Create default preferences */
	/* XXX: parameterize this */
	$ret = GalleryCoreApi::addDerivativePreference(
	    0, $this->getId(), DERIVATIVE_TYPE_IMAGE_THUMBNAIL, 'thumbnail|150');
	if ($ret->isError()) {
	    return $ret->wrap(__FILE__, __LINE__);
	}

	$ret = GalleryCoreApi::addDerivativePreference(
	    0, $this->getId(), DERIVATIVE_TYPE_IMAGE_RESIZE, 'scale|640');
	if ($ret->isError()) {
	    return $ret->wrap(__FILE__, __LINE__);
	}

	/* Use site default theme and sort order */
	$this->setTheme('');
	$this->setOrderBy('');
	$this->setOrderDirection(ORDER_ASCENDING);

	return GalleryStatus::success();
    }

    /**
     * Internal function to create the album directory
     *
     * @access private
     */
    function _createDir($albumDir) {
	global $gallery;

	$platform = $gallery->getPlatform();

	list($ret, $perm) = GalleryCoreApi::getPluginParameter(
	    'module', 'core', 'permissions.directory');
	if ($ret->isError()) {
	    return $ret->wrap(__FILE__, __LINE__);
	}

	if ($platform->file_exists($albumDir)) {
	    return GalleryStatus::error(ERROR_COLLISION, __FILE__, __LINE__,
					$albumDir . ' already exists');
	}

	if (!$platform->mkdir($albumDir, $perm)) {
	    return GalleryStatus::error(ERROR_COLLISION, __FILE__, __LINE__,
					'mkdir failed for ' . $albumDir);
	}

	return GalleryStatus::success();
    }

    /**
     * Can this item contain other file system items?
     *
     * Always returns true -- AlbumItems contain other GalleryItems
     *
     * @return true if this item can contain other file system items
     */
    function isContainer() {
	return true;
    }

    /**
     * Delete this AlbumItem
     *
     * Delete all children and then remove the album directory
     *
     * @access public
     * @return object GalleryStatus a status code
     */
    function delete() {
	global $gallery;

	/* Delete myself from the store */
	$ret = parent::delete();
	if ($ret->isError()) {
	    return $ret->wrap(__FILE__, __LINE__);
	}

	/* Delete derivative preferences */
	$ret = GalleryCoreApi::removeDerivativePreferencesForItem($this->getId());
	if ($ret->isError()) {
	    return $ret->wrap(__FILE__, __LINE__);
	}

	/* Get my path */
	list($ret, $path) = $this->fetchPath();
	if ($ret->isError()) {
	    return $ret->wrap(__FILE__, __LINE__);
	}

	/* Remove my directory and everything in it */
	$platform = $gallery->getPlatform();

	if ($platform->file_exists($path)) {
	    if (!$platform->recursiveRmdir($path)) {
		return GalleryStatus::error(ERROR_BAD_PATH, __FILE__, __LINE__);
	    }
	}

	return GalleryStatus::success();
    }

    /**
     * Rename this album
     *
     * @access public
     * @param string the path component
     * @return object GalleryStatus a status code
     */
    function rename($newName) {
	global $gallery;

	if ($newName == $this->getPathComponent()) {
	    return GalleryStatus::success();
	}

	/*
	 * Read lock the parent so that we don't have a race condition below.
	 */
	if (GalleryCoreApi::isReadLocked($this->getParentId()) ||
		GalleryCoreApi::isWriteLocked($this->getParentId())) {
	    $lockId = null;
	} else {
	    list ($ret, $lockId) = GalleryCoreApi::acquireReadLock($this->getParentId());
	    if ($ret->isError()) {
		return $ret->wrap(__FILE__, __LINE__);
	    }
	}

	$platform = $gallery->getPlatform();

	/*
	 * Get the current path
	 */
	list($ret, $currentPath) = $this->fetchPath();
	if ($ret->isError()) {
	    return $ret->wrap(__FILE__, __LINE__);
	}

	/*
	 * Set the new path in the database.  If that succeeds then we should
	 * be ok in general.  Jump through hoops to make sure that we release
	 * our locks at the end.
	 */
	$error = null;
	$ret = parent::rename($newName);
	if ($ret->isError()) {
	    $error = $ret->wrap(__FILE__, __LINE__);
	}

	/* The parent class may have changed/sanitized the pathComponent, so get it again */
	$newName = $this->getPathComponent();

	if (!isset($error)) {
	    /* Check to see if the desired path exists. */
	    $newPath = dirname($currentPath) . '/' . $newName;
	    if ($platform->file_exists($newPath)) {
		$error = GalleryStatus::error(ERROR_COLLISION, __FILE__, __LINE__);
	    }
	}

	if (!isset($error)) {
	    if (!$platform->rename($currentPath, $newPath)) {
		$error = GalleryStatus::error(ERROR_BAD_PATH, __FILE__, __LINE__);
	    }
	}

	/* Release locks */
	$ret = GalleryCoreApi::releaseLocks($lockId);
	if ($ret->isError()) {
	    return $ret->wrap(__FILE__, __LINE__);
	}

	if (isset($error)) {
	    return $error;
	}

	return GalleryStatus::success();
    }

    /**
     * Move this item to a new parent
     *
     * @param int the id of the GalleryItem parent
     * @return object GalleryStatus a status code
     */
    function move($newParentId) {
	/* Get the current parent sequence */
	list ($ret, $oldParentSequence) = GalleryCoreApi::fetchParentSequence($this->getId());
	if ($ret->isError()) {
	    return $ret->wrap(__FILE__, __LINE__);
	}
	$oldChildParentSequence = array_merge($oldParentSequence, array($this->getId()));

	/*
	 * Perform the move.  Note that *after* the move, my parent id is going to be different so
	 * the getParentId() calls are going to return $newParentId
	 */
	$ret = parent::move($newParentId);
	if ($ret->isError()) {
	    return $ret->wrap(__FILE__, __LINE__);
	}

	/* Figure out the new one */
	list ($ret, $newParentSequence) = GalleryCoreApi::fetchParentSequence($this->getParentId());
	if ($ret->isError()) {
	    return $ret->wrap(__FILE__, __LINE__);
	}
	$newParentSequence[] = $this->getParentId();
	$newChildParentSequence = array_merge($newParentSequence, array($this->getId()));

	/* Convert my parent sequence */
	$ret = GalleryCoreApi::setParentSequence($this->getId(), $newParentSequence);
	if ($ret->isError()) {
	    return $ret->wrap(__FILE__, __LINE__);
	}

	/* Convert my children's parent sequences */
	$ret = GalleryCoreApi::updateParentSequence(
	    $oldChildParentSequence, $newChildParentSequence);
	if ($ret->isError()) {
	    return $ret->wrap(__FILE__, __LINE__);
	}

	return GalleryStatus::success();
    }

    /**
     * @see GalleryEntity::itemTypeName
     */
    function itemTypeName($localized = true) {
	global $gallery;
	if ($localized) {
	    list ($ret, $core) = GalleryCoreApi::loadPlugin('module', 'core');
	    if (! $ret->isError()) {
		return array($core->translate('Album'), $core->translate('album'));
	    }
	}
	return array('Album', 'album');
    }
}

include(dirname(__FILE__) . '/interfaces/GalleryAlbumItem.inc');
?>
