<?php
/**
 * Generates array of classes for autoload
 *
 * @copyright NetMonsters <team@netmonsters.ru>
 * @link http://netmonsters.ru
 * @package Majestic
 * @subpackage util
 * @since 2010-02-24
 * @version SVN: $Id$
 * @filesource $URL$
 */

/**
 * @todo Refactoring writing, locking
 */
class AutoloadBuilder
{
    protected $autoload;

    protected $dirs;

    protected $exclude;

    protected $handler;

    protected $regex = '/(class|interface) ([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)/';

    public function __construct($autoload, $dirs = array(), $exclude = array())
    {
        $this->autoload = $autoload;
        $this->dirs = $dirs;
        $this->exclude = $exclude;
    }

    public function build()
    {
        $this->openAutoload();
        // for dublicates check
        $classes = array();
        foreach ($this->dirs as $dir) {
            $iterator = new RecursiveIteratorIterator(
                new RecursiveDirectoryIterator($dir),
                RecursiveIteratorIterator::LEAVES_ONLY
            );

            foreach ($iterator as $file) {

                if($this->isExcluded($file->getRealPath())) {
                    continue;
                }
                // skip non php files
                $e = explode('.', $file->getFileName());
                if ((end($e) !== 'php') || $this->rightSubstr($file->getFileName(), 8) == 'Test.php') {
                    continue;
                }

                $content = file_get_contents($file->getRealPath());
                $matches = array();

                $relative_path = substr($file->getRealPath(), strlen(PATH));

                if (preg_match_all($this->regex, $content, $matches, PREG_SET_ORDER)) {
                    foreach ($matches as $match) {
                        if (array_key_exists($match[2], $classes)) {
                            continue;
                        }
                        $string = "'{$match[2]}'=>'" . $relative_path . "',\n";
                        $this->write($string);
                        $classes[$match[2]] = $file->getRealPath();
                    }
                }
            }
        }
        $this->closeAutoload();
    }

    protected function isExcluded($file)
    {
        foreach ($this->exclude as $dir) {
            if (stripos($file, PATH . $dir) === 0) {
                return true;
            }
        }
        return false;
    }


    protected function openAutoload()
    {
        $this->write("<?php\n// This file is autogenerated by \n// " . __FILE__ . " script.\nreturn array(\n");
    }

    protected function closeAutoload()
    {
        if ($this->write(');')) {
            fclose($this->handler);
        }
    }

    protected function write($string)
    {
        if (!$this->handler) {
            if (!$this->handler = fopen($this->autoload, 'w')) {
                trigger_error("{$this->autoload} is not writable", E_USER_ERROR);
            }
        }
        return (bool) fwrite($this->handler, $string);
    }

    protected function rightSubstr($string, $nchars)
    {
        $right = substr($string, strlen($string) - $nchars, $nchars);
        return $right;
    }
}