<commit_before><?php

namespace Api\Model\Languageforge\Lexicon;

use Api\Library\Shared\LanguageData;
use Api\Model\Languageforge\Lexicon\Command\SendReceiveCommands;
use Api\Model\Languageforge\Lexicon\Config\LexConfiguration;
use Api\Model\Languageforge\Lexicon\Config\LexiconConfigObj;
use Api\Model\Languageforge\Lexicon\Dto\LexBaseViewDto;
use Api\Model\Languageforge\LfProjectModel;
use Api\Model\Mapper\MapOf;
use Palaso\Utilities\FileUtilities;

class LexiconProjectModel extends LfProjectModel
{
    public function __construct($id = '')
    {
        $this->appName = LfProjectModel::LEXICON_APP;
        $this->rolesClass = 'Api\Model\Languageforge\Lexicon\LexiconRoles';
        $this->inputSystems = new MapOf(
            function() {
                return new InputSystem();
            }
        );

        $this->config = new LexConfiguration();
        $this->sendReceiveProject = new SendReceiveProjectModel();

        // default values
        $this->inputSystems['en'] = new InputSystem('en', 'English', 'en');
        $this->inputSystems['th'] = new InputSystem('th', 'Thai', 'th');
        $this->languageCode = $this->config->entry->fields[LexiconConfigObj::LEXEME]->inputSystems[0];

        // This must be last, the constructor reads data in from the database which must overwrite the defaults above.
        parent::__construct($id);
    }

    /**
     *
     * @var MapOf <InputSystem>
     */
    public $inputSystems;

    /**
     *
     * @var LexConfiguration
     */
    public $config;

    /**
     *
     * @var string
     */
    public $liftFilePath;

    /**
     *
     * @var SendReceiveProjectModel
     */
    public $sendReceiveProject;

    /**
     *
     * @var string
     */
    public $sendReceiveUsername;

    /**
     * Adds an input system if it doesn't already exist
     * @param string $tag
     * @param string $abbr
     * @param string $name
     */
    public function addInputSystem($tag, $abbr = '', $name = '')
    {
        static $languages = null;
        if (!array_key_exists($tag, $this->inputSystems)) {
            if (! $abbr) {
                $abbr = $tag;
            }
            if (! $name) {
                $name = $tag;
                if (!$languages) {
                    $languages = new LanguageData();
                }
                $languageCode = LanguageData::getCode($tag);
                if (array_key_exists($languageCode, $languages)) {
                    $name = $languages[$languageCode]->name;
                }
            }
            $this->inputSystems[$tag] = new InputSystem($tag, $name, $abbr);
        }
    }

    public function getPublicSettings($userId)
    {
        $settings = parent::getPublicSettings($userId);
        $settings['currentUserRole'] = $this->users[$userId]->role;
        $settings['hasSendReceive'] = $this->hasSendReceive();

        return array_merge($settings, LexBaseViewDto::encode($this->id->asString(), $userId));
    }

    /**
     * @return bool
     */
    public function hasSendReceive()
    {
        return ($this->sendReceiveProject->identifier) ? true : false;
    }

    /**
     * Initialize the optionlists and create send receive symlinks for a project
     */
    public function initializeNewProject()
    {
        // setup default option lists
        $optionList = new LexOptionListModel($this);
        $listCode = LexiconConfigObj::flexOptionlistCode(LexiconConfigObj::POS);
        if (! $optionList->readByProperty('code', $listCode)) {
            $optionList->name = LexiconConfigObj::flexOptionlistName($listCode);
            $optionList->code = $listCode;
            $optionList->canDelete = false;
            $optionList->readFromJson(APPPATH . 'json/languageforge/lexicon/partOfSpeech.json');
            $optionList->write();
        }

        if ($this->hasSendReceive()) {
            $projectWorkPath = SendReceiveCommands::getLFMergePaths()->workPath . DIRECTORY_SEPARATOR . strtolower($this->projectCode);

            $srImagePath = $projectWorkPath . DIRECTORY_SEPARATOR . 'LinkedFiles' . DIRECTORY_SEPARATOR . 'Pictures';
            $assetImagePath = $this->getImageFolderPath();
            if (file_exists($assetImagePath)) {
                if (is_dir($assetImagePath)) {
                    FileUtilities::copyDirTree($assetImagePath, $srImagePath);
                    FileUtilities::removeFolderAndAllContents($assetImagePath);
                } else {
                    unlink($assetImagePath);
                }
            }
            FileUtilities::createAllFolders($srImagePath);
            symlink($srImagePath, $assetImagePath);

            $srAudioPath = $projectWorkPath . DIRECTORY_SEPARATOR . 'LinkedFiles' . DIRECTORY_SEPARATOR . 'AudioVisual';
            $assetAudioPath = $this->getAudioFolderPath();
            if (file_exists($assetAudioPath)) {
                if (is_dir($assetAudioPath)) {
                    FileUtilities::copyDirTree($assetAudioPath, $srAudioPath);
                    FileUtilities::removeFolderAndAllContents($assetAudioPath);
                } else {
                    unlink($assetAudioPath);
                }
            }
            FileUtilities::createAllFolders($srAudioPath);
            symlink($srAudioPath, $assetAudioPath);
        }
    }

    /**
     *
     * @return string
     */
    public function getImageFolderPath()
    {
        return $this->getAssetsFolderPath() . DIRECTORY_SEPARATOR . 'pictures';
    }

    /**
     *
     * @return string
     */
    public function getAudioFolderPath()
    {
        return $this->getAssetsFolderPath() . DIRECTORY_SEPARATOR . 'audio';
    }

}<commit_msg>feature/sendReceive: refactor "create assets folder symlinks for project"<commit_after><?php

