<?php

require_once('util.php');
require_once('comment.php');

class pb_Media {
    public static $TYPE_PICTURE = 0;
    public static $TYPE_MOVIE = 1;
    public static $TYPE_TEXT = 2;

    public static $TYPE_TO_STR;// = array(0 => 'picture', 1 => 'movie', 2 => 'text');
    public static $TYPE_TO_EXT;// = array(0 => '.jpg', 1 => '.flv', 2 => '.txt');
    public static $STR_TO_TYPE;// = array_flip(pb_Media::$TYPE_TO_STR);

    protected $id;
    protected $type = 0;
    protected $filename = NULL;
    protected $date = NULL;
    protected $repositoryId = 0;
    protected $userId = 0;
    protected $location = NULL;
    protected $description = NULL;
    protected $publicationDate = NULL;
    protected $commentCount = 0;

	/*
	 * Missing information:
	 * when: date
	 * where: latitude, longitude, altitude
	 * who: people
	 */
    /*
     * See http://en.wikipedia.org/wiki/Geotagging
     * Decimal degrees with negative numbers for South and West.
     * 41.89028; 12.49248
     */
    public function __construct($type, $filename, $date, $userId, $repositoryId, $location = NULL, $description = NULL, $publicationDate = NULL, $commentCount = 0) {
        $this->id = -1;
        $this->type = $type;
        $this->repositoryId = $repositoryId;
        $this->filename = $filename;
        $this->date = $date;
        $this->location = ($location == NULL) ? '' : $location;
        $this->userId = $userId;
        $this->commentCount = ($commentCount < 0) ? 0 : $commentCount;
        $this->description = ($description == NULL) ? '' : $description;
        $this->publicationDate = ($publicationDate == NULL) ? time() : $publicationDate;
    }
	public function getId() {
        return $this->id;
    }
	public function setId($id) {
        $this->id = $id;
    }
    public function getType() {
        return $this->type;
    }
    public function setType($type) {
        $this->type = $type;
    }
    public function getRepositoryId() {
        return $this->repositoryId;
    }
    public function setRepositoryId($repositoryId) {
        $this->repositoryId = $repositoryId;
    }
	public function getFilename() {
        return $this->filename;
    }
	public function setFilename($filename) {
        $this->filename = $filename;
    }
    public function getLocation() {
        return $this->location;
    }
    public function setLocation($location) {
        $this->location = $location;
    }
	public function getDate() {
        return $this->date;
    }
	public function setDate($date) {
        $this->date = $date;
    }
	public function getUserId() {
        return $this->userId;
    }
	public function setUserId($userId) {
        $this->userId = $userId;
    }
	public function getDescription() {
        return $this->description;
    }
	public function setDescription($description) {
        $this->description = $description;
    }
	public function getPublicationDate() {
        return $this->publicationDate;
    }
	public function setPublicationDate($publicationDate) {
        $this->publicationDate = $publicationDate;
    }
	public function getCommentCount() {
        return $this->commentCount;
    }
	public function setCommentCount($commentCount) {
        $this->commentCount = $commentCount;
    }
    public function getMediaFolder() {
        return pb_Repository::getFolderById($this->getRepositoryId()) . '/' . date('Y', $this->getDate());
    }
    public function getMiniFolder() {
        return $this->getMediaFolder() . '/mini';
    }
	public function getExtension() {
        if (array_key_exists($this->type, pb_Media::$TYPE_TO_EXT)) {
            return pb_Media::$TYPE_TO_EXT[$this->type];
        }
        return '';
    }
    public function getMediaPath() {
        return $this->getMediaFolder() . sprintf('/%03d', $this->getId()) . $this->getExtension();
    }
    public function getMiniPath() {
        return $this->getMiniFolder() . sprintf('/%03d.jpg', $this->getId());
    }
	public function insert() {
        $connection = Helper::getInstance()->getSQL();
        $connection->executef('INSERT INTO ' . DB_PREFIX . 'MEDIA (ID, TYPE, FILENAME, DATE, REPOSITORY_ID, USER_ID, LOCATION, DESCRIPTION, PUBLICATION_DATE, COMMENT_COUNT)'
            . ' VALUES(%d, %d, \'%s\', ' . sql_Connection::fromTimestamp('%d') . ', \'%s\', \'%s\', \'%s\', \'%s\', ' . sql_Connection::fromTimestamp('%d') . ', %d)',
            $this->getId(), $this->type, $this->filename, $this->date, $this->repositoryId, $this->userId, $this->location, $this->description, $this->publicationDate, $this->commentCount);
        if ($connection->getUpdateCount() != 1) {
            throw new Exception("Database failure");
        }
    }
    public function delete() {
        if ($this->id == NULL) {
            throw new Exception('Invalid id');
        }
        $connection = Helper::getInstance()->getSQL();
        $connection->executef('DELETE FROM ' . DB_PREFIX . 'MEDIA WHERE ID=%d', $this->id);
        if ($connection->getUpdateCount() != 1) {
            throw new Exception('Database failure');
        }
        pb_Comment::deleteByMediaId($this->id);
        $mediafolder = PB_PATH . $this->getFolder();
        if ((! unlink($this->getMediaPath())) ||
                (! unlink($this->getMiniPath()))) {
            throw new Exception('Cannot delete media');
        }
    }
	public function store($upfile, $upmini = NULL) {
        if (! Helper::mkdir($this->getMediaFolder())) {
            throw new Exception("Cannot create the media directory");
        }
        $upfile->moveTo($this->getMediaPath());
        if ($upmini != NULL) {
            if (! Helper::mkdir($this->getMiniFolder(), 0777)) {
                throw new Exception("Cannot create the media directory");
            }
            $upmini->moveTo($this->getMiniPath());
        }
    }
    public function create($file, $mini = NULL) {
        $connection = Helper::getInstance()->getSQL();
        $connection->begin();
        try {
            $this->setId(pb_Media::newId());
            $this->store($file, $mini);
            $this->insert();
            $connection->commit();
        }
        catch(Exception $e) {
            $connection->rollback();
            throw $e;
        }
    }
    public static function newId() {
        $connection = Helper::getInstance()->getSQL();
        if (! $connection->isInTransaction()) {
            throw new Exception("No transaction available");
        }
        $connection->executef('SELECT ID FROM ' . DB_PREFIX . 'MEDIA_ID');
        $rs = $connection->getResultSet();
        if (! $rs->next()) {
            throw new Exception("Database failure");
        }
        $object = $rs->getRowObject();
        $connection->executef('UPDATE ' . DB_PREFIX . 'MEDIA_ID SET ID=ID+1');
        if ($connection->getUpdateCount() != 1) {
            throw new Exception("Database failure");
        }
        return $object->ID;
    }
    public static function addComment($id) {
        $connection = Helper::getInstance()->getSQL();
        $connection->executef('UPDATE ' . DB_PREFIX . 'MEDIA SET COMMENT_COUNT=COMMENT_COUNT+1 WHERE ID=%d', $id);
        if ($connection->getUpdateCount() != 1) {
            throw new Exception("Database failure");
        }
    }
    public static function removeComment($id) {
        $connection = Helper::getInstance()->getSQL();
        $connection->executef('UPDATE ' . DB_PREFIX . 'MEDIA SET COMMENT_COUNT=COMMENT_COUNT-1 WHERE ID=%d', $id);
        if ($connection->getUpdateCount() != 1) {
            throw new Exception("Database failure");
        }
    }
    public static function createFromResultSet($rs) {
        $object = $rs->getRowObject();
        $media = new pb_Media($object->TYPE, $object->FILENAME, $object->DATE, $object->USER_ID, $object->REPOSITORY_ID,
        	$object->LOCATION, $object->DESCRIPTION, $object->PUBLICATION_DATE, $object->COMMENT_COUNT);
        $media->setId($object->ID);
        return $media;
    }
    public static function getSelectionFields() {
        return 'ID, TYPE, FILENAME, ' . sql_Connection::toTimestamp('DATE') . ', USER_ID, REPOSITORY_ID, LOCATION, DESCRIPTION, ' .
        	sql_Connection::toTimestamp('PUBLICATION_DATE') . ', COMMENT_COUNT';
    }
    public static function fetchFromId($id) {
        $connection = Helper::getInstance()->getSQL();
        $connection->executef('SELECT ' . pb_Media::getSelectionFields() . ' FROM ' . DB_PREFIX . 'MEDIA WHERE ID=%d', $id);
        $rs = $connection->getResultSet();
        if (! $rs->next()) {
            return NULL;
        }
        return pb_Media::createFromResultSet($rs);
    }
    public static function getLastPublicationDate() {
        $connection = Helper::getInstance()->getSQL();
        $connection->executef('SELECT ' . sql_Connection::toTimestamp('MAX(PUBLICATION_DATE)', 'MAX_DATE') . ' FROM ' . DB_PREFIX . 'MEDIA');
        $rs = $connection->getResultSet();
        if (! $rs->next()) {
            return NULL;
        }
        $object = $rs->getRowObject();
        return $object->MAX_DATE;
    }
    public static function initializeTable() {
        $connection = Helper::getInstance()->getSQL();
        $connection->execute('DROP TABLE IF EXISTS ' . DB_PREFIX . 'MEDIA_ID');
        $connection->execute('CREATE TABLE ' . DB_PREFIX . 'MEDIA_ID (ID bigint(20) unsigned NOT NULL default \'0\')');
        $connection->execute('INSERT INTO ' . DB_PREFIX . 'MEDIA_ID (ID) VALUES(1)');
        $connection->execute('DROP TABLE IF EXISTS ' . DB_PREFIX . 'MEDIA');
        $connection->execute('CREATE TABLE ' . DB_PREFIX . 'MEDIA (' .
            'ID bigint(20) unsigned NOT NULL default \'0\', ' .
            'TYPE int(3) NOT NULL default \'0\', ' .
            'FILENAME varchar(256) NOT NULL default \'\', ' .
            'DATE datetime NOT NULL default \'0000-00-00 00:00:00\', ' .
            'USER_ID bigint(20) unsigned NOT NULL, ' .
            'REPOSITORY_ID bigint(20) unsigned NOT NULL, ' .
            'LOCATION varchar(32) NOT NULL default \'\', ' .
            'DESCRIPTION varchar(1024) NOT NULL default \'\', ' .
            'PUBLICATION_DATE datetime NOT NULL default \'0000-00-00 00:00:00\', ' .
            //'TAGS varchar(256) NOT NULL default \'\', ' .
            //'PEOPLE varchar(256) NOT NULL default \'\', ' .
            'COMMENT_COUNT int(11) NOT NULL default \'0\', ' .
            'PRIMARY KEY (ID)' .
        ') CHARACTER SET utf8 COLLATE utf8_bin');
    }
}

