<?php

/**
 * If Polylang is active:
 * - save and retrieve customizer setting per language
 * - on front-page, set options and theme mod for the selected language
 * - expect customizer to use setting type = theme_mod (the customizer default), only exceptions are 'blog', 'blogname' and 'site_icon' (see $option_types )
 *
 * Inspired by https://github.com/fastlinemedia/customizer-export-import
 */

namespace Richardevcom\Apsfc;

// Instantiate the class.
$GLOBAL['apsfc'] = Apsfc::init();

/**
 * Class Apsfc
 *
 * @package Dekode\DSS\Nettsteder_Mal
 */
class Apsfc
{
	var $settings = false;

	/**
	 * Static factory
	 *
	 * @link https://carlalexander.ca/static-factory-method-pattern-wordpress/, https://carlalexander.ca/designing-class-wordpress-hooks/
	 *
	 * @return void
	 */
	public static function init()
	{
		$self = new self();
		$options = get_option('polylang');

		/**
		 * Force "The language is set from content" (in Language->Settings->URL modifications)
		 */
		if (get_option('apsfc_force_lang') == "on") {
			if (isset($options['force_lang']) && 0 !== $options['force_lang']) {
				$options['force_lang'] = 0;
				update_option('polylang', $options);
			}
		}

		/**
		 * Disable detect browser language, will return default language instead.
		 */
		// add_filter( 'pll_preferred_language', '__return_false' );

		\add_action('customize_controls_enqueue_scripts', [$self, 'add_lang_to_customizer_previewer'], 9);
		\add_action('wp_before_admin_bar_render', [$self, 'on_wp_before_admin_bar_render'], 100);
		\add_action('admin_menu', [$self, 'on_admin_menu'], 100);

		$theme_stylesheet_slug = get_option('stylesheet');
		$option_types          = ['blogname', 'blogdescription', 'site_icon'];

		// Get theme mod options.
		add_filter('option_theme_mods_' . $theme_stylesheet_slug, [$self, 'on_option_theme_mods_get'], 10, 1);
		// Update theme mod options.
		add_filter('pre_update_option_theme_mods_' . $theme_stylesheet_slug, [$self, 'on_option_theme_mods_update'], 10, 2);

		foreach ($option_types as $option_type) {
			add_filter('pre_option_' . $option_type, [$self, 'on_wp_option_get'], 10, 3); // get_option hook.
			add_filter('pre_update_option_' . $option_type, [$self, 'on_wp_option_update'], 10, 3); // update_option hook.
		}

		return $self;
	}

	/**
	 * Initialize Polylang API so we can call some function prematurely its initialization.
	 *
	 * @return void
	 */
	public function premature_initialization()
	{
		if (!function_exists('pll_current_language')) {
			$poly_file = WP_PLUGIN_DIR . '/polylang/include/api.php';
			if (!file_exists($poly_file)) {
				$poly_file = WP_PLUGIN_DIR . '/polylang-pro/include/api.php';
				if (!file_exists($poly_file)) $poly_file = WP_PLUGIN_DIR . '/polylang-pro/vendor/wpsyntex/polylang/include/api.php';
			}

			require $poly_file;
			if (!isset($GLOBALS['polylang'])) $GLOBALS['polylang'] = null;
		}
	}

	/**
	 * Load plugin textdomain.
	 *
	 * @since 1.0.2
	 */
	public function pc_load_textdomain()
	{
		load_plugin_textdomain('apsfc', false, basename(dirname(__FILE__)) . '/languages');
	}


	/**
	 * Constructor.
	 */
	private function __construct()
	{
		/**
		 * Prematurely initialize Polylang API
		 */
		add_action('plugins_loaded', [$this, 'premature_initialization']);

		/**
		 * Load plugin text domain (l10n)
		 */
		add_action('plugins_loaded', [$this, 'pc_load_textdomain'], 0);
		$this->setup_settings();
	}

	/**
	 * Setup settings & pages
	 */
	function setup_settings()
	{
		require_once dirname(__FILE__) . '/class-settings.php';
		$settings = new ApsfcSettings();
	}

	/**
	 * Helper to fetch custom customizer db content.
	 *
	 * @return mixed Customizer array or false.
	 */
	protected function get_custom_customizer_option()
	{
		$current_language = pll_current_language();
		$theme_slug       = get_option('template');
		$option_prefix    = \str_replace('-', '_', $theme_slug);
		$option_name      = $option_prefix . '_apsfc_settings_' . $current_language;

		return get_option($option_name, false);
	}

