<?php
/**
 * Please see weepie-framework.php for more details.
 */

namespace WpieFw\Wpie;

use WpieFw\WpieSrc;
use WpieFw\Wpie\WpieGlobals;
use WpieFw\Wpie\WpieAutoUpdate;

use WpieFw\Exceptions\WpieException;
use WpieFw\Exceptions\WpieFyException;
use WpieFw\Exceptions\WpieRuntimeException;
use WpieFw\Exceptions\WpieInvalidArgumentException;
use WpieFw\Exceptions\WpieUnexpectedValueException;
use WpieFw\Exceptions\WpieExceptionInterface;
use WpieFw\Exceptions\WpieExceptionLogger;

use WpieFw\Files\WpieFileFinder;
use WpieFw\Framework\Patterns\Resolver\WpieWpOptionsResolver;

use WpieFw\Notices\WpieNotices;
use WpieFw\Helpers\WpieMiscHelper;
use WpieFw\Helpers\WpieMultisiteHelper;
use WpieFw\Helpers\WpieAjaxHelper;
use WpieFw\Helpers\WpieMultilangHelper;
use WpieFw\Helpers\WpieCronHelper;

use WpieFw\Multilang\WpieMultilangValues;
use WpieFw\Multilang\WpieMultilangFactory;
use WpieFw\Multilang\WpieMultilangProcessor;
use WpieFw\Multilang\Definition\WpieMultilangDefinition;

use WpieFw\Settings\WpieSettingsFactory;
use WpieFw\Settings\WpieSettingsValues;
use WpieFw\Settings\WpieSettingsGenerator;
use WpieFw\Settings\WpieSettingsValidator;
use WpieFw\Settings\WpieSettingsProcessor;
use WpieFw\Settings\Resolver\WpieSettingValuesResolverFactory;
use WpieFw\Settings\Definition\WpieSettingsDefinition;
use WpieFw\Settings\Iterator\WpieSettingsCollection;

use WpieFw\Modules\WpieModulesValues;
use WpieFw\Modules\WpieModulesFactory;
use WpieFw\Modules\WpieModulesBuilder;
use WpieFw\Modules\WpieModulesGenerator;
use WpieFw\Modules\WpieModuleProcessor;
use WpieFw\Modules\Definition\WpieModulesDefinition;
use WpieFw\Modules\Resolver\WpieModuleValuesResolverFactory;

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

/**
 * WpieCore Class
 *
 * @author $Author: Vincent Weber <weepie-plugins@outlook.com> $
 * @since 1.4.0
 */
class WpieCore
{
	/**
	 * The unique namespace of the Plugin that is extending WeePie Framework
	 *
	 * @var string
	 *
	 * @since 1.0
	 */
	private $nameSpace = '';

	/**
	 * Instance for WpieSrc
	 *
	 * @since 1.4.0
	 *
	 * @var WpieSrc
	 */
	private $wpieSrc;

