<?php  // vim:set et ts=4 sw=4 sts=4:
# Copyright (C) 2003-2014 hipplay Inc.
#
# This is UNPUBLISHED PROPRIETARY SOURCE CODE OF hipplay Inc.
# The copyright notice above does not evidence any actual or intended
# publication of such source code. The contents of this file may not
# be disclosed to third parties, copied or duplicated in any form, in
# whole or in part, without the prior written permission of
# hipplay Inc.
#
namespace HipPlayConnect\REST\services\indexer;



use HipPlayConnect\AxRecoverableErrorException;
use HipPlayConnect\Configuration\AxFeatures;
use HipPlayConnect\FileSystem\AxDownloadManager;
use HipPlayConnect\FileSystem\AxPathMapper;
use HipPlayConnect\REST\AxAbstractRESTResource;
use HipPlayConnect\REST\AxRESTResourceInterface;
use HipPlayConnect\REST\AxRESTResponse;

class AxIndexerRESTResource extends AxAbstractRESTResource implements AxRESTResourceInterface {

    const DEBUG_INDEXER = FALSE;

    const XML_TIMESTAMPS  = '<indexer timestamps="%s" />';
    const XML_TOKEN       = '<download token="%s" timestamps="%s" />';
    const PATH_MAPPING    = '/tmpHost/path_mapping.txt';

    private $token;

    /**
     * @param string $token
     */
    public function __construct ($token = NULL) {
        $this->token = $token;
    }

    private function startsWith($haystack, $needle)
    {
        $length = strlen($needle);
        return (substr($haystack, 0, $length) === $needle);
    }

    /**
     * Return list of Index Database files or null if no database.
     */
    private function getFiles () {
        // Get path to index database from db_dir
        // configuration parameter.
        $confFile = AxFeatures::get('MINIDLNA_CONF');
        if (empty($confFile) || !file_exists($confFile)) {
            error_log("MINIDLNA_CONF not set or target file missing: " . $confFile);
            return NULL;
        }

        // Load the db_dir from minidlna.conf
        $dbPath = "";
        foreach (file($confFile) as $line) {
            if ($this->startsWith($line, "db_dir=")) {
                $dbPath = trim(substr($line,7));
                break;
            }
        }

        // Remove possible trailing comma.
        $dbPath = rtrim($dbPath, ',');
        if (empty($dbPath)) {
            error_log("db_dir empty.");
            throw new AxRecoverableErrorException("No database found.", AxRecoverableErrorException::ERR_NO_DATABASE_FOUND);
        }

        $dbPath = rtrim($dbPath, '/');

        $dbPath = AxPathMapper::mapMount($dbPath);
        $dbPath = "$dbPath/files.db";

        if (!file_exists($dbPath)) {
            error_log("no database file: $dbPath");
            throw new AxRecoverableErrorException("No database found.", AxRecoverableErrorException::ERR_NO_DATABASE_FOUND);
        }

        // Add name of path mapping file.
        $files = explode(',', $dbPath);
        $files[] = self::PATH_MAPPING;

        return $files;
    }

    /**
     * Return timestamps of Index Database files.
     *
     * @param array $files The filenames to collect modification timestamps for.
     *
     * @return string The comma-separated list of timestamps.
     */
    private function getTimestamps (array $files) {
        // Loop through list of files and calculate last-modification times.
        $timestamps = array();
        foreach ($files as $file) {
            $timestamp = @filemtime($file);
            if ($timestamp === FALSE)
                error_log("File not found: $file");

            $timestamps[] = $timestamp;
        }
        $timestamps = implode(',', $timestamps);

        return $timestamps;
    }

    protected function GET (array $queryParams) {
        // Download only if token has been generated.
        if (empty($this->token))
            return new AxRESTResponse(405);

        if ($this->token == 'timestamps') {
            // Generate list of files.
            $files = $this->getFiles();

            // Return list of timestamps.
            if (self::DEBUG_INDEXER)
                $timestamps = rand();
            else
                $timestamps = $this->getTimestamps($files);

            return $this->generateXmlResponse(self::XML_TIMESTAMPS, array($timestamps));
        } else {
            AxDownloadManager::downloadForToken($this->token);
            // should never get here
            return NULL;
        }
    }

    protected function POST (array $queryParams, $requestBody) {
        // Generate list of Index Database files.
        $files = $this->getFiles();

        // Calculate modification times.
        $timestamps = $this->getTimestamps($files);

        // Generate token for download.
        if (empty($this->token)) {

            // Generate the token.
            $this->token = AxDownloadManager::getToken($files);
        }

        return $this->generateXmlResponse(self::XML_TOKEN, array($this->token, $timestamps));
    }
}