	/**
	 * Helper to update custom customizer db content.
	 *
	 * @param mixed $data Data to insert.
	 *
	 * @return bool Success.
	 */
	protected function update_custom_customizer_option($data)
	{
		$current_language = pll_current_language();
		$theme_slug       = get_option('template');
		$option_prefix    = \str_replace('-', '_', $theme_slug);
		$option_name      = $option_prefix . '_apsfc_settings_' . $current_language;

		return update_option($option_name, $data);
	}

	/**
	 * Helper
	 *
	 * @return bool If the current language is the default language.
	 */
	protected function current_lang_not_default()
	{
		if (function_exists('pll_current_language')) return pll_current_language() !== pll_default_language();
		return false;
	}

	/**
	 * Check the custom db field on get_option hook to be able to return custom language value.
	 * If the current language is default, then return from default wp option
	 *
	 * @param bool   $pre_option This is false. If something else is returned wp exits the check in db and uses this value.
	 * @param string $option Option name asked for.
	 * @param mixed  $default Default value, second args when asking for options.
	 *
	 * @return mixed
	 */
	public function on_wp_option_get($pre_option, $option, $default)
	{

		// If not the default language, then skip the custom check and wp will the use default options.
		if ($this->current_lang_not_default()) {
			$data = $this->get_custom_customizer_option();

			// Found the custom option. Move on.
			if (is_array($data) && isset($data['options']) && isset($data['options'][$option])) {
				return $data['options'][$option];
			}
		}

		return $default;
	}

	/**
	 * Update the custom db field on get_option hook.
	 * If the current language is not default, then return old value to prevent from saving to default wp option.
	 *
	 * @param mixed  $value The new, unserialized option value.
	 * @param mixed  $old_value The old option value.
	 * @param string $option Option name.
	 *
	 * @return mixed
	 */
	public function on_wp_option_update($value, $old_value, $option)
	{
		// Fetch custom option db field.
		$data       = $this->get_custom_customizer_option();
		$theme_slug = get_option('template');
		// If false, the field hasn't been created yet, so it must be created.
		if (false === $data) {
			$data = [
				'template' => $theme_slug,
				'mods'     => [],
				'options'  => [],
			];
		}

		// Make sure the options array exists. We are going to use it soon.
		if (!isset($data['options'])) {
			$data['options'] = [];
		}

		$data['options'][$option] = $value;

		// Update option value in custom db field. (Not necessary to save for default language since it uses default wp option fields for values when get option).
		$this->update_custom_customizer_option($data);

		// If the current language is not the default language, prevent saving to option table by passing the old value back. It will then exit after the filter.
		if ($this->current_lang_not_default()) {
			return $old_value;
		}

		return $value;
	}

	/**
	 * Check the custom db field on get_option customizer field option name hook to be able to return custom language value.
	 * Parse arguments with default wp customizer values to make sure all are present in the return.
	 *
	 * @param array $value The customizer settings.
	 *
	 * @return array
	 */
	public function on_option_theme_mods_get($value)
	{
		$data = $this->get_custom_customizer_option();

		if (isset($data['mods']) && is_array($data['mods']) && !empty($data['mods'])) {
			$value = wp_parse_args($data['mods'], $value);
		}

		// Remove members with integer key from mods.
		foreach ($value as $key => $mod) {
			if (is_numeric($key)) {
				unset($value[$key]);
			}
		}

		return $value;
	}

	/**
	 * Update custom customizer option.
	 * If the current language is not default, then return old value to prevent from saving to customizer wp option.
	 *
	 * @param mixed $value The new, unserialized option value.
	 * @param mixed $old_value The old option value.
	 */
	public function on_option_theme_mods_update($value, $old_value)
	{

		$current_data = $this->get_custom_customizer_option();
		$theme_slug   = get_option('template');

		$data = [
			'template' => $theme_slug,
			'mods'     => isset($current_data['mods']) ? $current_data['mods'] : [],
			'options'  => isset($current_data['options']) ? $current_data['options'] : [],
		];

		if (is_array($value) && !empty($value)) {
			foreach ($value as $key => $val) {
				$data['mods'][$key] = $val;
			}
		}
		$this->update_custom_customizer_option($data);

		if ($this->current_lang_not_default()) {
			return $old_value;
		}

		return $value;
	}

