<?php
/**
 * File that define P24_Config_Accessor class.
 *
 * @package Przelewy24
 */

defined( 'ABSPATH' ) || exit;

/**
 * Accessor for P24_Config_Holder.
 *
 * This class know active currency and style of booleans.
 * These two properties are unknown to P24_Config_Holder.
 */
class P24_Config_Accessor {

	const AM_STRICT    = 'am_strict';
	const AM_WORDPRESS = 'am_wordpress';

	/**
	 * Name of currency that is described by config.
	 *
	 * @var string
	 */
	private $currency;

	/**
	 * The object holding config.
	 *
	 * @var P24_Config_Holder
	 */
	private $config;

	/**
	 * The style of accessor.
	 *
	 * The booleans may be expected to be in form yes/no.
	 *
	 * @var string
	 */
	private $access_mode;

	/**
	 * Array holding translation of bool representations.
	 *
	 * @var array
	 */
	private $bool_translation_table;

	/**
	 * The constructor.
	 *
	 * The default boolean mode is yes/no.
	 *
	 * @param string            $currency Name of currency.
	 * @param P24_Config_Holder $config The config.
	 */
	public function __construct( $currency, P24_Config_Holder $config ) {
		$this->currency = (string) $currency;
		$this->config   = $config;
		$this->access_mode_to_wordpress();
		$this->bool_translation_table = array(
			self::AM_STRICT    => array( false, true ),
			self::AM_WORDPRESS => array( 'no', 'yes' ),
		);
		$this->fix_booleans();
	}

	/**
	 * Convert variable to selected bool representation.
	 *
	 * @param bool $input The input variable to be converted.
	 * @return bool|string
	 * @throws InvalidArgumentException If conversion cannot be made.
	 */
	public function to_selected_bool( $input ) {
		if ( false === $input ) {
			return $this->bool_translation_table[ $this->access_mode ][0];
		} elseif ( true === $input ) {
			return $this->bool_translation_table[ $this->access_mode ][1];
		} else {
			throw new InvalidArgumentException( 'Wrong input type, it has to be bool.' );
		}
	}

	/**
	 * Convert variable from selected bool representation.
	 *
	 * @param bool|string $input The input variable to be converted.
	 * @return bool
	 * @throws InvalidArgumentException If conversion cannot be made.
	 */
	public function from_selected_bool( $input ) {
		$row = $this->bool_translation_table[ $this->access_mode ];
		$key = array_search( $input, $row, true );
		if ( 0 === $key ) {
			return false;
		} elseif ( 1 === $key ) {
			return true;
		} else {
			throw new InvalidArgumentException( 'Wrong input, it cannot be converted to bool.' );
		}
	}

	/**
	 * Convert all booleans in config to PHP representation.
	 */
	private function fix_booleans() {
		$to_fix       = array(
			'pass_cart',
			'p24_oneclick',
			'p24_payinshop',
			'p24_acceptinshop',
			'p24_show_methods_checkout',
			'p24_show_methods_confirmation',
			'p24_graphics',
			'p24_wait_for_result',
			'p24_use_special_status',
			'sub_enabled',
			'p24_send_payment_reminder',
			'p24_admin_mail_early_on_new_order',
			'p24_client_mail_on_hold_at_pending',
		);
		$default_true = array(
			'pass_cart',
		);
		foreach ( $to_fix as $one ) {
			if ( null === $this->config->{$one} ) {
				$this->config->{$one} = in_array( $one, $default_true, true );
			} elseif ( ! is_bool( $this->config->{$one} ) ) {
				$this->config->{$one} = self::from_selected_bool( $this->config->{$one} );
			}
		}
	}

	/**
	 * The cloner.
	 */
	public function __clone() {
		$this->config = clone $this->config;
	}

	/**
	 * Set access mode for booleans to PHP types.
	 *
	 * @return $this
	 */
	public function access_mode_to_strict() {
		$this->access_mode = self::AM_STRICT;
		return $this;
	}

	/**
	 * Set access mode for booleans to strings yes and no.
	 *
	 * @return $this
	 */
	public function access_mode_to_wordpress() {
		$this->access_mode = self::AM_WORDPRESS;
		return $this;
	}

	/**
	 * Get currency.
	 *
	 * @return string
	 */
	public function get_currency() {
		return (string) $this->currency;
	}

	/**
	 * Get title from config.
	 *
	 * @return string
	 */
	public function get_title() {
		return (string) $this->config->title;
	}

