<?php namespace HashOver;

// Copyright (C) 2018-2021 Jacob Barkdull
// This file is part of HashOver.
//
// HashOver is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// HashOver is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with HashOver. If not, see <http://www.gnu.org/licenses/>.


class JavaScriptBuild
{
protected $directory;
protected $files = array ();

public function __construct ($directory = '.')
{
$this->changeDirectory ($directory);
}

public function changeDirectory ($directory = '.')
{
$this->directory = trim ($directory, '/') . '/';
}

protected function addFile ($file)
{
// Add file to files array if it isn't already present
if (!in_array ($file, $this->files, true)) {
$this->files[] = $file;
}
}

protected function addDependencies ($file, array $dependencies)
{
// Add each dependency to files array
foreach ($dependencies as $dependency) {
$dependency = $this->directory . $dependency;

// Check if the file exists
if (file_exists ($file)) {
// If so, add file to files array
$this->addFile ($dependency);
} else {
// If not, throw exception on failure
throw new \Exception (sprintf (
'"%s" depends on "%s" but it does not exist.',
$file, $dependency
));
}
}

return true;
}

protected function includeFile ($file)
{
// Attempt to read JavaScript file
$file = @file_get_contents ($file);

// Check if the file read successfully
if ($file !== false) {
// If so, return the contents
return trim ($file);
}

// Otherwise throw exception
throw new \Exception (
sprintf ('Unable to include "%s"', $file)
);
}

public function registerFile ($file, array $options = array ())
{
$file = $this->directory . $file;

if (!empty ($options)) {
// Check if there is an include condition
if (isset ($options['include'])) {
// If so, return void if include is false
if ($options['include'] === false) {
return;
}
}

// Add optional dependencies to files array
if (!empty ($options['dependencies'])) {
$dependencies = $options['dependencies'];
$this->addDependencies ($file, $dependencies);
}
}

// Check if the file exists
if (file_exists ($file)) {
// If so, add file to files array
$this->addFile ($file);
} else {
// If not, throw exception
throw new \Exception (
sprintf ('"%s" does not exist.', $file)
);
}

return true;
}

public function build ($minify = false, $minify_level = 0)
{
// Array for included JavaScript files
$files = array ();

// Attempt to include registered JavaScript files
foreach ($this->files as $file) {
$files[] = $this->includeFile ($file);
}

// Join the included JavaScript files
$javascript = implode (PHP_EOL . PHP_EOL, $files);

// Minify the JavaScript if told to
if (!isset ($_GET['unminified'])) {
if ($minify === true and $minify_level > 0) {
// Instantiate JavaScript minification class
$minifier = new JavaScriptMinifier ();

// Minify JavaScript build result
$minified = $minifier->minify ($javascript, $minify_level);

// Set minified result as JavaScript output
$javascript = $minified;
}
}

// Return normal JavaScript code
return $javascript;
}
}