<?php

namespace BootstrapUI\Shell\Task;

use Cake\Console\Shell;
use Cake\Core\Configure;
use Cake\Core\Plugin;
use Cake\Filesystem\File;
use Cake\Filesystem\Folder;

/**
 * Task for installing Bootstrap assets and layouts to app.
 */
class TwbsAssetsTask extends Shell
{
    protected $_assetDir;
    protected $_nodeDir;
    protected $_cssDir;
    protected $_jsDir;

    /**
     * TwbsAssetsTask constructor.
     */
    public function __construct()
    {
        parent::__construct();
        $this->_assetDir = new Folder(Plugin::path('BootstrapUI') . 'webroot', true);
        $this->_nodeDir = new Folder(Plugin::path('BootstrapUI') . 'node_modules', true);
        $this->_cssDir = new Folder($this->_assetDir->path . DS . 'css', true);
        $this->_jsDir = new Folder($this->_assetDir->path . DS . 'js', true);
    }

    /**
     * Installs Bootstrap assets using npm
     *
     * @return void
     */
    public function installAssets()
    {
        $this->info('Checking npm...');
        if (!`which npm`) {
            $this->abort('NPM (https://www.npmjs.com/) is required, but not installed. Aborting.');
        }

        chdir(Plugin::path('BootstrapUI'));
        $node_mod = new Folder('node_modules');
        if ($node_mod->delete()) {
            $this->success('Cleared node_modules...');
        }

        exec('npm install --verbose', $output, $return);
        $this->out($output);
        if ($return === 0) {
            $this->success('Bootstrap assets installed successfully.');
        } else {
            $this->abort('Bootstrap assets could not be installed.');
        }
    }

    /**
     * Copy assets from node_modules folder to plugin's webroot
     * If in production mode, just copies min. required and minified assets
     *
     * @return void
     */
    public function copyAssets()
    {
        $this->info('Clearing webroot and copying assets...');
        if ($this->_clear($this->_assetDir, '^(?!cover)(?!dashboard)(?!signin)(?!baked-with-cakephp.svg).*$')) {
            $this->success('All files cleared...');
        }

        $files = [];
        $folders = [];
        $folders[] = new Folder($this->_nodeDir->path . DS . 'bootstrap/dist');
        $folders[] = new Folder($this->_nodeDir->path . DS . 'jquery/dist');
        $folders[] = new Folder($this->_nodeDir->path . DS . 'popper.js/dist/umd');

        foreach ($folders as $folder) {
            foreach ($folder->findRecursive() as $file) {
                $files[] = new File($file);
            }
        }
        $this->_copy($files);
    }

    /**
     * Copy sample layouts to app's layout dir
     *
     * @param string $target The destination path
     * @return void
     */
    public function copyLayouts($target = null)
    {
        $this->info('Copying sample layouts...');
        $layoutDir = new Folder(Plugin::path('BootstrapUI') . 'src' . DS . 'Template' . DS . 'Layout' . DS . 'examples');

        if ($target == null) {
            $target = APP . 'Template' . DS . 'Layout' . DS . 'TwitterBootstrap';
        }

        if (!$layoutDir->copy($target)) {
            $this->abort('Sample layouts could not be copied.');
        }
        $this->success('Sample layouts copied successfully.');
    }

    /**
     * Copy files to assetdir's css/js path
     *
     * @param array $files Assetfiles to copy
     * @return void
     */
    protected function _copy(array $files)
    {
        foreach ($files as $file) {
            $dir = null;
            if (preg_match('/.css/', $file->name)) {
                $dir = $this->_cssDir;
            } elseif (preg_match('/.js|.min.map/', $file->name)) {
                $dir = $this->_jsDir;
            }

            if ($file->copy($dir->path . DS . $file->name)) {
                $this->success($file->name . ' successfully copied.');
            } else {
                $this->warn($file->name . ' could not be copied.');
            }
        }
    }

    /**
     * Clear folder of assets
     *
     * @param \Cake\Filesystem\Folder $folder Folder to clear
     * @param string $except Files to skip
     * @return bool
     */
    protected function _clear(Folder $folder, $except)
    {
        $files = $folder->findRecursive($except);
        foreach ($files as $file) {
            $file = new File($file);
            if (!$file->delete()) {
                return false;
            }
        }

        return true;
    }
}