	/**
	 * Set title in config.
	 *
	 * @param string $title The new title.
	 * @return P24_Config_Accessor
	 */
	public function set_title( $title ) {
		$this->config->title = (string) $title;
		return $this;
	}

	/**
	 * Get merchant_id from config.
	 *
	 * @return string
	 */
	public function get_merchant_id() {
		return (string) $this->config->merchant_id;
	}

	/**
	 * Set merchant_id in config.
	 *
	 * @param string $merchant_id The new merchant_id.
	 * @return P24_Config_Accessor
	 */
	public function set_merchant_id( $merchant_id ) {
		$this->config->merchant_id = (string) $merchant_id;
		return $this;
	}

	/**
	 * Get shop_id form config.
	 *
	 * @return string
	 */
	public function get_shop_id() {
		return (string) $this->config->shop_id;
	}

	/**
	 * Set shop_id in config.
	 *
	 * @param string $shop_id The new shop_id.
	 * @return P24_Config_Accessor
	 */
	public function set_shop_id( $shop_id ) {
		$this->config->shop_id = (string) $shop_id;
		return $this;
	}

	/**
	 * Get salt from config.
	 *
	 * @return string
	 */
	public function get_salt() {
		return (string) $this->config->salt;
	}

	/**
	 * Set salt in config.
	 *
	 * @param string $salt The new salt.
	 * @return P24_Config_Accessor
	 */
	public function set_salt( $salt ) {
		$this->config->salt = (string) $salt;
		return $this;
	}

	/**
	 * Get operation mode from config.
	 *
	 * @return string The new p24_operation_mode
	 */
	public function get_p24_operation_mode() {
		return (string) $this->config->p24_operation_mode;
	}

	/**
	 * Set operation mode in config.
	 *
	 * @param string $p24_operation_mode The new p24_operation_mode.
	 * @return P24_Config_Accessor
	 */
	public function set_p24_operation_mode( $p24_operation_mode ) {
		$this->config->p24_operation_mode = (string) $p24_operation_mode;
		return $this;
	}

	/**
	 * Compare modes and return bool.
	 *
	 * @param string $checked The value to compare mode with.
	 * @return bool|string
	 */
	public function is_p24_operation_mode( $checked ) {
		$mode    = $this->get_p24_operation_mode();
		$is_mode = $checked === $mode;
		return $this->to_selected_bool( $is_mode );
	}

	/**
	 * Get description from config.
	 *
	 * @return string
	 */
	public function get_description() {
		return (string) $this->config->description;
	}

	/**
	 * Set description in config.
	 *
	 * @param string $description The new description.
	 * @return P24_Config_Accessor
	 */
	public function set_description( $description ) {
		$this->config->description = (string) $description;
		return $this;
	}

	/**
	 * Get p24_api from config.
	 *
	 * @return string
	 */
	public function get_p24_api() {
		return (string) $this->config->p24_api;
	}

	/**
	 * Set p24_api in config.
	 *
	 * @param string $p24_api The new p24_api.
	 * @return P24_Config_Accessor
	 */
	public function set_p24_api( $p24_api ) {
		$this->config->p24_api = (string) $p24_api;
		return $this;
	}

	/**
	 * Return pass_cart from config.
	 *
	 * The value is converted to selected representation.
	 *
	 * @return bool|string
	 * @throws LogicException If the internal representation of value is broken.
	 */
	public function get_pass_cart() {
		try {
			$pass_cart = $this->config->pass_cart;
			return $this->to_selected_bool( $pass_cart );
		} catch ( InvalidArgumentException $ex ) {
			$msg = 'The internal representation of conceal_cart is invalid.';
			throw new LogicException( esc_html( $msg ) );
		}
	}

	/**
	 * Set pass_cart in config.
	 *
	 * The input is expected to be in selected representation.
	 *
	 * @param bool|string $pass_cart The new pass_cart.
	 * @return P24_Config_Accessor
	 * @throws InvalidArgumentException If input is in wrong representation.
	 */
	public function set_pass_cart( $pass_cart ) {
		$this->config->pass_cart = $this->from_selected_bool( $pass_cart );
		return $this;
	}

	/**
	 * Get p24_paymethods_super_first from config.
	 *
	 * @return string
	 */
	public function get_p24_paymethods_super_first() {
		return (string) $this->config->p24_paymethods_super_first;
	}