pb_Media::$TYPE_TO_STR = array(0 => 'picture', 1 => 'movie', 2 => 'text');
pb_Media::$TYPE_TO_EXT = array(0 => '.jpg', 1 => '.flv', 2 => '.txt');
pb_Media::$STR_TO_TYPE = array_flip(pb_Media::$TYPE_TO_STR);

function media_add($exchange) {
    $request = $exchange->getRequest();
    $date = $request->getAttribute('date'); // as unix timestamp
    $description = $request->getAttribute('description');
    $typeValue = $request->getAttribute('type');
    $repositoryId = sxe_Server::getDOMElementAttribute($request, 'repositoryId', NULL);
    $location = sxe_Server::getDOMElementAttribute($request, 'location', NULL);
    $name = sxe_Server::getDOMElementAttribute($request, 'name', NULL);
    $miniKey = sxe_Server::getDOMElementAttribute($request, 'miniKey', 'mini');
    $localFile = sxe_Server::getDOMElementAttribute($request, 'localFile', NULL);
    $authUser = $exchange->getServer()->getContextKey('user');
    if ($repositoryId == NULL) {
        throw new Exception('Repository id ' . $repositoryId . ' not found');
    }
    // TODO Check repo exists and user subscribes?
    if (! array_key_exists($typeValue, pb_Media::$STR_TO_TYPE)) {
        throw new Exception('Invalid type "' + $typeValue + '"');
    }
    $type = pb_Media::$STR_TO_TYPE[$typeValue];
    $publicationDate = time();
    $userId = $authUser->getId();
    if ($localFile == NULL) {
        $fileKey = sxe_Server::getDOMElementAttribute($request, 'fileKey', 'file');
        $file = util_UploadedFile::createFromDistant($fileKey, $name);
    } else {
        $file = util_UploadedFile::createFromLocal($localFile, $name);
    }
    $mini = util_UploadedFile::createFromDistant($miniKey);
    $media = new pb_Media($type, $file->getName(), $date, $authUser->getId(), $repositoryId, $location, $description, $publicationDate);
    $media->create($file, $mini);
    $exchange->done('Media inserted');
}