	/**
	 * Start the engine of WeePie Framework
	 *
	 * @access protected
	 *
	 * @param string $nameSpace
	 * @param array $args
	 *
	 * @uses WpieCore::wpInit()
	 *
	 * @since 1.4.0
	 *
	 * @throws WpieInvalidArgumentException if mandatory method input params are missing
	 */
	protected function engine( $nameSpace = '', array $args = [] )
	{
		try {
			// Check for a valid namespace
			if( '' === trim( $nameSpace ) ) {
				throw new WpieInvalidArgumentException( 'Could not start WeePie Framework for plugin. Namespace parameter is empty.' );
			}

			// First make sure the args params of type string are not empty
			$args = array_map( function( $arg ) {
				if( is_string( $arg ) ) {
					$arg = trim( $arg );
					if( '' === $arg ) {
						throw new WpieInvalidArgumentException( 'Mandatory plugin parameter missing.' );
					}
					return $arg;
				} else {
					return $arg;
				}
			}, $args );

			// Import parameters from method arguments
			extract( $args );

			// Set the unique lowercase plugin namespace
			$this->nameSpace = strtolower( trim( $nameSpace ) );

			// Check for a valid settings array, if present  to do settings
			$doSettings = ( is_array( $settings ) && isset( $settings['pageTitle'] ) ) ? true : false;

			// Flag that client initiated activating process of current Plugin
			$isActivating = WpieMiscHelper::isActivatingPlugin( $file );

			// if the request initiated a reset, set $isResetting to true
			$isResetting = false;
			$isExporting = false;
			$isImporting = false;

			if( isset( $_REQUEST['ns'] ) && $this->nameSpace === $_REQUEST['ns'] ) {
				if( isset( $_REQUEST['force_delete_settings'] ) && '1' === $_REQUEST['force_delete_settings'] ) {
					$isResetting = true;
				} elseif( isset( $_REQUEST['wpie_do_reset'] )  && '1' === $_REQUEST['wpie_do_reset'] ) {
					$isResetting = true;
				} elseif( isset( $_REQUEST['wpie_do_export'] )  && '1' === $_REQUEST['wpie_do_export'] ) {
					$isExporting = true;
				} elseif( isset( $_REQUEST['wpie_do_import'] )  && '1' === $_REQUEST['wpie_do_import'] ) {
					$isImporting = true;
				}
			}
			// Create WpieGlobals instance
			$globals = new WpieGlobals( $nameSpace );
			// Add params to WpieGlobals instance
			$globals
				->setMultiple( [
					'file' 			=> $file,
					'fileWpieFw'	=> $fileWpieFw,
					'version'		=> $version,
					'versionWf'		=> $versionWf,
					'doSettings'	=> $doSettings,
					'pageTitle'		=> $doSettings ? $settings['pageTitle'] : '',
					'menuTitle'		=> $doSettings ? $settings['menuTitle'] : '',
					'isResetting'	=> $isResetting,
					'isActivating'	=> $isActivating,
					'isExporting'   => $isExporting,
					'isImporting'   => $isImporting,
					'pluginName'	=> WpieMiscHelper::getPluginData( $file, 'Name' )
				] )
				->setGlobals();

			// Init the WeePie Sources (/src) handler
			$this->initWpieSrc( $globals );

			/**
			 * Allow others to apply logic at the beginning of this method
			 *
			 * Pay attention with code hooking into this action!
			 *
			 * @since 1.2.3
			 */
			do_action( $this->nameSpace . '_before_start' );

			// Register the activation and deactivation hooks
			// @todo rename pluginPathFile?
			register_deactivation_hook( $this->getGlobal( 'pluginPathFile' ), [ $this, 'deactivatePlugin' ] );

			// To allow prio 11, use add_action instead of register_activation_hook()
			add_action( 'activate_' . $this->getGlobal( 'pluginFile' ), [ $this, 'activatePlugin' ], 11 );

			if( WpieMiscHelper::isFaviconRequest() ) {
				return;
			}

			// Prevent plugins from executing during deactivating
			if( WpieMiscHelper::isDeactivating() ) {
				return;
			}

			// Stop here for Cron jobs
			// @todo: allow WeePie crons
			if( WpieCronHelper::doingCron() ) {
				return;
			}

			// Stop here for some Ajax requests
			if( WpieAjaxHelper::maybeQuitForAjax() ) {
				return;
			}

			// Maybe set the WeePie Ajax global
			WpieAjaxHelper::maybeSetWpieAjaxGlobal();

			// Hook the plugin on the init action
			if( !$isActivating ) {
				add_action( 'init', [ $this, 'wpInit' ], 2 );
			} else {
				add_action( 'activate_' . $this->getGlobal( 'pluginFile' ), [ $this, 'wpInit' ], 10 );
			}

			define( 'wpie_running_' . $this->nameSpace, true );
		} catch ( WpieExceptionInterface $e ) {
			$this->notify( $e );
		} catch ( \Throwable $e ) {
			$this->notify( $e );
		}
	}

