<?php

/**
 * 
 * This file is dynamically generated by the WordpressEnqueueChunksPlugin for Webpack.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
 * OR OTHER DEALINGS IN THE SOFTWARE.
 * 
 */

namespace WordpressEnqueueChunksPlugin;

class AssetRegistrationException extends \Exception {};

/**
 * Get a user-defined config setting
 *
 * @param string $key
 * @return mixed
 */
function get($key)
{
    static $config = null;
    if (defined('WPECP_TEST') && WPECP_TEST) {
        return WPECP_TEST_CONFIG[$key];
    }
    if (is_null($config)) {
        $config = json_decode('{% props %}', true);
    }
    return isset($config[$key]) ? $config[$key] : null;
}

/**
 * Get an array of chunks and chunk meta from an array of script names
 * 
 * @param array $assets
 * @param array $manifest
 * @return array
 */
function getChunks(array $assets, array $manifest)
{
    if (empty($assets)) {
        return $manifest['chunks'];
    }
    $deps = array_reduce($assets, function($acc, $asset) use($manifest) {
        if (isset($manifest['entries'][$asset])) {
            return array_merge($acc, $manifest['entries'][$asset]['deps']);
        }
        return $acc;
    }, []);
    $keys = array_flip(array_unique(array_merge($assets, $deps)));
    return array_intersect_key($manifest['chunks'], $keys);
}

/**
 * Builds a script handle
 * 
 * @param string $asset
 * @return string
 */
function makeHandle($asset)
{
    $namespace = get('namespace');
    $delimiter = get('delimiter');
    return "{$namespace}{$delimiter}{$asset}";
}

/**
 * Check if a script has already been registered
 * 
 * @param string $asset
 * @return boolean
 */
function isRegistered($asset)
{
    return wp_script_is(makeHandle($asset), 'registered');
}

/**
 * Get the full url to an asset
 * 
 * @param string $file
 * @param string $context
 * @return string
 */
function getAssetUrl($file, $context)
{
    $dir = trailingslashit(get('assetsDir'));
    if ($context === 'plugin') {
        return plugins_url($dir . $file);
    }
    return get_theme_file_uri($dir . $file);
}

/**
 * Maps an asset's dependencies by handle
 * 
 * @param string $asset
 * @return array
 */
function mapDependencies($asset)
{
    $manifest = get('manifest');
    if (isset($manifest['entries'][$asset])) {
        $deps = $manifest['entries'][$asset]['deps'];
        return array_map(__NAMESPACE__ . '\\makeHandle', $deps);
    }
    return [];
}

/**
 * Generates arguments to be passed to wp_register_script
 * 
 * @param string $asset
 * @param array $data
 * @return array
 */
function makeScriptArgs($asset, array $data)
{
    $handle = makeHandle($asset);
    $src = getAssetUrl($data['file'], get('context'));
    $deps = mapDependencies($asset);
    $version = $data['hash'];
    $inFooter = true; // @TODO: expose this to the user
    return compact('handle', 'src', 'deps', 'version', 'inFooter');
}

/**
 * Register an asset
 * 
 * @param string $asset
 * @param array $args
 * @return boolean
 */
function register($asset, array $args)
{
    if (isRegistered($asset)) {
        return true;
    }
    $filtered = apply_filters("wpecp/register/$asset", $args);
    $success = call_user_func_array('wp_register_script', $filtered);
    if (!$success) {
        throw new AssetRegistrationException("Unable to register asset $asset!");
    }
    return true;
}

/**
 * Registers all or just some of the assets in a manifest
 * 
 * @param array $scripts
 * @return void
 */
function registerScripts(array $scripts = [])
{
    $manifest = get('manifest');
    foreach (getChunks($scripts, $manifest) as $chunk => $data) {
        if (isRegistered($chunk)) {
            continue;
        }
        $args = makeScriptArgs($chunk, $data);
        register($chunk, $args);
    }
}