	/**
	 * Set p24_paymethods_super_first in config.
	 *
	 * @param string $p24_paymethods_super_first The new p24_paymethods_first.
	 * @return P24_Config_Accessor
	 */
	public function set_p24_paymethods_super_first( $p24_paymethods_super_first ) {
		$this->config->p24_paymethods_super_first = (string) $p24_paymethods_super_first;
		return $this;
	}

	/**
	 * Return p24_oneclick from config.
	 *
	 * The value is converted to selected representation.
	 *
	 * @return bool|string
	 * @throws LogicException If the internal representation of value is broken.
	 */
	public function get_p24_oneclick() {
		try {
			$p24_oneclick = $this->config->p24_oneclick;
			return $this->to_selected_bool( $p24_oneclick );
		} catch ( InvalidArgumentException $ex ) {
			$msg = 'The internal representation of p24_oneclick is invalid.';
			throw new LogicException( esc_html( $msg ) );
		}
	}

	/**
	 * Set p24_oneclick in config.
	 *
	 * The input is expected to be in selected representation.
	 *
	 * @param bool|string $p24_oneclick The new p24_oneclick.
	 * @return P24_Config_Accessor
	 * @throws InvalidArgumentException If input is in wrong representation.
	 */
	public function set_p24_oneclick( $p24_oneclick ) {
		$this->config->p24_oneclick = $this->from_selected_bool( $p24_oneclick );
		return $this;
	}

	/**
	 * Return p24_payinshop from config.
	 *
	 * The value is converted to selected representation.
	 *
	 * @return bool|string
	 * @throws LogicException If the internal representation of value is broken.
	 */
	public function get_p24_payinshop() {
		try {
			$p24_payinshop = $this->config->p24_payinshop;
			return $this->to_selected_bool( $p24_payinshop );
		} catch ( InvalidArgumentException $ex ) {
			$msg = 'The internal representation of p24_payinshop is invalid.';
			throw new LogicException( esc_html( $msg ) );
		}
	}

	/**
	 * Set p24_acceptinshop in config.
	 *
	 * The input is expected to be in selected representation.
	 *
	 * @param bool|string $p24_acceptinshop The new p24_oneclick.
	 * @return P24_Config_Accessor
	 * @throws InvalidArgumentException If input is in wrong representation.
	 */
	public function set_p24_acceptinshop( $p24_acceptinshop ) {
		$this->config->p24_acceptinshop = $this->from_selected_bool( $p24_acceptinshop );
		return $this;
	}

	/**
	 * Return p24_acceptinshop from config.
	 *
	 * The value is converted to selected representation.
	 *
	 * @return bool|string
	 * @throws LogicException If the internal representation of value is broken.
	 */
	public function get_p24_acceptinshop() {
		try {
			$p24_acceptinshop = $this->config->p24_acceptinshop;
			return $this->to_selected_bool( $p24_acceptinshop );
		} catch ( InvalidArgumentException $ex ) {
			$msg = 'The internal representation of p24_acceptinshop is invalid.';
			throw new LogicException( esc_html( $msg ) );
		}
	}

	/**
	 * Set p24_payinshop in config.
	 *
	 * The input is expected to be in selected representation.
	 *
	 * @param bool|string $p24_payinshop The new p24_payinshop.
	 * @return P24_Config_Accessor
	 * @throws InvalidArgumentException If input is in wrong representation.
	 */
	public function set_p24_payinshop( $p24_payinshop ) {
		$this->config->p24_payinshop = $this->from_selected_bool( $p24_payinshop );
		return $this;
	}

	/**
	 * Return p24_show_methods_checkout from config.
	 *
	 * The value is converted to selected representation.
	 *
	 * @return bool|string
	 * @throws LogicException If the internal representation of value is broken.
	 */
	public function get_p24_show_methods_checkout() {
		try {
			$p24_show_methods_checkout = $this->config->p24_show_methods_checkout;
			return $this->to_selected_bool( $p24_show_methods_checkout );
		} catch ( InvalidArgumentException $ex ) {
			$msg = 'The internal representation of p24_show_methods_checkout  is invalid.';
			throw new LogicException( esc_html( $msg ) );
		}
	}

	/**
	 * Set p24_show_methods_checkout in config.
	 *
	 * The input is expected to be in selected representation.
	 *
	 * @param bool|string $p24_show_methods_checkout The new p24_show_methods_checkout.
	 * @return P24_Config_Accessor
	 * @throws InvalidArgumentException If input is in wrong representation.
	 */
	public function set_p24_show_methods_checkout( $p24_show_methods_checkout ) {
		$this->config->p24_show_methods_checkout = $this->from_selected_bool( $p24_show_methods_checkout );
		return $this;
	}