	/**
	 * Callback for the init or plugin activation hook: initialize most of the Plugin
	 *
	 * @uses self::initUpgrader()
	 * @uses self::initWpiefy()
	 * @uses WpieUpgrader::needReActivation()
	 * @uses self::activatePlugin()
	 * @uses self::init()
	 *
	 * @since 1.4.0
	 */
	public function wpInit()
	{
		try {
			// Load the plugin text domain
			WpieMultilangHelper::loadPluginTextDomain( 'weepie', false, $this->getGlobal( 'wfPathLangRel' ) );
			WpieMultilangHelper::loadPluginTextDomain( $this->nameSpace, false, $this->getGlobal( 'pluginPathLangRel' ) );

			// Create nonce for use in Ajax requests and add it to the WpieGlobals
			// The nonce is printed as a JavaScript variable inside {@link WpieHooksAdmin::printScriptsAdminHeaderVars()}
			$this->getGlobals()->set( 'nonce', wp_create_nonce( $this->nameSpace . '-action' ) );

			// check if user has permissions for resetting
			if( $this->getGlobal( 'isResetting' ) && !current_user_can( 'manage_options') ) {
				$this->getGlobals()->set( 'isResetting', false );
			}

			// Init the Upgrader and WpieFy
			// These are neccacary in all cases
			$this->initUpgrader();
			$this->initWpiefy();

			// Do the 'activate plugin logic' when a silent version change has been detected
			$silent = false;

			// But only when the user can `activate_plugins`
			if( current_user_can( 'activate_plugins' ) ) {
			    $silent = $this->wpieSrc->get( 'upgrader' )->hasVersionChangedSilently();
			    if( !$this->wpieSrc->get( 'upgrader' )->isActivated  && $silent ) {
			        $this->getGlobals()->set( 'isActivating', true );
			        $this->activatePlugin();
			    }
			}

			$isActivating = $this->getGlobal( 'isActivating', false );

			// Flag to init all other logic (but not whem activating)
			$this->init( [
				'autoupdate'   => !$isActivating,
				'multiLang'    => !$isActivating,
				'settings'     => !$isActivating,
				'settingspage' => !$isActivating,
				'modules'      => !$isActivating,
				'hooks'        => !$isActivating || $silent,
				'shortcodes'   => !$isActivating,
				'restapi'      => !$isActivating,

			] );
		} catch ( WpieExceptionInterface $e ) {
			$this->notify( $e );
		} catch ( \Throwable $e ) {
			$this->notify( $e );
		}
	}

	/**
	 * Callback for the deactivate_{$file} action hook
	 *
	 * @acces public
	 *
	 * @param bool $network Whether
	 *
	 * @since 1.1
	 */
	public function deactivatePlugin( $network )
	{
		// nothing yet
	}

