<?php

/**
 * 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; under version 2
 * of the License (non-upgradable).
 *
 * 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.
 *
 * Copyright (c) 2013 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT);
 *
 *
 */

namespace oat\taoQtiItem\controller;

//use oat\taoQtiItem\controller\QtiPreview;
use oat\oatbox\service\ServiceManager;
use oat\tao\model\asset\AssetService;
use oat\taoQtiItem\helpers\QtiFile;
use oat\taoQtiItem\model\qti\Service;
use oat\taoQtiItem\model\qti\Item;
use OutOfBoundsException;
use OutOfRangeException;
use \taoItems_actions_ItemPreview;
use \tao_helpers_Uri;
use \core_kernel_classes_Resource;
use \common_Exception;
use \taoQtiCommon_helpers_PciVariableFiller;
use \common_Logger;
use \taoQtiCommon_helpers_ResultTransmissionException;
use \taoQtiCommon_helpers_PciStateOutput;
use \taoQtiCommon_helpers_Utils;
use \common_ext_ExtensionsManager;
use qtism\common\datatypes\files\FileSystemFileManager;
use qtism\runtime\common\State;
use qtism\runtime\tests\SessionManager;
use qtism\runtime\tests\AssessmentItemSession;
use qtism\runtime\tests\AssessmentItemSessionException;
use qtism\data\storage\xml\XmlDocument;
use qtism\data\storage\StorageException;

/**
 * Qti Item Runner Controller
 *
 * @author CRP Henri Tudor - TAO Team - {@link http://www.tao.lu}
 * @package taoQTI

 * @license GPLv2  http://www.opensource.org/licenses/gpl-2.0.php
 */
class QtiPreview extends taoItems_actions_ItemPreview
{

    public function getPreviewUrl($item, $options = [])
    {
        $code = base64_encode($item->getUri());
        return _url('render/' . $code . '/index', 'QtiPreview', 'taoQtiItem', $options);
    }

    public function submitResponses()
    {

        $itemUri = tao_helpers_Uri::decode($this->getRequestParameter('itemUri'));

        if (!empty($itemUri)) {
            $this->processResponses(new core_kernel_classes_Resource($itemUri));
        } else {
            throw new common_Exception('missing required itemUri');
        }
    }

    /**
     * Item's ResponseProcessing.
     *
     * @param core_kernel_classes_Resource $item The Item you want to apply ResponseProcessing.
     * @throws \RuntimeException If an error occurs while processing responses or transmitting results
     */
    protected function processResponses(core_kernel_classes_Resource $item)
    {

        $jsonPayload = taoQtiCommon_helpers_Utils::readJsonPayload();

        try {
            $qtiXmlFileContent = QtiFile::getQtiFileContent($item);
            $qtiXmlDoc = new XmlDocument();
            $qtiXmlDoc->loadFromString($qtiXmlFileContent);
        } catch (StorageException $e) {
            $msg = "An error occurred while loading QTI-XML file at expected location '${qtiXmlFilePath}'.";
            common_Logger::e(($e->getPrevious() !== null) ? $e->getPrevious()->getMessage() : $e->getMessage());
            throw new \RuntimeException($msg, 0, $e);
        }

        $itemSession = new AssessmentItemSession($qtiXmlDoc->getDocumentComponent(), new SessionManager());
        $itemSession->beginItemSession();

        $variables = [];
        $filler = new taoQtiCommon_helpers_PciVariableFiller($qtiXmlDoc->getDocumentComponent());

        // Convert client-side data as QtiSm Runtime Variables.
        foreach ($jsonPayload as $id => $response) {
            try {
                $var  = $filler->fill($id, $response);
                // Do not take into account QTI Files at preview time.
                // Simply delete the created file.
                if (taoQtiCommon_helpers_Utils::isQtiFile($var, false) === true) {
                    $fileManager = new FileSystemFileManager();
                    $fileManager->delete($var->getValue());
                } else {
                    $variables[] = $var;
                }
            } catch (OutOfRangeException $e) {
                // A variable value could not be converted, ignore it.
                // Developer's note: QTI Pairs with a single identifier (missing second identifier of the pair) are transmitted as an array of length 1,
                // this might cause problem. Such "broken" pairs are simply ignored.
                common_Logger::d("Client-side value for variable '${id}' is ignored due to data malformation.");
            } catch (OutOfBoundsException $e) {
                // No such identifier found in item.
                common_Logger::d("The variable with identifier '${id}' is not declared in the item definition.");
            }
        }

        try {
            $itemSession->beginAttempt();
            $itemSession->endAttempt(new State($variables));

            // Return the item session state to the client-side.
            $this->returnJson(
                [
                    'success' => true,
                    'displayFeedback' => true,
                    'itemSession' => self::buildOutcomeResponse($itemSession)
                ]
            );
        } catch (AssessmentItemSessionException $e) {
            $msg = "An error occurred while processing the responses.";
            throw new \RuntimeException($msg, 0, $e);
        } catch (taoQtiCommon_helpers_ResultTransmissionException $e) {
            $msg = "An error occurred while transmitting a result to the target Result Server.";
            throw new \RuntimeException($msg, 0, $e);
        }
    }

