<commit_before><?php
/*
 * Copyright 2015 <NAME> <http://jacksleight.com/>
 * This source file is subject to the MIT license that is bundled with this package in the file LICENCE. 
 */

namespace Coast;

use Coast\Path;
use Coast\File;
use Coast\Dir;
use Coast\View\Content;

class View implements \Coast\App\Access, \Coast\App\Executable
{
    use \Coast\App\Access\Implementation;
    use \Coast\App\Executable\Implementation;

    protected $_dirs = [];

    protected $_extName = 'php';

    protected $_partialSeparator = '_';

    protected $_contexts = [];

    protected $_active;

    protected $_extends = [];

    protected $_files = [];

    public function __construct(array $options = array())
    {
        foreach ($options as $name => $value) {
            if ($name[0] == '_') {
                throw new \Coast\Exception("Access to '{$name}' is prohibited");  
            }
            $this->$name($value);
        }
    }

    public function dir($group, Dir $dir = null)
    {
        if (func_num_args() > 0) {
            if (!$group) {
                $group = 'default';
            }
            $this->_dirs[$group] = $dir;
            $this->_meta($group, $dir);
            return $this;
        }
        return isset($this->_dirs[$group])
            ? $this->_dirs[$group]
            : null;
    }

    public function dirs(array $dirs = null)
    {
        if (func_num_args() > 0) {
            foreach ($dirs as $group => $dir) {
                $this->dir($group, $dir);
            }
            return $this;
        }
        return $this->_dirs;
    }

    public function extName($extName = null)
    {
        if (func_num_args() > 0) {
            $this->_extName = $extName;
            return $this;
        }
        return $this->_extName;
    }

    public function partialSeparator($partialSeparator = null)
    {
        if (func_num_args() > 0) {
            $this->_partialSeparator = $partialSeparator;
            return $this;
        }
        return $this->_partialSeparator;
    }

    protected function _meta($group, Dir $dir)
    {
        $meta = $dir->file('_.php');
        if (!$meta->exists()) {
            return;
        }

        $meta = include $meta->name();

        if ($meta['extends']) {
            foreach ($meta['extends'] as $source => $target) {
                array_unshift($this->_extends, [
                    $this->_dirs[$group]
                        ->dir($source),
                    $this->_dirs[isset($target[1]) ? $target[1] : $group]
                        ->dir($target[0]),
                ]);
            }
        }
    }

    public function script($path, $group = null)
    {  
        $path = new \Coast\Path($path);
        if (isset($this->_active)) {
            if (!isset($group)) {
                $path = $path->isRelative()
                    ? $path->toAbsolute($this->_active->script->path)
                    : $path;
                $group = $this->_active->script->group;
            } else if (!$path->isAbsolute()) {
                $path = new \Coast\Path("/{$path}");
            }
        } else {
            if (!$path->isAbsolute()) {
                $path = new \Coast\Path("/{$path}");
            }
            if (!isset($group)) {
                $group = 'default';
            }
        }
        if (!isset($this->_dirs[$group])) {
            throw new View\Exception("View group '{$group}' does not exist");
        }
        return (object) [
            'key'   => "{$group}:{$path}",
            'group' => $group,
            'path'  => $path,
        ];
    }

    public function files($script)
    {
        if (!isset($this->_files[$script->key])) {
            $files = [];
            $file  = $this->_dirs[$script->group]
                ->file("{$script->path}.{$this->_extName}");
            if ($file->exists()) {
                array_push($files, $file);
            }
            foreach ($this->_extends as $extend) {
                if (!$file->isWithin($extend[0])) {
                    continue;
                }
                $file = $extend[1]->file($file->toRelative($extend[0]));
                if ($file->exists()) {
                    array_push($files, $file);
                }
            }
            $this->_files[$script->key] = $files;
        }

        return $this->_files[$script->key];
    }

