<?php

/*
 * The Black Sheep Research Library for Joomla applications
 * Copyright (c) 2017 Black Sheep Research
 * Author: Martin Brampton martin@black-sheep-research.com
 * Web: https://black-sheep-research.com
 * License: GNU General Public License version 2
 */

namespace BlackSheepResearch\Component\UserPoints\Site;

defined('_JEXEC') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Uri\Uri;

class WebAssetManager {

    protected static $instance = [];
    protected $extension = '';
    protected $assets = [];
    protected $style = [];
    protected $script = [];

    protected function __construct($extension) {
        $this->extension = $extension;
        $this->assets = json_decode(file_get_contents(JPATH_SITE . "/media/$extension/joomla.asset.json"), true);
    }

    public static function getInstance($extension) {
        if (!isset(self::$instance[$extension])) {
            // Remove false AND to enable Joomla WAM
            if (false AND class_exists('\Joomla\CMS\WebAsset\WebAssetManager')) {
                self::$instance[$extension] = Factory::getApplication()->getDocument()->getWebAssetManager();
            }
            else {
                self::$instance[$extension] = new self($extension);
            }
        }
        return self::$instance[$extension];
    }

    public function useStyle($name) {
        if (!isset($this->style[$name])) {
            $this->use('style', $name);
        }
        return $this;
    }

    public function useScript($name) {
        if (!isset($this->script[$name])) {
            $this->use('script', $name);
        }
        return $this;
    }

    private function use(string $type, string $name) {
        $asset = $this->findAsset($type, $name);
        if (count($asset)) {
            foreach (($asset['dependencies'] ?? []) as $depend) {
                $this->useScript($depend);
            }
            $this->$type($this->expandURI($asset['uri'], $type), [], ($asset['attributes'] ?? []));
            $this->$type[$name] = true;
        }
    }

    public function assetExists(string $type, string $name): bool {
        return count($this->findAsset($type, $name)) ? true : false;
    }

    private function findAsset(string $type, string $name): array {
        foreach ($this->assets['assets'] as $asset) {
            if ($type == $asset['type'] AND $name == $asset['name']) {
                return $asset;
            }
        }
        return [];
    }

    public function registerScript(string $name, string $uri, array $options = [], array $attributes = [], array $dependencies = []) {
        $this->register('script', $name, $uri, $options, $attributes, $dependencies);
    }

    public function registerStyle(string $name, string $uri, array $options = [], array $attributes = [], array $dependencies = []) {
        $this->register('style', $name, $uri, $options, $attributes, $dependencies);
    }

    private function register(string $type, string $name, string $uri, array $options = [], array $attributes = [], array $dependencies = []) {
        foreach (['type', 'name', 'uri', 'options', 'attributes', 'dependencies'] as $field) {
            $asset[$field] = $$field;
        }
        $this->assets[] = $asset;
    }

    private function expandURI(string $uri, string $type) : string {
        $typecode = ['script' => 'js', 'style' => 'css'];
        $dir = $typecode[$type];
        $file = $this->lastPart($uri, '/');
        return "media/$this->extension/$dir/$file";
    }

    private function script(string $file, array $options = array(), array $attribs = array()) {
        $prefix = 0 === stripos($file, 'http') ? '' : Uri::root();
        HTMLHelper::script($prefix . $file, $options, $attribs);
    }

    private function style(string $file, array $options = array(), array $attribs = array()) {
        $prefix = 0 === stripos($file, 'http') ? '' : URI::root();
        HTMLHelper::stylesheet($prefix . $file, $options, $attribs);
    }

    private function lastPart(string $field, string $separator, bool $lowercase = true) : string {
        $parts = explode($separator, $field);
        $last = end($parts);
        return $lowercase ? strtolower($last) : $last;
    }
}