	/**
	 * Return p24_show_methods_confirmation from config.
	 *
	 * The value is converted to selected representation.
	 *
	 * @return bool|string
	 * @throws LogicException If the internal representation of value is broken.
	 */
	public function get_p24_show_methods_confirmation() {
		try {
			$p24_show_methods_confirmation = $this->config->p24_show_methods_confirmation;
			return $this->to_selected_bool( $p24_show_methods_confirmation );
		} catch ( InvalidArgumentException $ex ) {
			$msg = 'The internal representation of p24_show_methods_confirmation is invalid.';
			throw new LogicException( esc_html( $msg ) );
		}
	}

	/**
	 * Set p24_show_methods_confirmation in config.
	 *
	 * The input is expected to be in selected representation.
	 *
	 * @param bool|string $p24_show_methods_confirmation The new p24_show_methods_confirmation.
	 * @return P24_Config_Accessor
	 * @throws InvalidArgumentException If input is in wrong representation.
	 */
	public function set_p24_show_methods_confirmation( $p24_show_methods_confirmation ) {
		$this->config->p24_show_methods_confirmation = $this->from_selected_bool( $p24_show_methods_confirmation );
		return $this;
	}

	/**
	 * Return p24_graphics from config.
	 *
	 * The value is converted to selected representation.
	 *
	 * @return bool|string
	 * @throws LogicException If the internal representation of value is broken.
	 */
	public function get_p24_graphics() {
		try {
			$p24_graphics = $this->config->p24_graphics;
			return $this->to_selected_bool( $p24_graphics );
		} catch ( InvalidArgumentException $ex ) {
			$msg = 'The internal representation of p24_graphics is invalid.';
			throw new LogicException( esc_html( $msg ) );
		}
	}

	/**
	 * Set p24_graphics in config.
	 *
	 * The input is expected to be in selected representation.
	 *
	 * @param bool|string $p24_graphics The new p24_graphics.
	 * @return P24_Config_Accessor
	 * @throws InvalidArgumentException If input is in wrong representation.
	 */
	public function set_p24_graphics( $p24_graphics ) {
		$this->config->p24_graphics = $this->from_selected_bool( $p24_graphics );
		return $this;
	}

	/**
	 * Get p24_paymethods_first from config.
	 *
	 * @return string
	 */
	public function get_p24_paymethods_first() {
		return (string) $this->config->p24_paymethods_first;
	}

	/**
	 * Set p24_paymethods_first in config.
	 *
	 * @param string $p24_paymethods_first The new p24_paymethods_first.
	 * @return P24_Config_Accessor
	 */
	public function set_p24_paymethods_first( $p24_paymethods_first ) {
		$this->config->p24_paymethods_first = (string) $p24_paymethods_first;
		return $this;
	}

	/**
	 * Get p24_paymethods_second from config.
	 *
	 * @return string
	 */
	public function get_p24_paymethods_second() {
		return (string) $this->config->p24_paymethods_second;
	}

	/**
	 * Set p24_paymethods_second in config.
	 *
	 * @param string $p24_paymethods_second The new p24_paymethods_second.
	 * @return P24_Config_Accessor
	 */
	public function set_p24_paymethods_second( $p24_paymethods_second ) {
		$this->config->p24_paymethods_second = (string) $p24_paymethods_second;
		return $this;
	}

	/**
	 * Return p24_wait_for_result from config.
	 *
	 * The value is converted to selected representation.
	 *
	 * @return bool|string
	 * @throws LogicException If the internal representation of value is broken.
	 */
	public function get_p24_wait_for_result() {
		try {
			$p24_wait_for_result = $this->config->p24_wait_for_result;
			return $this->to_selected_bool( $p24_wait_for_result );
		} catch ( InvalidArgumentException $ex ) {
			$msg = 'The internal representation of p24_wait_for_result is invalid.';
			throw new LogicException( esc_html( $msg ) );
		}
	}

	/**
	 * Set p24_wait_for_result in config.
	 *
	 * The input is expected to be in selected representation.
	 *
	 * @param bool|string $p24_wait_for_result The new p24_wait_for_result.
	 * @return P24_Config_Accessor
	 * @throws InvalidArgumentException If input is in wrong representation.
	 */
	public function set_p24_wait_for_result( $p24_wait_for_result ) {
		$this->config->p24_wait_for_result = $this->from_selected_bool( $p24_wait_for_result );
		return $this;
	}