    public function render($path, array $params = array(), $group = null, Content $previous = null)
    {  
        $script = $this->script($path, $group);
        array_unshift($this->_contexts, (object) ([
            'script'   => $script,
            'params'   => $params,
            'vars'     => [],<commit_msg>Update view extensions API<commit_after><?php
/*
 * Copyright 2015 <NAME> <http://jacksleight.com/>
 * This source file is subject to the MIT license that is bundled with this package in the file LICENCE. 
 */

namespace Coast;

use Coast\Path;
use Coast\File;
use Coast\Dir;
use Coast\View\Content;

class View implements \Coast\App\Access, \Coast\App\Executable
{
    use \Coast\App\Access\Implementation;
    use \Coast\App\Executable\Implementation;

    protected $_dirs = [];

    protected $_extName = 'php';

    protected $_partialSeparator = '_';

    protected $_contexts = [];

    protected $_active;

    protected $_extensions = [];

    protected $_files = [];

    public function __construct(array $options = array())
    {
        foreach ($options as $name => $value) {
            if ($name[0] == '_') {
                throw new \Coast\Exception("Access to '{$name}' is prohibited");  
            }
            $this->$name($value);
        }
    }

    public function dir($group, Dir $dir = null)
    {
        if (func_num_args() > 0) {
            if (!$group) {
                $group = 'default';
            }
            $this->_dirs[$group] = $dir;
            $this->_meta($group, $dir);
            return $this;
        }
        return isset($this->_dirs[$group])
            ? $this->_dirs[$group]
            : null;
    }

    public function dirs(array $dirs = null)
    {
        if (func_num_args() > 0) {
            foreach ($dirs as $group => $dir) {
                $this->dir($group, $dir);
            }
            return $this;
        }
        return $this->_dirs;
    }

    public function extension($group, $source, $target)
    {
        array_unshift($this->_extensions, [
            $this->_dirs[$group]
                ->dir($source),
            $this->_dirs[isset($target[1]) ? $target[1] : $group]
                ->dir($target[0]),
        ]);
        return $this;
    }

    public function extensions($group = null, array $extensions = null)
    {
        if (func_num_args() > 0) {
            foreach ($extensions as $source => $target) {
                $this->extension($group, $source, $target);
            }
            return $this;
        }
        return $this->_extensions;
    }

    public function extName($extName = null)
    {
        if (func_num_args() > 0) {
            $this->_extName = $extName;
            return $this;
        }
        return $this->_extName;
    }

    public function partialSeparator($partialSeparator = null)
    {
        if (func_num_args() > 0) {
            $this->_partialSeparator = $partialSeparator;
            return $this;
        }
        return $this->_partialSeparator;
    }

    protected function _meta($group, Dir $dir)
    {
        $meta = $dir->file('_.php');
        if (!$meta->exists()) {
            return;
        }

        $meta = include $meta->name();
        if (isset($meta['extensions'])) {
            $this->extensions($group, $meta['extensions']);
        }
    }

    public function script($path, $group = null)
    {  
        $path = new \Coast\Path($path);
        if (isset($this->_active)) {
            if (!isset($group)) {
                $path = $path->isRelative()
                    ? $path->toAbsolute($this->_active->script->path)
                    : $path;
                $group = $this->_active->script->group;
            } else if (!$path->isAbsolute()) {
                $path = new \Coast\Path("/{$path}");
            }
        } else {
            if (!$path->isAbsolute()) {
                $path = new \Coast\Path("/{$path}");
            }
            if (!isset($group)) {
                $group = 'default';
            }
        }
        if (!isset($this->_dirs[$group])) {
            throw new View\Exception("View group '{$group}' does not exist");
        }
        return (object) [
            'key'   => "{$group}:{$path}",
            'group' => $group,
            'path'  => $path,
        ];
    }

    public function files($script)
    {
        if (!isset($this->_files[$script->key])) {
            $files = [];
            $file  = $this->_dirs[$script->group]
                ->file("{$script->path}.{$this->_extName}");
            if ($file->exists()) {
                array_push($files, $file);
            }
            foreach ($this->_extensions as $extension) {
                if (!$file->isWithin($extension[0])) {
                    continue;
                }
                $file = $extension[1]->file($file->toRelative($extension[0]));
                if ($file->exists()) {
                    array_push($files, $file);
                }
            }
            $this->_files[$script->key] = $files;
        }

        return $this->_files[$script->key];
    }

    public function render($path, array $params = array(), $group = null, Content $previous = null)
    {  
        $script = $this->script($path, $group);
        array_unshift($this->_contexts, (object) ([
            'script'   => $script,
            'params'   => $params,
            'vars'     => [],
{'fraction_non_alphanumeric': 0.16122115580967938, 'fraction_numerical': 0.0031652031856238515, 'mean_word_length': 1.5474642392717814, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 137, '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': '4839484', 'n_tokens_mistral': 2838, 'n_tokens_neox': 2751, 'n_words': 581}