namespace Api\Model\Languageforge\Lexicon;

use Api\Library\Shared\LanguageData;
use Api\Model\Languageforge\Lexicon\Command\SendReceiveCommands;
use Api\Model\Languageforge\Lexicon\Config\LexConfiguration;
use Api\Model\Languageforge\Lexicon\Config\LexiconConfigObj;
use Api\Model\Languageforge\Lexicon\Dto\LexBaseViewDto;
use Api\Model\Languageforge\LfProjectModel;
use Api\Model\Mapper\MapOf;
use Palaso\Utilities\FileUtilities;

class LexiconProjectModel extends LfProjectModel
{
    public function __construct($id = '')
    {
        $this->appName = LfProjectModel::LEXICON_APP;
        $this->rolesClass = 'Api\Model\Languageforge\Lexicon\LexiconRoles';
        $this->inputSystems = new MapOf(
            function() {
                return new InputSystem();
            }
        );

        $this->config = new LexConfiguration();
        $this->sendReceiveProject = new SendReceiveProjectModel();

        // default values
        $this->inputSystems['en'] = new InputSystem('en', 'English', 'en');
        $this->inputSystems['th'] = new InputSystem('th', 'Thai', 'th');
        $this->languageCode = $this->config->entry->fields[LexiconConfigObj::LEXEME]->inputSystems[0];

        // This must be last, the constructor reads data in from the database which must overwrite the defaults above.
        parent::__construct($id);
    }

    /**
     *
     * @var MapOf <InputSystem>
     */
    public $inputSystems;

    /**
     *
     * @var LexConfiguration
     */
    public $config;

    /**
     *
     * @var string
     */
    public $liftFilePath;

    /**
     *
     * @var SendReceiveProjectModel
     */
    public $sendReceiveProject;

    /**
     *
     * @var string
     */
    public $sendReceiveUsername;

    /**
     * Adds an input system if it doesn't already exist
     * @param string $tag
     * @param string $abbr
     * @param string $name
     */
    public function addInputSystem($tag, $abbr = '', $name = '')
    {
        static $languages = null;
        if (!array_key_exists($tag, $this->inputSystems)) {
            if (! $abbr) {
                $abbr = $tag;
            }
            if (! $name) {
                $name = $tag;
                if (!$languages) {
                    $languages = new LanguageData();
                }
                $languageCode = LanguageData::getCode($tag);
                if (array_key_exists($languageCode, $languages)) {
                    $name = $languages[$languageCode]->name;
                }
            }
            $this->inputSystems[$tag] = new InputSystem($tag, $name, $abbr);
        }
    }

    public function getPublicSettings($userId)
    {
        $settings = parent::getPublicSettings($userId);
        $settings['currentUserRole'] = $this->users[$userId]->role;
        $settings['hasSendReceive'] = $this->hasSendReceive();

        return array_merge($settings, LexBaseViewDto::encode($this->id->asString(), $userId));
    }

    /**
     * @return bool
     */
    public function hasSendReceive()
    {
        return ($this->sendReceiveProject->identifier) ? true : false;
    }

    /**
     * Initialize the optionlists and create send receive symlinks for a project
     */
    public function initializeNewProject()
    {
        // setup default option lists
        $optionList = new LexOptionListModel($this);
        $listCode = LexiconConfigObj::flexOptionlistCode(LexiconConfigObj::POS);
        if (! $optionList->readByProperty('code', $listCode)) {
            $optionList->name = LexiconConfigObj::flexOptionlistName($listCode);
            $optionList->code = $listCode;
            $optionList->canDelete = false;
            $optionList->readFromJson(APPPATH . 'json/languageforge/lexicon/partOfSpeech.json');
            $optionList->write();
        }

        if ($this->hasSendReceive()) {
            $projectWorkPath = SendReceiveCommands::getLFMergePaths()->workPath . DIRECTORY_SEPARATOR . strtolower($this->projectCode);

            $srImagePath = $projectWorkPath . DIRECTORY_SEPARATOR . 'LinkedFiles' . DIRECTORY_SEPARATOR . 'Pictures';
            $assetImagePath = $this->getImageFolderPath();
            $this->moveExistingFilesAndCreateSymlink($srImagePath, $assetImagePath);

            $srAudioPath = $projectWorkPath . DIRECTORY_SEPARATOR . 'LinkedFiles' . DIRECTORY_SEPARATOR . 'AudioVisual';
            $assetAudioPath = $this->getAudioFolderPath();
            $this->moveExistingFilesAndCreateSymlink($srAudioPath, $assetAudioPath);
        }
    }

    /**
     *
     * @return string
     */
    public function getImageFolderPath()
    {
        return $this->getAssetsFolderPath() . DIRECTORY_SEPARATOR . 'pictures';
    }

    /**
     *
     * @return string
     */
    public function getAudioFolderPath()
    {
        return $this->getAssetsFolderPath() . DIRECTORY_SEPARATOR . 'audio';
    }

    /**
     * @param $targetPath
     * @param $linkPath
     */
    private function moveExistingFilesAndCreateSymlink($targetPath, $linkPath)
    {
        if (file_exists($linkPath)) {
            if (is_dir($linkPath)) {
                FileUtilities::copyDirTree($linkPath, $targetPath);
                FileUtilities::removeFolderAndAllContents($linkPath);
            } else {
                unlink($linkPath);
            }
        }
        FileUtilities::createAllFolders($targetPath);
        symlink($targetPath, $linkPath);
    }

}
{'fraction_non_alphanumeric': 0.1254243344648919, 'fraction_numerical': 0.00017866714311238162, 'mean_word_length': 2.2916789179653043, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 77, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5525130', 'n_tokens_mistral': 3246, 'n_tokens_neox': 3133, 'n_words': 551}