	/**
	 * Return p24_use_special_status from config.
	 *
	 * The value is converted to selected representation.
	 *
	 * @return bool|string
	 * @throws LogicException If the internal representation of value is broken.
	 */
	public function get_p24_use_special_status() {
		try {
			$p24_use_special_status = $this->config->p24_use_special_status;
			return $this->to_selected_bool( $p24_use_special_status );
		} catch ( InvalidArgumentException $ex ) {
			$msg = 'The internal representation of p24_use_special_status is invalid.';
			throw new LogicException( esc_html( $msg ) );
		}
	}

	/**
	 * Set p24_use_special_status in config.
	 *
	 * The input is expected to be in selected representation.
	 *
	 * @param bool|string $p24_use_special_status The new p24_use_special_status.
	 * @return P24_Config_Accessor
	 * @throws InvalidArgumentException If input is in wrong representation.
	 */
	public function set_p24_use_special_status( $p24_use_special_status ) {
		$this->config->p24_use_special_status = $this->from_selected_bool( $p24_use_special_status );
		return $this;
	}

	/**
	 * Get p24_custom_pending_status from config.
	 *
	 * @return string
	 */
	public function get_p24_custom_pending_status() {
		return (string) $this->config->p24_custom_pending_status;
	}

	/**
	 * Get p24_custom_pending_status from config.
	 *
	 * @return string
	 */
	public function get_p24_custom_processing_status() {
		return (string) $this->config->p24_custom_processing_status;
	}

	/**
	 * Return sub_enabled from config.
	 *
	 * The value is converted to selected representation.
	 *
	 * @return bool|string
	 * @throws LogicException If the internal representation of value is broken.
	 */
	public function get_sub_enabled() {
		try {
			$sub_enabled = $this->config->sub_enabled;
			return $this->to_selected_bool( $sub_enabled );
		} catch ( InvalidArgumentException $ex ) {
			$msg = 'The internal representation of sub_enabled is invalid.';
			throw new LogicException( esc_html( $msg ) );
		}
	}

	/**
	 * Set sub_enabled in config.
	 *
	 * The input is expected to be in selected representation.
	 *
	 * @param bool|string $sub_enabled The new sub_enabled.
	 * @return P24_Config_Accessor
	 * @throws InvalidArgumentException If input is in wrong representation.
	 */
	public function set_sub_enabled( $sub_enabled ) {
		$this->config->sub_enabled = $this->from_selected_bool( $sub_enabled );
		return $this;
	}

	/**
	 * Get p24_custom_promote_p24 from config
	 *
	 * @return bool|string
	 */
	public function get_is_custom_promoted_p24() {
		$is_pay_now_promoted = $this->config->p24_custom_promote_p24;
		return $this->to_selected_bool( $is_pay_now_promoted );
	}

	/**
	 * Get p24_add_to_alternative_button from config
	 *
	 * @return bool|string
	 */
	public function get_is_add_to_alternative_button() {
		$is_pay_now_alt_button = $this->config->p24_add_to_alternative_button;
		return $this->to_selected_bool( $is_pay_now_alt_button );
	}

	/**
	 * Get p24_send_payment_reminder from config
	 *
	 * @return bool|string
	 */
	public function get_send_payment_reminder() {
		$send_payment_reminder = $this->config->p24_send_payment_reminder;
		return $this->to_selected_bool( $send_payment_reminder );
	}

	/**
	 * Get p24_payment_reminder_delay from config
	 *
	 * @return int
	 */
	public function get_payment_reminder_delay() {
		return (int) $this->config->p24_payment_reminder_delay;
	}

	/**
	 * Get p24_admin_mail_early_on_new_order from config
	 *
	 * @return bool|string
	 */
	public function get_admin_mail_early_on_new_order() {
		$admin_mail_early_on_new_order = $this->config->p24_admin_mail_early_on_new_order;
		return $this->to_selected_bool( $admin_mail_early_on_new_order );
	}

	/**
	 * Get p24_admin_mail_early_on_new_order from config
	 *
	 * @return bool|string
	 */
	public function get_client_mail_on_hold_at_pending() {
		$client_mail_on_hold_at_pending = $this->config->p24_client_mail_on_hold_at_pending;
		return $this->to_selected_bool( $client_mail_on_hold_at_pending );
	}
}
