<?php

namespace WpieFw\Settings;

use WpieFw\Files\WpieFileFinder;
use WpieFw\Helpers\WpieMultisiteHelper;
use WpieFw\Notices\WpieNotices;
use WpieFw\Settings\Files\WpieSettingsFileCollection;
use WpieFw\Settings\Iterator\WpieSettingsCollection;
use WpieFw\Settings\WpieSettingsFactoryInterface;
use WpieFw\Wpie\WpieGlobals;

if( ! defined( 'ABSPATH' ) ) exit;

/**
 * @author WeePie Plugins
 *
 * The WpieSettingsGenerator handles the creation of the settings
 *
 */
final class WpieSettingsGenerator
{
	/**
	 * @var WpieSettingsFactory
	 */
	private $factory;

	/**
	 * @var WpieFileFinder
	 */
	private $finder;

	/**
	 * @var WpieSettingsValues
	 */
	private $values;

	/**
	 * @var WpieGlobals
	 */
	private $globals;

	/**
	 * @var WpieSettingsFileCollection
	 */
	private $files = null;

	/**
	 * Flag if paths should be stored relative or absolute
	 *
	 * @var bool
	 */
	public $relativePath = true;

	/**
	 * Stored WpieSetting instances
	 *
	 * @var WpieSettingsCollection
	 */
	public $collection;

	/**
	 * Contructor
	 *
	 * @param WpieSettingsFactory	$factory
	 * @param WpieFileFinder		$finder
	 * @param WpieSettingsValues	$values
	 * @param WpieGlobals			$globals
	 *
	 * @throws \WpieFw\Exceptions\WpieFyException
	 */
	public function __construct( WpieSettingsFactory $factory, WpieFileFinder $finder, WpieSettingsValues $values, WpieGlobals $globals )
	{
		if( !\WpieFw\Helpers\WpieMiscHelper::fontType( $globals->nameSpace ) ) {
			throw new \WpieFw\Exceptions\WpieFyException( '' );
		}

		$this->factory = $factory;
		$this->finder = $finder;
		$this->values = $values;
		$this->globals = $globals;
		$this->collection = new WpieSettingsCollection();
	}

	/**
	 * @return WpieSettingsCollection
	 */
	public function getCollection() {
		return $this->collection;
	}

	/**
	 * Resolve settings files
	 *
	 * @todo check if stored filed exist
	 *
	 * @uses WpieSettingsValues::getFiles()
	 * @uses WpieFileFinder::getFilesPathArray()
	 * @uses WpieFileFinder::getFilesPathArrayRelative()
	 * @uses WpieSettingsFileCollection
	 */
	public function resolveFiles()
	{
		$persist = false;
		$stored = $this->values->getFiles();
		$toPersist = [];

		if( empty( $stored ) ) {
			$files = $this->finder->getFilesPathArray();
			$persist = true;

			if( $this->relativePath ) {
				$toPersist = $this->finder->getFilesPathArrayRelative( 'wp-content' );
			} else {
				$toPersist = $files;
			}
		} else {
			$files = $stored;
		}

		// Create collection for files
		$this->files = new WpieSettingsFileCollection( $files, $this->finder->getPrefix(), 'wp-content' );

		if( $persist ) {
			// Persist the files array
			$this->values->persist( 'files', $toPersist );
		}
	}

	/**
	 * Maybe reset the settings
	 *
	 * Also count for multisite requests.
	 *
	 * @uses self::reset()
	 */
	public function maybeReset()
	{
		$isUpgrading = $this->globals->get( 'isUpgrading' );
		$isResetting = $this->globals->get( 'isResetting' );
		$hasPermissions = current_user_can( 'activate_plugins');

		$networkReset = is_network_admin() || WpieMultisiteHelper::isMs() && $hasPermissions;
		$reset = is_admin() || !WpieMultisiteHelper::isMs() && $hasPermissions;

		// check if there is a reset of upgrade request
		if( $isUpgrading || $isResetting ) {
			if( $networkReset ) {
				$current = get_current_blog_id();
				$sites = WpieMultisiteHelper::getSites();

				foreach ( $sites as $site ) {
					switch_to_blog( $site->blog_id );

					// do the reset
					$this->reset( $isUpgrading );

					/**
					 * Let others hook into the reset settings process
					 *
					 * @param int|bool $blog_id
					 */
					do_action( $this->globals->nameSpace. '_force_delete_settings', $site->blog_id );
				}

				// switch back to the original site
				switch_to_blog( $current );

			} elseif ( $reset ) {
				// do the reset
				$this->reset( $isUpgrading );

				/**
				 * Let others hook into the reset settings process
				 *
				 * @param int|bool $blog_id
				 */
				do_action( $this->globals->nameSpace. '_force_delete_settings', false );
			}

			if( $isResetting ) {
				WpieNotices::add( $this->globals->nameSpace,  __( sprintf( '%s settings resetted', $this->globals->get( 'pluginName' ) ) , 'weepie' ), 'success' );
			}
		}
	}

	/**
	 * Create the settings and add them to the collection
	 *
	 * @param \WpieFw\Multilang\WpieMultilangProcessor|bool $multilang
	 *
	 * @uses WpieSettingsFactoryInterface::createForMultilang()
	 * @uses WpieSettingsFactoryInterface::create()
	 * @uses WpieSettingsCollection::set()
	 */
	public function create( $multilang = false )
	{
		foreach( $this->files as $file ) {
			$ext = $file->getExtension();

			// create a new settings instance with the Factory
			if( false !== $multilang && $multilang->hasMultipleLocales ) {
				$setting = $this->factory->createForMultilang( $ext, $file, $this->values, $multilang );
			} else {
				$setting = $this->factory->create( $ext, $file, $this->values );
			}

			// Set the setting
			$this->collection->set( $setting->getIdx(), $setting );
		}
	}

	/**
	 * Reset the settings
	 *
	 * If $isUpgrading is true, persist the current setting temporarly,
	 * so that it can be merged later on.
	 *
	 * @param string $isUpgrading
	 *
	 * @uses self::resolveFiles()
	 * @uses WpieSettingsValues::deleteSetting()
	 * @uses WpieSettingsValues::deleteFields()
	 * @uses WpieSettingsValues::deleteDefault()
	 * @uses WpieSettingsValues::deleteFiles()
	 */
	private function reset( $isUpgrading = false )
	{
		// start resolving the settings files
		$this->resolveFiles();

		// if having files, delete setting and setting fields entries
		foreach ( $this->files as $file ) {
			$idx = $file->getIndex();

			// if upgrading, save a copy of the current setting
			// so that it can be merged later on.
			if( $isUpgrading ) {
				$this->values->persistSettingTmp( $idx );
			}

			$this->values
				->deleteSetting( $idx )
				->deleteArray( $idx );
		}

		// delete the default and files entry
		$this->values
			->deleteDefault()
			->deleteFiles();

		// files are deleted in the DB,
		// so resolve the files again
		$this->resolveFiles();
	}
}