function media_delete($exchange) {
    $request = $exchange->getRequest();
    $mediaId = $request->getAttribute('mediaId');
    $authUser = $exchange->getServer()->getContextKey('user');
    $media = pb_Media::fetchFromId($mediaId);
    if ($media == NULL) {
        throw new Exception("Media id " . $mediaId . " not found");
    }
    if (($media->getUserId() != $authUser->getId()) && (! $authUser->hasRight('admin'))) {
        throw new Exception('Not owner');
    }
    $media->delete();
    $exchange->done("Media deleted");
}

function media_listReply($exchange, $repositoryIds, $from, $to) {
    $connection = Helper::getInstance()->getSQL();
    $response = $exchange->createResponseElement('mediaListResult');
    foreach ($repositoryIds as $repositoryId) {
        //echo '<!-- fetch medias for repository ' . $repositoryId . ', from: ' . $from . ', to: ' . $to . ' -->';
        $connection->executef('SELECT ' . pb_Media::getSelectionFields() . ' FROM ' . DB_PREFIX .
            'MEDIA WHERE REPOSITORY_ID = %d AND PUBLICATION_DATE >= ' . sql_Connection::fromTimestamp('%d') .
            'AND PUBLICATION_DATE < ' . sql_Connection::fromTimestamp('%d'),
            $repositoryId, $from, $to);
        $rs = $connection->getResultSet();
        while ($rs->next()) {
            $media = pb_Media::createFromResultSet($rs);
            $response->appendChild($exchange->createResponseElement('media', array(
                'id' => $media->getId(),
                'type' => pb_Media::$TYPE_TO_STR[$media->getType()],
                'filename' => $media->getFilename(),
                'date' => $media->getDate(),
                'userId' => $media->getUserId(),
                'repositoryId' => $media->getRepositoryId(),
                'description' => $media->getDescription(),
                'pubDate' => $media->getPublicationDate(),
                'commentCount' => $media->getCommentCount()
            )));
        }
    }
    $exchange->replyXML($response);
}

function media_listPublic($exchange) {
    $request = $exchange->getRequest();
    $from = sxe_Server::getDOMElementAttribute($request, 'from', 0);
    $to = sxe_Server::getDOMElementAttribute($request, 'to', time() + 1);
    media_listReply($exchange, pb_Repository::getPublicRepositoryIds(), $from, $to);
}

function media_list($exchange) {
    $request = $exchange->getRequest();
    $from = sxe_Server::getDOMElementAttribute($request, 'from', 0);
    $to = sxe_Server::getDOMElementAttribute($request, 'to', time() + 1);
    $authUser = $exchange->getServer()->getContextKey('user');
    $repositoryIds = pb_Repository::getRepositoryIdsByUserId($authUser->getId());
    media_listReply($exchange, $repositoryIds, $from, $to);
}

?>