    /**
     * Get the ResultServer API call to be used by the item.
     *
     * @return string A string representing JavaScript instructions.
     */
    protected function getResultServer()
    {
        $itemUri = tao_helpers_Uri::decode($this->getRequestParameter('uri'));
        return [
            'module'    => 'taoQtiItem/QtiPreviewResultServerApi',
            'endpoint'  => ROOT_URL . 'taoQtiItem/QtiPreview/',
            'params'    => $itemUri
        ];
    }


    protected static function buildOutcomeResponse(AssessmentItemSession $itemSession)
    {
        $stateOutput = new taoQtiCommon_helpers_PciStateOutput();

        foreach ($itemSession->getOutcomeVariables(false) as $var) {
            $stateOutput->addVariable($var);
        }

        $output = $stateOutput->getOutput();
        return $output;
    }

    /**
     * (non-PHPdoc)
     * @see taoItems_actions_ItemPreview::getRenderedItem()
     */
    protected function getRenderedItem($item)
    {

        //@todo make getRenderedItem language dependent
        $lang = \common_session_SessionManager::getSession()->getDataLanguage();
        $qtiItem = Service::singleton()->getDataItemByRdfItem($item, $lang, true);
        if ($qtiItem) {
            $contentVariableElements = array_merge($this->getModalFeedbacks($qtiItem), $this->getRubricBlocks($qtiItem));

            /** @var AssetService $assetService */
            $assetService = ServiceManager::getServiceManager()->get(AssetService::SERVICE_ID);

            $taoBaseUrl = $assetService->getJsBaseWww('tao');
            $qtiBaseUrl = $assetService->getJsBaseWww('taoQtiItem');

            $taoLibUrl = $taoBaseUrl . 'js/';
            $taoQtiItemLibUrl = $qtiBaseUrl . 'js/';

            $xhtml = $qtiItem->toXHTML([
                'contentVariableElements' => $contentVariableElements,
                //  'js' => array($qtiBaseUrl.'js/preview/qtiViewSelector.js'),
                'js_var' => ['view' => $this->getRequestView()],
                // 'css' => array($qtiBaseUrl.'css/preview/qtiViewSelector.css'),
                'path' => [
                    'tao' => $taoLibUrl,
                    'taoQtiItem' => $taoQtiItemLibUrl
                ],
                'client_config_url' => $this->getClientConfigUrl()

            ]);
        } else {
            \common_Logger::i('Try to preview an empty item', [$item->getUri()]);
            $xhtml = '';
        }

        return $xhtml;
    }

    protected function getRequestView()
    {
        $returnValue = 'candidate';

        if ($this->hasRequestParameter('view')) {
            $returnValue = tao_helpers_Uri::decode($this->getRequestParameter('view'));
        }

        return $returnValue;
    }

    protected function getRubricBlocks(Item $qtiItem)
    {

        $returnValue = [];

        $currentView = $this->getRequestView();
        $rubricBlocks = $qtiItem->getRubricBlocks();

        foreach ($rubricBlocks as $rubricBlock) {
            $view = $rubricBlock->attr('view');

            if (!empty($view) && in_array($currentView, $view)) {
                $returnValue[$rubricBlock->getSerial()] = $rubricBlock->toArray();
            }
        }

        return $returnValue;
    }

    protected function getModalFeedbacks(Item $qtiItem)
    {

        $returnValue = [];

        $feedbacks = $qtiItem->getModalFeedbacks();
        foreach ($feedbacks as $feedback) {
            $returnValue[$feedback->getSerial()] = $feedback->toArray();
        }

        return $returnValue;
    }

    public function getTemplateElements(Item $qtiItem)
    {

        throw new common_Exception('qti template elments, to be implemented');
        //1. process templateRules
        //2. return the template values
    }
}