	/**
	 * Callback for the activate_{$file} action hook
	 *
	 * If the current installation is multisite, all blogs are being called with the switch_to_blog() function.
	 *
	 * @param bool $network, indicates if the Plugin is being activated 'network wide'
	 *
	 * @uses self::initWpiefy()
	 * @uses self::_activatePlugin()
	 *
	 * @since 0.1
	 */
	public function activatePlugin( $network = null )
	{
		try {
			if( null === $network ) {
				$network = $this->wpieSrc->get( 'upgrader' )->networkActivated;
			}

			if( $network ) {
			    $currentBlog = ( !is_network_admin() ) ? get_current_blog_id() : 0;
				$sites = WpieMultisiteHelper::getSites();

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

					$this->_activatePlugin( $network );

					// remove all attached action to ensure the callbacks are only called ones
					remove_all_actions( $this->nameSpace . '_activate_plugin' );
				}

				// switch back to the current blog
				if( $currentBlog ) {
				    switch_to_blog( $currentBlog );
				}
			} else {
				$this->_activatePlugin( $network );

				if( '' !== $this->getGlobal( 'optionActivating', '' ) ) {
					add_option( $this->getGlobal( 'optionActivating' ) , true );
				}
			}
		} catch ( WpieFyException $e ) {
		} catch ( WpieExceptionInterface $e ) {
			$this->notify( $e, true, true );
		} catch ( \Throwable $e ) {
			$this->notify( $e, true, true );
		}
	}

	/**
	 * Do activation / upgrade logic
	 *
	 * @access private
	 *
	 * @param string $network
	 *
	 * @uses WpieUpgrader::doUpgradeDependendLogic()
	 * @uses self::initMultiLang()
	 * @uses self::initSettings()
	 * @uses self::initSettingsPage()
	 * @uses self::initModules()
	 *
	 * @since 3.2.7
	 */
	private function _activatePlugin( $network = false )
	{
		// When upgrading, do depended logic
		if( $upgrading = $this->getGlobal( 'isUpgrading', false ) ) {
			$this->wpieSrc
				->get( 'upgrader' )
				->doUpgradeDependendLogic( $network	);
		}

		// Initialize logic needed during activating
		$this->init( [
				'multiLang'    => 1,
				'settings'     => 1,
				'settingspage' => 1,
				'modules'      => 1
		] );

		/**
		 * Let Plugin modules hook into this process
		 *
		 * @param bool $upgrading
		 *
		 * @since 1.0
		 */
		do_action( $this->nameSpace . '_activate_plugin', $upgrading );
	}

	/**
	 * Add a notice and log for given Exception
	 *
	 * @param \Throwable|\Exception $e
	 * @param bool $whenLoggedIn
	 * @param bool $die
	 *
	 * @uses WpieNotices::add()
	 * @uses WpieExceptionLogger::log()
	 *
	 * @since 2.0
	 */
	private function notify( $e, $whenLoggedIn = true, $die = false )
	{
		if( $e instanceof \Throwable || $e instanceof \Exception ) {

			if( $die ) {
				wp_die( $e->getMessage(), 'WeePie Framework > Error', [ 'back_link' => true ] );
			}

			// Add a notice to the WordPress Dashboard
			WpieNotices::add( $this->nameSpace, $e->getMessage() );
			// Log the Exception as a system message, and only when logged in
			WpieExceptionLogger::log( $e, $whenLoggedIn );
		}
	}

	/**
	 * Return WpieGlobals instance
	 *
	 * @since 1.4.0
	 *
	 * @return WpieGlobals|null
	 */
	private function getGlobals()
	{
		return $this->wpieSrc->get( 'globals', null );
	}

	/**
	 * Return WpieGlobals entry
	 *
	 * @param string $name
	 *
	 * @uses self::getGlobals()
	 */
	private function getGlobal( $name = '', $default = null )
	{
		if( null !== $this->getGlobals() ) {
			if( $this->getGlobals()->offsetExists( $name ) ) {
				return $this->getGlobals()->get( $name );
			} else {
				return $default;
			}
		} else {
			return $default;
		}
	}

	/**
	 * Init upgrader logic
	 *
	 * @acces private
	 *
	 * @param bool|null $network
	 *
	 * @uses WpieUpgrader::hook()
	 *
	 * @since 1.4.0
	 */
	private function initUpgrader()
	{
	    if( !current_user_can( 'update_plugins' ) ) {
			return;
		}

		// Create WpieUpgrader instance
		$upgrader = $this->wpieSrc->create(
				'WpieFw\Wpie\WpieUpgrader'
				);

		$upgrader
			->setParams()
			->persistData()
			->pluginNotices();

		// Update the WpieGlobals
		$this->getGlobals()->setMultiple( [
				'isUpgrading'	=> $upgrader->upgrading,
				'versionOld'	=> $upgrader->versionPluginOld,
				'versionWfOld'	=> $upgrader->versionWfOld
		] );
	}

	/**
	 * WeePieFy this install
	 *
	 * @access private
	 *
	 * @uses WpieFy::isWpiefied()
	 *
	 * @since 1.2.3
	 */
	private function initWpiefy()
	{
		try {
			$this->wpieSrc->create(
					'WpieFw\Wpie\WpieFy',
					[],
					'',
					false
					);

			if( false === $this->wpieSrc->get( 'fy' )->isWpiefied() ) {
				throw new WpieFyException( '' );
			}
		} catch( WpieExceptionInterface $e ) {
			throw $e;
		}
	}

	/**
	 * Initialize the Auto Update logic
	 *
	 * @uses WpieAutoUpdate
	 *
	 * @since 2.0
	 */
	private function initAutoUpdate()
	{
	    if( !current_user_can( 'update_plugins' ) ) {
			return;
		}

		$this->wpieSrc->create(
				'WpieFw\Wpie\WpieAutoUpdate'
				);
	}

	/**
	 * Initialize multi language setups
	 *
	 * @access private
	 *
	 * @uses WpieMultiLangProcessor class
	 *
	 * @todo add support for more multi language plugins
	 *
	 * Support now:
	 *
	 *  - WPML
	 *
	 * @since 1.2
	 */
	private function initMultiLang()
	{
		if( ! WpieMultilangHelper::hasActivePlugin() ) {
			return;
		}

		$optionlanguages = $this->getGlobal( 'optionLanguages' );

		$factory = new WpieMultilangFactory();

		// Create WpieMultilangDefinition instance
		$definitions = new WpieMultilangDefinition(
			[
				// define the option name which stores the active languages
				'langs' => $optionlanguages
			]
		);

		// Create a WpieWpOptionsResolver instance
		$resolver = new WpieWpOptionsResolver( $definitions );

		// Create WpieMultilangValues instance
		$values = new WpieMultilangValues( $resolver, $definitions );

		// Create a WpieMultilangPluginInterface instance
		$plugin = $factory->create( WpieMultilangHelper::getActivePlugin() );

		// Create WpieMultilangProcessor instance
		$processor = $this->wpieSrc->create(
			'WpieFw\Multilang\WpieMultilangProcessor',
			[ $plugin, $values ]
		);

		// let plugin instance set params
		$processor->init();

		add_action( $this->nameSpace . '_after_init_settings', [ $processor, 'afterInitSettings' ] );
		add_action( $this->nameSpace . '_after_init_settings_page', [ $processor, 'afterInitSettingsPage' ] );
	}

	/**
	 * Initialize the WeePie Plugin settings
	 *
	 * @access private
	 *
	 * @since 1.2
	 */
	private function initSettings()
	{
		$multilang = $this->wpieSrc->get( 'multilangprocessor', false );
		$locale = ( false !== $multilang ) ? $multilang->activeLocale : $this->getGlobal( 'locale' );

		if( !$this->getGlobal( 'doSettings' ) ) {
			$this->wpieSrc->create(
				'WpieFw\Settings\WpieSettingsProcessor',
				[ new WpieSettingsCollection(), $locale ]
			);

			return;
		}

		$path = $this->getGlobal( 'settingsPath' );
		$uri = $this->getGlobal( 'settingsUri' );
		$optionSettings = $this->getGlobal( 'optionSettings' );
		$optionSettingDefault = $this->getGlobal( 'optionSettingDefault' );

		// Create WpieSettingsFactory instance
		$settingsFactory = new WpieSettingsFactory();

		// Create WpieSettingValuesResolverFactory instance
		$valuesResolverFactory = new WpieSettingValuesResolverFactory( 'wp_options' );

		// Create WpieFileFinder instance and set $recursive to FALSE
		$finder = new WpieFileFinder( $path, 'xml', $this->nameSpace . '-tab-', '', false );

		// Create WpieSettingsDefinition instance
		$definitions = new WpieSettingsDefinition(
			[
				// define the settings file locations
				'files' => $optionSettings,
				// the default setting
				'default' => $optionSettingDefault,
				// and a blueprint for the settings file name
				'setting' => sprintf( '%s_settings_{IDX}', $this->nameSpace ),
				// and a blueprint for the settings temporary file name
				'setting_tmp' => sprintf( '%s_settings_{IDX}_tmp', $this->nameSpace ),
				// and the settings fields
				'array' => sprintf( '%s_settings_{IDX}_fields', $this->nameSpace ),
			],
			['IDX']
		);

		// Create WpieSettingsValues instance
		$values = new WpieSettingsValues( $valuesResolverFactory, $definitions );

		// Create WpieSettingsGenerator instance
		$generator = $this->wpieSrc->create(
				'WpieFw\Settings\WpieSettingsGenerator',
				[ $settingsFactory, $finder, $values ]
				);

		$generator->maybeReset();
		$generator->resolveFiles();
		$generator->create( $multilang );

		// get the collection with WpieSettings instances
		$collection = $generator->getCollection();

		$processor = $this->wpieSrc->create(
				'WpieFw\Settings\WpieSettingsProcessor',
				[ $collection, $locale ]
				);

		/**
		 * @todo add comment for {nameSpace}_after_init_settings
		 */
		do_action( $this->nameSpace . '_after_init_settings', $processor );
	}

	/**
	 * Initialize the WeePie Plugin settings page
	 *
	 * @access private
	 *
	 * @uses WpiePluginSettingsPage class
	 *
	 * @since 1.2
	 */
	private function initSettingsPage()
	{
		$pageTitle = $this->getGlobal( 'pageTitle', '' );
		$menuTitle = $this->getGlobal( 'menuTitle', '' );
		$processor = $this->wpieSrc->get( 'settingsprocessor', false );

		// Expepecting a valid WpieSettingsProcessor here if doSettings is true
		if( !$processor && $this->getGlobal( 'doSettings' ) ) {
			throw new WpieUnexpectedValueException( 'Instance of WpieSettingsProcessor is false while doSettings is true.' );
			return;
		}

		$settingsPage = $this->wpieSrc->create(
				'WpieFw\Settings\WpieSettingsPage',
				[ $pageTitle, $menuTitle ]
				);

		// Add the WpieSettingsPage instance to the WpieSettingsProcessor instance
		$processor->settingsPage = $settingsPage;

		if( !$this->getGlobal( 'doSettings' ) ) {
			return;
		}

		if( $processor->settings->hasCollection() ) {
			// Init the settings page logic
			$processor->initSettingsPage();

			/**
			 * @todo add comment for {nameSpace}_before_init_modules
			 */
			add_action( $this->nameSpace . '_before_init_modules', [ $processor->settingsPage, 'hook' ], 2 );

			// @todo check tabs else set false
			$processor->hasSettingsPage = true;

			/**
			 * @todo add comment for {nameSpace}_after_init_settings_page
			 */
			do_action( $this->nameSpace . '_after_init_settings_page', $processor );
		}
	}

	/**
	 * Initialize WeePie Framework Plugin modules
	 *
	 * An instance of class WpiePluginModuleProcessor is created.
	 * This instance search, inits and hooks the modules to the Plugin
	 *
	 * Plugins that extend the WeePie Framework can place Modules in folder '[YOUR_PLUGIN_ROOT]/modules'.
	 *
	 * @access private
	 *
	 * @param bool $reset flag to delete the database option first
	 *
	 * @uses WpiePluginModuleProcessor::deleteModulesOption()
	 * @uses WpiePluginModuleProcessor::findModules()
	 * @uses WpiePluginModuleProcessor::includeModule()
	 * @uses WpiePluginModuleProcessor::init()
	 * @uses WpiePluginModuleProcessor::hook()
	 *
	 * @since 0.1
	 */
	private function initModules()
	{
		$path = $this->getGlobal( 'modulePath' );
		$modules = $this->getGlobal( 'optionModules' );
		$settingsProcessor = $this->wpieSrc->get( 'settingsprocessor', false );

		// Create WpieModulesFactory instance
		$modulesFactory = new WpieModulesFactory();
		// Create WpieModulesBuilder instance
		$modulesBuilder = new WpieModulesBuilder( $modulesFactory );
		// Create WpieSettingValuesResolverFactory instance
		$valuesResolverFactory = new WpieModuleValuesResolverFactory( 'wp_options' );

		$finder = new WpieFileFinder( $path, 'php', $this->nameSpace . '-module-' );

		// Create WpieModulesDefinition instance
		$definitions = new WpieModulesDefinition(
			[
				// define the modules file locations
				'files' => $modules,
			]
		);

		// Create WpieModulesValues instance
		$values = new WpieModulesValues( $valuesResolverFactory, $definitions );

		// Create WpieSettingsGenerator instance
		$generator = $this->wpieSrc->create(
				'WpieFw\Modules\WpieModulesGenerator',
				[ $modulesBuilder, $finder, $values, 'settingsprocessor' ]
				);

		$generator->maybeReset();
		$generator->resolveFiles();
		$generator->load();
		$generator->create();

		// Get the module collection
		$collection = $generator->getCollection();

		$processor = $this->wpieSrc->create(
				'WpieFw\Modules\WpieModuleProcessor',
				[ $collection ]
				);

		// loop over all modules and start init process:
		// * call hook {nameSpace}_module_before_start
		// * call WpieModule::start()
		// * call hook {nameSpace}_module_after_start
		// * hook into different actions
		$processor->init();

 		do_action( $this->nameSpace . '_before_init_modules', $settingsProcessor );

 		$processor->hook();

 		do_action( $this->nameSpace . '_after_init_modules' );
	}

	/**
	 * Init WpieSrc instance
	 *
	 * @param WpieGlobals $globals
	 *
	 * @since 1.4.0
	 */
	private function initWpieSrc( WpieGlobals $globals )
	{
		// Create the WpieSrc instance and add the WpieGlobals
		$this->wpieSrc = new WpieSrc( $globals );
	}

	/**
	 * Init the WpieHooks instance.
	 *
	 * The add method will setup all hooks
	 *
	 * @acces private
	 *
	 * @uses WpieHooks
	 * @uses WpieHooks::add()
	 *
	 * @since 1.4.0
	 */
	private function initHooks()
	{
	    // Return on not authenticated admin requests, but only when not doing a Wpie AJAX request
	    if( is_admin() && !is_user_logged_in() && !WpieAjaxHelper::doingWpieAction() ) {
	        return;
	    }

	    if( is_admin() ) {
			$hooks = $this->wpieSrc->create(
					'WpieFw\Hooks\WpieHooksAdmin',
					[ 'settingsprocessor' ]
					);
		} else {
			$hooks = $this->wpieSrc->create(
					'WpieFw\Hooks\WpieHooksFrontend'
					);
		}

		// Add the hooks for admin or frontend
		$hooks->add();

		if( is_admin() ) {
			/**
			 * Let others hook after admin hooks are added
			 */
			do_action( $this->nameSpace . '_init_admin_only_hooks' );

		} elseif( !is_admin() && $hooks->doFrontend ) {
			/**
			 * Let others hook after frontend hooks are added
			 */
			do_action( $this->nameSpace . '_init_frontend_only_hooks' );
		}

		/**
		 * Let others hook after hooks are added
		 */
		do_action( $this->nameSpace . '_init_hooks' );
	}

	/**
	 * Init shortcodes for modules
	 *
	 * @acces private
	 *
	 * @uses add_shortcode()
	 *
	 * @since 1.2.5
	 */
	private function initShortcodes()
	{
		$this->wpieSrc->create(
				'WpieFw\Shortcodes\WpieShortcodes'
				)
			->add();
	}

	/**
	 * Init rest api for modules
	 *
	 * @acces private
	 *
	 * @since 2.0.14
	 */
	private function initRestApi()
	{
		$this->wpieSrc->create(
				'WpieFw\Rest\WpieRestApi'
				)
			->init();
	}


	/**
	 * Init src classes and logic
	 *
	 * @access private
	 *
	 * @param array $what specifies what should be initiated
	 *
	 * @uses wp_parse_args()
	 * @uses self::initAutoUpdate()
	 * @uses self::initMultiLang()
	 * @uses self::initSettings()
	 * @uses self::initSettingsPage()
	 * @uses self::initModules()
	 * @uses self::initHooks()
	 * @uses self::initShortcodes()
	 *
	 * @since 2.0.1
	 */
	private function init( array $what = [] )
	{
		$args = wp_parse_args( $what, [
				'autoupdate'   => 0,
				'multiLang'    => 0,
				'settings'     => 0,
				'settingspage' => 0,
				'modules'      => 0,
				'hooks'        => 0,
				'shortcodes'   => 0,
				'restapi'      => 0
		] );

		extract( $args );

		if( $autoupdate ) {
			// Init the Envato auto updating logic
			$this->initAutoUpdate();
		}
		if( $multiLang ) {
			$this->initMultiLang();
		}
		if( $settings ) {
			$this->initSettings();
		}
		if( $settingspage ) {
			$this->initSettingsPage();
		}
		if( $modules ) {
			$this->initModules();
		}
		if( $hooks ) {
			$this->initHooks();
		}
		if( $shortcodes ) {
			$this->initShortcodes();
		}
		if( $restapi ) {
			$this->initRestApi();
		}
	}
}