<?php
/*
 * $RCSfile: GalleryItemAttributesHelper_advanced.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.13 $ $Date: 2005/08/23 03:49:04 $
 * @package GalleryCore
 * @author Bharat Mediratta <bharat@menalto.com>
 */

/**
 *
 * @package GalleryCore
 * @subpackage Helpers
 */
class GalleryItemAttributesHelper_advanced {
    /**
     * Rebalance the order weights associated with this item's children.
     * When this method is complete, the child item ids should still have the
     * same order as they have now, but their order weights should be spaced
     * out to exactly the spacing value specified in the arguments.
     *
     * @param int the parent id
     * @param int the order spacing
     * @return object GalleryStatus a status code
     * @static
     */
    function rebalanceChildOrderWeights($parentItemId, $spacing=1000) {
	global $gallery;

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

	list ($ret, $ids) = GalleryCoreApi::fetchChildItemIdsIgnorePermissions($parentItem);
	if ($ret->isError()) {
 	    return $ret->wrap(__FILE__, __LINE__);
	}

	$current = $spacing;
	foreach ($ids as $id) {
	    $gallery->guaranteeTimeLimit(5);
	    $ret = GalleryItemAttributesHelper_advanced::setOrderWeight($id, $current);
	    if ($ret->isError()) {
		return $ret->wrap(__FILE__, __LINE__);
	    }
	    $current += $spacing;
	}

	return GalleryStatus::success();
    }

    /**
     * Fetch the highest or lowest weight of all children
     * @param int the parent item id
     * @param int the direction (HIGHER_WEIGHT, LOWER_WEIGHT)
     * @return array object GalleryStatus a status code
     *               int a weight
     * @static
     */
    function fetchExtremeChildWeight($itemId, $direction) {
	global $gallery;

	if ($direction == LOWER_WEIGHT) {
	    $aggregate = 'MIN';
	} else {
	    $aggregate = 'MAX';
	}

	$query = '
        SELECT
          ' . $aggregate . '([GalleryItemAttributesMap::orderWeight])
        FROM
          [GalleryItemAttributesMap], [GalleryChildEntity]
        WHERE
          [GalleryChildEntity::id] = [GalleryItemAttributesMap::itemId]
          AND
          [GalleryChildEntity::parentId] = ?
        ';
	list ($ret, $searchResults) = $gallery->search($query, array($itemId));
	if ($ret->isError()) {
	    return array($ret->wrap(__FILE__, __LINE__), null);
	}

	$result = $searchResults->nextResult();
	if (isset($result[0])) {
	    $weight = (int)$result[0];
	} else {
	    $weight = 0;
	}

	return array(GalleryStatus::success(), $weight);
    }

    /**
     * Fetch the weight of the next peer in line (higher or lower, as specified)
     *
     * @param int the item id
     * @param int the direction (HIGHER_WEIGHT, LOWER_WEIGHT)
     * @return array object GalleryStatus a status code
     *               int a weight
     * @static
     */
    function fetchNextWeight($itemId, $direction) {
	global $gallery;

	if ($direction == LOWER_WEIGHT) {
	    $aggregate = 'MAX';
	    $comparison = '<';
	} else {
	    $aggregate = 'MIN';
	    $comparison = '>';
	}

	$query = '
        SELECT
          ' . $aggregate . '([GalleryItemAttributesMap=2::orderWeight])
        FROM
          [GalleryItemAttributesMap=1], [GalleryItemAttributesMap=2],
          [GalleryChildEntity=1], [GalleryChildEntity=2]
        WHERE
          [GalleryChildEntity=1::id] = ?
          AND
          [GalleryChildEntity=1::parentId] = [GalleryChildEntity=2::parentId]
          AND
          [GalleryChildEntity=1::id] = [GalleryItemAttributesMap=1::itemId]
          AND
          [GalleryChildEntity=2::id] = [GalleryItemAttributesMap=2::itemId]
          AND
          [GalleryItemAttributesMap=2::orderWeight] ' .
		$comparison . ' [GalleryItemAttributesMap=1::orderWeight]
        ';
	list ($ret, $searchResults) = $gallery->search($query, array($itemId));
	if ($ret->isError()) {
	    return array($ret->wrap(__FILE__, __LINE__), null);
	}

	$result = $searchResults->nextResult();
	if (isset($result[0])) {
	    $weight = (int)$result[0];
	} else {
	    $weight = null;
	}

	return array(GalleryStatus::success(), $weight);
    }

    /**
     * Update the view count for this item id
     * @param int the item id
     * @param int the new count
     * @return object GalleryStatus a status code
     * @static
     */
    function setViewCount($itemId, $count) {
	GalleryCoreApi::relativeRequireOnce('modules/core/classes/GalleryItemAttributesMap.class');
	$ret = GalleryItemAttributesMap::updateMapEntry(array('itemId' => $itemId),
							array('viewCount' => $count));
	if ($ret->isError()) {
	    return $ret->wrap(__FILE__, __LINE__);
	}

	return GalleryStatus::success();
    }

