#!/usr/bin/env php
<?php

$workingDirectory = realpath(($argc > 1) ? $argv[1] : '.');

function compile_path($directory) {
    global $workingDirectory;
    return implode(
        DIRECTORY_SEPARATOR,
        array_merge([$workingDirectory], (array)($directory))
    );
}

function get_template_mtime($template) {
    $templateDependencies = ['index.tpl', 'menu.tpl', 'content/' . $template];
    foreach ($templateDependencies as $template) {
        $includes = [];
        preg_match_all('/\{include .*\}/',
                       file_get_contents(compile_path(['template', $template])),
                       $includes);
        foreach ($includes[0] as $include) {
            $externalPath = [];
            if (preg_match('/file="(.*)"/', $include, $externalPath)) {
                $templateDependencies[] = $externalPath[1];
            }
        }
    }
    foreach (glob(compile_path(['config', '*.json'])) as $configFile) {
        $templateDependencies[] = '../config/' . basename($configFile);
    }
    return max(
        array_map(
            function($file) {
                return filemtime(compile_path(['template', $file]));
            },
            $templateDependencies
        )
    );
}

$outputDirectory = compile_path('static');

if (!file_exists($outputDirectory)) {
    mkdir($outputDirectory);
} else {
    if (!is_dir($outputDirectory)) {
        throw new Exception('Output path already exists, but not a directory');
    }
}

$templateDirectory = compile_path(['template', 'content']);

if (!(file_exists($templateDirectory) && is_dir($templateDirectory))) {
    throw new Exception('Template directory not found');
}

$inputDirectory = compile_path('http');
if (is_link($inputDirectory)) {
    $inputDirectory = compile_path('src');
}

$dynamicFiles = ['.htaccess', 'index.php'];
exec(
    'rsync -urLp '
    . implode(
        ' ',
        array_map(
            function($file) {
                return '--exclude=' . $file;
            },
            $dynamicFiles
        )
    ) . ' '
    . escapeshellarg($inputDirectory . DIRECTORY_SEPARATOR) . ' '
    . escapeshellarg($outputDirectory));

exec('find ' . escapeshellarg(compile_path('caches')) . ' -type f -not -name .gitignore -delete');

$bootstrapper = compile_path(['include', 'setup.php']);
require_once($bootstrapper);

$indexTemplates = ['index.tpl', 'main.tpl', 'home.tpl'];

$indexTemplate = array_search(TRUE, array_map(
    function($template) {
        return file_exists(compile_path(['template', 'content', $template]));
    },
    $indexTemplates
));
if ($indexTemplate === FALSE) {
    throw new Exception('Index template not found');
}

$filesToRender = ['index.html' => $indexTemplates[$indexTemplate],
                  '404.html' => '../404.tpl'];

$contentTemplateCommand = sprintf(
    'find %s -name \*.tpl',
    escapeshellarg($templateDirectory)
);
$contentTemplates = array_filter(
    explode(
        PHP_EOL,
        shell_exec($contentTemplateCommand)
    )
);
foreach ($contentTemplates as $file) {
    $fileMatch = array();
    if (preg_match(sprintf(
        '#^%s\/(.*\.tpl)$#',
        preg_quote($templateDirectory)
    ), $file, $fileMatch)) {
        $filesToRender[
            preg_replace(
                '/\.tpl$/',
                DIRECTORY_SEPARATOR . 'index.html',
                $fileMatch[1]
            )
        ] = $fileMatch[1];
    }
}

$lang = ($argc > 2) ? $argv[2] : '';
Env::setLang($lang);

$renderer = new MySmarty();
$renderer->assign('lang', Env::lang());

$basePath = ($argc > 3) ? $argv[3] : '/';
$renderer->assign('base', $basePath);

try {
    $scripts = Env::get('resources', 'scripts');
} catch(EnvNoSuchEntryException $e) {
    $scripts = [];
}
try {
    $sheets = Env::get('resources', 'sheets');
} catch(EnvNoSuchEntryException $e) {
    $sheets = [];
}
try {
    $minify = (bool)Env::get('resources', 'minify');
} catch(EnvNoSuchEntryException $e) {
    $minify = FALSE;
}
if ($minify && class_exists('Minify')) {
    $minifiedJSPath = compile_path(['static', '_js', 'scripts.js']);
    $minifiedJSHash = Minify::minifyJS($scripts, $minifiedJSPath);
    $outputScripts = [
        basename($minifiedJSPath) . '?mtime=' . $minifiedJSHash
    ];
    $minifiedCSSPath = compile_path(['static', '_css', 'styles.css']);
    $minifiedCSSHash = Minify::minifyCSS($sheets, $minifiedCSSPath);
    $outputSheets = [
        basename($minifiedCSSPath) . '?mtime=' . $minifiedCSSHash
    ];
    foreach ($scripts as $script) {
        unlink(compile_path(['static', '_js', $script]));
    }
    foreach ($sheets as $sheet) {
        unlink(compile_path(['static', '_css', $sheet]));
    }
} else {
    $outputScripts = $scripts;
    $outputSheets = $sheets;
}
foreach ($filesToRender as $output => $template) {

    $outputPath = compile_path(['static', $output]);

    if (!file_exists($outputPath)
        || filemtime($outputPath) < get_template_mtime($template)
        || filemtime($outputPath) < filemtime(__FILE__)
        || ($minify && class_exists('Minify') && (filemtime($outputPath) < Minify::getMTime($scripts, $sheets)))) {

        $content = new MySmarty();
        $content->assign('lang', Env::lang());
        $menu = new MySmarty();
        try {
            if (class_exists('Menu')) {
                $menu->assign('items', Menu::getItems());
                $menu->assign('content', Menu::getActiveLink(preg_replace('/\.tpl$/', '', $template)));
            }
        } catch(EnvNoSuchEntryException $e) {}
        $renderer->assign('menu', $menu->fetch('menu.tpl'));
        $renderer->assign('content', $content->fetch('content/' . $template));
        $title = NULL;
        try {
            $title = Env::get('titles', preg_replace('/\.tpl$/', '', $template));
        } catch(EnvNoSuchEntryException $e) {}
        $renderer->assign('title', $title);
        $renderer->assign('scripts', $outputScripts);
        $renderer->assign('sheets', $outputSheets);
        $outputDir = implode(
            DIRECTORY_SEPARATOR,
            array_slice(explode(DIRECTORY_SEPARATOR, $outputPath), 0, -1)
        );
        if (!is_dir($outputDir)) {
            mkdir($outputDir, 0777, TRUE);
        }
        file_put_contents($outputPath, $renderer->fetch('index.tpl'));

    }

}

if (!file_exists(compile_path(['static', '.htaccess']))) {
    file_put_contents(compile_path(['static', '.htaccess']),
                      'ErrorDocument 404 ' . rtrim($basePath, '/') . '/404.html' . PHP_EOL);
}

?>