	/**
	 * If Polylang activated, set the preview url and add select language control
	 *
	 * @author soderlind
	 * @version 1.0.0
	 * @link https://gist.github.com/soderlind/1908634f5eb0c1f69428666dd2a291d0
	 */
	public function add_lang_to_customizer_previewer()
	{
		$language = (empty($_REQUEST['lang'])) ? pll_current_language() : $_REQUEST['lang'];
		if (empty($language)) $language = pll_default_language();

		if (is_customize_preview() && (!isset($_REQUEST['lang']) || $_REQUEST['lang'] == 'all' || empty($_REQUEST['lang']))) {
			$url = get_admin_url() . 'customize.php?lang=' . $language; // EDIT this to your needs
			wp_safe_redirect($url);
			var_dump($url);
			exit();
		}

		$handle    = 'dss-add-lang-to-template';
		$src       = plugin_dir_url(dirname(__FILE__)) . 'assets/js/apsfc.js';
		$deps      = ['customize-controls'];
		$version   = rand();
		$in_footer = 1;
		wp_enqueue_script($handle, $src, $deps, $version, $in_footer);

		if (empty($language)) {
			$language = pll_default_language();
		}

		if (!empty($_REQUEST['url'])) {
			$current_url = add_query_arg('lang', $language, $_REQUEST['url']);
		} else {
			$current_url = add_query_arg('lang', $language, pll_home_url($language));
		}
		wp_add_inline_script(
			$handle,
			sprintf(
				'var pcLangTrans = "' . __('Language', 'apsfc') . '";' .
					'PSPolyLang.init( %s );',
				wp_json_encode(
					[
						'url'              => $current_url,
						'languages'        => get_transient('pll_languages_list'),
						'current_language' => $language,
					]
				)
			),
			'after'
		);
	}

	/**
	 * Append lang="contrycode" to the customizer url in the adminbar
	 *
	 * @return void
	 */
	public function on_wp_before_admin_bar_render()
	{
		global $wp_admin_bar;
		$customize_node = $wp_admin_bar->get_node('customize');
		if (!empty($customize_node)) {
			$customize_node->href = add_query_arg('lang', pll_current_language(), $customize_node->href);
			$wp_admin_bar->add_node($customize_node);
		}
	}

	/**
	 * Append lang="contrycode" to the customizer url in the Admin->Apperance->Customize menu
	 *
	 * @return void
	 */
	public function on_admin_menu()
	{
		global $submenu;
		$parent = 'themes.php';
		if (!isset($submenu[$parent])) {
			return;
		}
		foreach ($submenu[$parent] as $k => $d) {
			if ('customize' === $d['1']) {
				$submenu[$parent][$k]['2'] = add_query_arg('lang', pll_current_language(), $submenu[$parent][$k]['2']);
				break;
			}
		}
	}
}

if (class_exists('WP_Customize_Setting')) {
	/**
	 * A class that extends WP_Customize_Setting so we can access
	 * the protected updated method when importing options.
	 *
	 * @since 0.3
	 */
	final class CustomizerPolylangOption extends \WP_Customize_Setting
	{


		/**
		 * Import an option value for this setting.
		 *
		 * @since 0.3
		 *
		 * @param mixed $value The option value.
		 *
		 * @return void
		 */
		public function import($value)
		{
			$this->update($value);
		}
	}
}

/**
 * Polylang register strings.
 */

if (function_exists('pll_register_string')) {

	/**
	 * Register fields for Polylang string translations
	 *
	 * @param string $option_name Option name
	 * @param array  $fields Field names
	 *
	 * @return void
	 */
	function register_polylang_column_strings($option_name, $fields)
	{
		$columns    = get_option($option_name);
		$theme_name = wp_get_theme()->get('Name');
		if (!empty($columns)) :
			for ($i = 0; $i < $columns; $i++) :
				foreach ($fields as $field) {
					pll_register_string($option_name . '_' . $i . '_' . $field, get_option($option_name . '_' . $i . '_' . $field), $theme_name, true);
				}
			endfor;
		endif;
	}

	register_polylang_column_strings('options_footer_columns', ['title', 'text']);
	register_polylang_column_strings('options_footer_logos', ['image', 'url']);
}
