<?php

namespace NPS\Model;

use \DateTime;
use NPS\Entity\KnowledgeBaseEntity;
use NPS\DependencyInjection\IKnowledgeBaseInfoProvider;
use NPS\Etc\TMessage;
use NPS\Exception\ExpertSystemCommunicationException;


/**
 * Knowledge base model object
 * @author Lukas Korinek
 */
class KnowledgeBase implements IDomainObject
{
    use TMessage;

    // Status definitions
    const STATUS_DEV = 0;
    const STATUS_TESTING = 1;
    const STATUS_PUBLIC = 2;
    const STATUS_DEMO = 3;
    const STATUS_DISABLED = 4;

    /** @var KnowledgeBaseEntity $entity */
    private $entity;

    /** @var IKnowledgeBaseInfoProvider $infoProvider */
    private $infoProvider;

    /** @var string $content File content of the knowledge base */
    private $content;

    public function __construct(KnowledgeBaseEntity $entity, IKnowledgeBaseInfoProvider $infoProvider)
    {
        $this->entity = $entity;
        $this->infoProvider = $infoProvider;
    }

    /////////////////////////////////////////////////////////////////////////////
    // Getters

    /**
     * Gets name of the knowledge base
     * @return string
     */
    public function getName()
    {
        $language = explode('-', $this->infoProvider->getDefaultLanguage())[0];
        
        // Unsupported language may not result in unnecessary fetching
        $supported = $this->getSupportedLanguages();
        if(!in_array($language, $supported))
        {
            $language = reset($supported);
        }

        if(!array_key_exists($language, $this->entity->name))
        {
            $this->entity->name[$language] = $this->infoProvider->getKnowledgeBaseName($this->getPath());
        }

        return $this->entity->name[$language];
    }

    /**
     * Gets knowledge base description
     * @return string
     */
    public function getDescription()
    {
        $language = explode('-', $this->infoProvider->getDefaultLanguage())[0];

        // Unsupported language may not result in unnecessary fetching
        $supported = $this->getSupportedLanguages();
        if(!in_array($language, $supported))
        {
            $language = reset($supported);
        }

        if(!array_key_exists($language, $this->entity->description))
        {
            $this->entity->description[$language] = $this->infoProvider->getKnowledgeBaseDescription($this->getPath());
        }

        return $this->entity->description[$language];
    }

    /**
     * Gets a correct discrimininator tag for multimedia matching during question and hypothesis parsing
     * Warning: Must be in sync with media file creation in order to match correctly
     * @return string
     */
    public function getBaseDiscriminatorTag()
    {
        return 'bind_' . $this->getKnowledgeBaseBindId();
    }

    /**
     * Gets path of the knowledge base file
     * @return string
     */
    public function getPath()
    {
        return $this->entity->path;
    }

    /**
     * @inheritdoc
     */
    public function getId()
    {
        return $this->entity->getId();
    }

    /**
     * @inheritdoc
     */
    public function getKnowledgeBaseBindId()
    {
        return $this->entity->bindId;
    }

    /**
     * @inheritdoc
     */
    public function getEntity()
    {
        return $this->entity;
    }

    /**
     * Gets version date of the knowledge base
     * @return DateTime
     */
    public function getVersion()
    {
        return $this->entity->dateCreated;
    }

    /**
     * Gets status of the knowledge base
     * @param bool $asText Get the status as text or in the model form
     * @return int|string
     */
    public function getStatus()
    {
        return $this->entity->status;
    }

    /**
     * Gets the file content
     * @return string
     */
    protected function getContent()
    {
        if(!$this->content)
        {
            $this->content = file_get_contents($this->getPath());
        }

        return $this->content;
    }

    /**
     * Gets content checksum
     * @return int
     */
    public function getChecksum()
    {
        return crc32($this->getContent());
    }

    /**
     * Gets a list of languages supported by this knowledge base
     * @return array
     */
    public function getSupportedLanguages()
    {
        if(empty($this->entity->languages))
        {
            if(!$languages = $this->infoProvider->getKnowledgeBaseLanguages($this->getPath()))
            {
                throw new ExpertSystemCommunicationException('List of available languages couldnt be loaded');
            }

            $languages = array_map(function($language)
            {
                return explode('-', $language)[0];
            }, $languages);
            
            $this->entity->languages = $languages;
            return $languages;
        }

        return $this->entity->languages;
    }


    //////////////////////////////////////////////////////////////////////////////
    // Updating etc

    /**
     * Set status of this base
     * @param int $status
     */
    public function setStatus($status)
    {
        $this->entity->status = $status;
    }

    /**
     * Updates the file of a knowledge base with the content
     * @param string $content 
     * @return bool True on success
     */
    public function updateContent($content)
    {
        if(empty(trim($content)))   
        {
            $this->pushMessage('Invalid knowledge base content passed.');
            return false;
        }

        if($this->getChecksum() == crc32($content))
        {
            $this->pushMessage('Nothing to update, content is the same.');
            return true;
        }

        if(file_put_contents($this->getPath(), $content) === false)
        {
            $this->pushMessage('Knowledge base could not be created because of a permission issue or disk space issue.');
            return false;
        }

        $this->content = $content;
        
        // Invalidate DB cache upon content update
        $this->invalidateDbCache();
        
        return true;
    }

    /**
     * Invalidates DB cached stuff
     */
    public function invalidateDbCache()
    {
        $this->entity->languages = [];
        $this->entity->name = [];
        $this->entity->description = [];
    }

}