    /**
     * Set the parent id sequence for an item id
     *
     * @param int id the item id
     * @param array the parent sequence (ids)
     * @return object GalleryStatus a status code
     * @static
     */
    function setParentSequence($itemId, $parentSequence) {
	if (empty($parentSequence)) {
	    $parentSequence = '';
	} else {
	    $parentSequence = join('/', $parentSequence) . '/';
	}

	GalleryCoreApi::relativeRequireOnce('modules/core/classes/GalleryItemAttributesMap.class');
	$ret = GalleryItemAttributesMap::updateMapEntry(array('itemId' => $itemId),
							array('parentSequence' => $parentSequence));
	if ($ret->isError()) {
	    return $ret->wrap(__FILE__, __LINE__);
	}

	return GalleryStatus::success();
    }

    /**
     * Create a new set of attributes for an item
     * @param int the item id
     * @param array the sequence of parent ids
     * @return object GalleryStatus a status code
     * @static
     */
    function createItemAttributes($itemId, $parentSequence) {
	if (empty($parentSequence)) {
	    $parentSequence = '';
	} else {
	    $parentSequence = join('/', $parentSequence) . '/';
	}
	GalleryCoreApi::relativeRequireOnce('modules/core/classes/GalleryItemAttributesMap.class');
	$ret = GalleryItemAttributesMap::addMapEntry(array('itemId' => $itemId,
							   'viewCount' => 0,
							   'orderWeight' => 0,
							   'parentSequence' => $parentSequence));
	if ($ret->isError()) {
	    return $ret->wrap(__FILE__, __LINE__);
	}

	return GalleryStatus::success();
    }

    /**
     * Remove the attributes for the given item
     * @param int the item id
     * @return object GalleryStatus a status code
     * @static
     */
    function removeItemAttributes($itemId) {
	GalleryCoreApi::relativeRequireOnce('modules/core/classes/GalleryItemAttributesMap.class');
	$ret = GalleryItemAttributesMap::removeMapEntry(array('itemId' => $itemId));
	if ($ret->isError()) {
	    return $ret->wrap(__FILE__, __LINE__);
	}

	return GalleryStatus::success();
    }

    /**
     * Set the order weight for an item id
     * @param int the item id
     * @param int the new order weight
     * @return object GalleryStatus a status code
     * @static
     */
    function setOrderWeight($itemId, $orderWeight) {
	GalleryCoreApi::relativeRequireOnce('modules/core/classes/GalleryItemAttributesMap.class');
	$ret = GalleryItemAttributesMap::updateMapEntry(array('itemId' => $itemId),
							array('orderWeight' => $orderWeight));
	if ($ret->isError()) {
	    return $ret->wrap(__FILE__, __LINE__);
	}

	return GalleryStatus::success();
    }

    /**
     * Get the view count for this item id
     * @param int the item id
     * @return array object GalleryStatus a status code
     *               int view count
     * @static
     */
    function fetchViewCount($itemId) {
	GalleryCoreApi::relativeRequireOnce(
	    'modules/core/classes/helpers/GalleryItemAttributesHelper_medium.class');
	list ($ret, $viewCounts) =
	    GalleryItemAttributesHelper_medium::fetchViewCounts(array($itemId));
	if ($ret->isError()) {
	    return array($ret->wrap(__FILE__, __LINE__), null);
	}

	return array(GalleryStatus::success(), $viewCounts[$itemId]);
    }

    /**
     * Update all items containing the source parent sequence to the new parent sequence
     *
     * @param int id the item id
     * @param array the parent sequence (ids)
     * @return object GalleryStatus a status code
     * @static
     */
    function updateParentSequence($oldParentSequence, $newParentSequence) {
	GalleryCoreApi::relativeRequireOnce(
	    'modules/core/classes/GalleryStorage/DatabaseSqlFragment.class');
	global $gallery;

	$oldParentSequence = join('/', $oldParentSequence) . '/';
	$newParentSequence = join('/', $newParentSequence) . '/';

	$storage =& $gallery->getStorage();
	list ($ret, $substring) = $storage->getFunctionSql('SUBSTRING', array(
		  '[GalleryItemAttributesMap::parentSequence]', strlen($oldParentSequence) + 1));
	if ($ret->isError()) {
	    return $ret->wrap(__FILE__, __LINE__);
	}
	list ($ret, $newSequenceSql) = $storage->getFunctionSql('CONCAT', array('?', $substring));
	if ($ret->isError()) {
	    return $ret->wrap(__FILE__, __LINE__);
	}

	GalleryCoreApi::relativeRequireOnce('modules/core/classes/GalleryItemAttributesMap.class');
	$ret = GalleryItemAttributesMap::updateMapEntry(
	     array('parentSequence' =>
			new DatabaseSqlFragment('LIKE ?', $oldParentSequence . '%')),
	     array('parentSequence' =>
			new DatabaseSqlFragment('=' . $newSequenceSql, $newParentSequence)));
	if ($ret->isError()) {
	    return $ret->wrap(__FILE__, __LINE__);
	}

	return GalleryStatus::success();
    }
}
?>
