<?php

/**
 * This file is part of an ADDON for use with LEPTON Core.
 * This ADDON is released under the GNU GPL.
 * Additional license terms can be seen in the info.php of this module.
 *
 *
 *	@module			captcha_control
 *	@version		see info.php of this module
 *	@authors		LEPTON Project, W. Studer
 *	@copyright		2010-2026 LEPTON Project
 *	@link			https://lepton-cms.org
 *	@license		https://gnu.org/licenses/gpl.html
 *	@license_terms	please see info.php of this module
 *	@platform		see info.php of this module
 *
 *
 */


class captcha_control extends LEPTON_abstract
{
	public array $aSettings = [];
	public string $sPluginName = '';
	
	// plugin instance
	public LEPTON_database $database;
	public object|null $oPLUGIN = null;

	public static $instance;

	public function __construct()
	{
	}

	public function initialize()
	{
		// set database
		$this->database = LEPTON_database::getInstance();

		// get settings
		$this->database->execute_query(
			"SELECT * FROM ".TABLE_PREFIX."mod_captcha_control", 
			true, 
			$this->aSettings, 
			false 
		);

		// get plugin configuration json string and convert into array if valid
		$json_data = $this->json_validate( $this->aSettings[ "ct_text" ] );
		if ( true === is_array( $json_data ))
		{ 
			$this->aSettings[ "all_plugin_config" ] = $json_data; 
		}
		else
		{ 
			$this->aSettings[ "all_plugin_config" ] = []; 
		}

		// create PLUGIN instance
		$this->create_plugin_instance( $this->aSettings[ "captcha_type" ] );
		if ( false === is_null( $this->oPLUGIN ))
		{
			$this->sPluginName = $this->aSettings[ "captcha_type" ];
		}

	}


	/* ===============================================================================
	 * create a plugin instance
	 *
	 * access:	public
	 * param:	array with elements
	 * output:	captcha
	 */
	public function create_plugin_instance( $plugin )
	{
		// no instance change needed
		if ( $this->sPluginName == $plugin )
		{ 
			return; 
		}

		$this->oPLUGIN = null;

		// create new instance of plugin
		$path = LEPTON_PATH . "/modules/captcha_control/plugins/" . $plugin . "/classes/" . $plugin . ".php";
        if (file_exists($path))
		{
			require_once $path;

			if ( class_exists( $plugin, false ))	// no autoload
			{
				// create captcha plugin instance
				$this->oPLUGIN = $plugin::getInstance();

				// merge with languages set in captcha modul: translations used in several plugins
				$this->oPLUGIN->merge_languages( $this->language );

				// set settings
				$this->oPLUGIN->set_settings( $this->aSettings );
			}
		}
	}

	/** =========================================================================
	 *
	 * validate a json string
	 *
	 * @param	string $string		json string
	 * @return	mixed		array when json string is valid
	 *						error string when json is invalid
	 * @access	private
	 *
	 */
	private function json_validate(string $string ): mixed
	{
		// decode the JSON data into assoc array
		$result = json_decode( $string, true );

		// switch and check possible JSON errors
		switch (json_last_error())
		{
			case JSON_ERROR_NONE:
				$error = ''; // JSON is valid // No error has occurred
				break;
			case JSON_ERROR_DEPTH:
				$error = 'The maximum stack depth has been exceeded.';
				break;
			case JSON_ERROR_STATE_MISMATCH:
				$error = 'Invalid or malformed JSON.';
				break;
			case JSON_ERROR_CTRL_CHAR:
				$error = 'Control character error, possibly incorrectly encoded.';
				break;
			case JSON_ERROR_SYNTAX:
				$error = 'Syntax error, malformed JSON.';
				break;
			case JSON_ERROR_UNSUPPORTED_TYPE:
				$error = 'A value of a type that cannot be encoded was given.';
				break;
			default:
				$error = 'Unknown JSON error occured.';
				break;
		}

        if ($error !== '')
		{
			// throw the Exception or exit // or whatever :)
			return $error;
		}
		
		return $result;
	}

	/* ===============================================================================
	 * build a captcha as defined in captcha_control
	 *
	 * access:	public
	 * param:	array with elements
	 * output:	captcha
	 */
	public function build_captcha(array $params = []): string
	{
		// create a captcha
        if ((true === is_null($this->oPLUGIN)) || (false === $this->oPLUGIN->is_useable))
		{
			// use default calc_text plugin instead
            unset($this->oPLUGIN);
            $this->oPLUGIN = $this->load_plugin_class("calc_text");
		}

        if ((false === is_null($this->oPLUGIN)) && (true === $this->oPLUGIN->is_useable))
		{
            return $this->oPLUGIN->build_captcha($params);
		}

		return "";
	}

	/* ===============================================================================
	 * calculate the captcha string
	 *
	 * scope:	frontend
	 * access:	public
	 * param:	array with attributes
	 * output:	the captcha
	 */
	public function calculate_captcha(array $params )
	{
		// calculate a captcha
        if ((true === is_null($this->oPLUGIN)) || (false === $this->oPLUGIN->is_useable))
		{
			// use default calc_text plugin instead
            unset($this->oPLUGIN);
            $this->oPLUGIN = $this->load_plugin_class("calc_text");
		}

        if ((false === is_null($this->oPLUGIN)) && (true === $this->oPLUGIN->is_useable))
		{
            return $this->oPLUGIN->calculate_captcha($params);
		}

		return "";
	}

	/* ===============================================================================
	 * test/validate a captcha
	 *
	 * scope:	frontend
	 * access:	public
	 * param:	captcha value
	 * output:	captcha
	 */
	public function test_captcha( $value, $section_id )
	{
		
		if ((ENABLED_ASP == 1) && (!captcha_control_services::insiteASPTimeRange(time())))
		{
				return false;
		}
		
		return $this->oPLUGIN->test_captcha( $value, $section_id );		
	}

	
	/**
	 * Prepare the captcha values
	 */

	public function call_captcha(string $action, string $style, int $section_id)
	{
		// set default params
		$params = [
			"ACTION"		=> $action,
			"SECTION_ID"	=> $section_id
		];

		// set - based on old logic - action specific styles
		switch ($action)
		{
			case "image":
				$params[ "IMAGE_ATTR" ]	= $style;
				break;
			case "image_iframe":
				if ( CAPTCHA_TYPE != "calc_text" )
				{
					$params[ "IMAGE_ATTR" ]	= $style;
				}
				break;
			case "input":
				$params[ "INPUT_ATTR" ]	= $style;
				break;
			case "text":
				$params[ "TEXT_ATTR" ]	= $style;
				break;
		}

		// build the captcha
		echo self::build_captcha( $params );
	}		
}
