<?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
 *	@version		see info.php of this module
 *	@authors		LEPTON Project, W. Studer
 *	@copyright		2020-2021 LEPTON Project
 *	@link			https://lepton-cms.org
 *	@license		http://www.gnu.org/licenses/gpl.html
 *	@license_terms	please see info.php of this module
 *	@platform		see info.php of this module
 *
 *
 */


class captcha extends LEPTON_abstract
{

	public $database = 0;

	// plugin setting
	public $settings = array();

	// plugin instance
	public $oPLUGIN = NULL;
	public $pluginName = NULL;

	// Own instance for this class!
	static $instance;

	public function __construct()
	{
	}

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

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

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


		// create PLUGIN instance
		$this->create_plugin_instance( $this->settings[ "captcha_type" ] );
		if ( false === is_null( $this->oPLUGIN ))
		{
			$this->pluginName = $this->settings[ "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->pluginName == $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->settings );
			}
		}
	}

	/** =========================================================================
	 *
	 * validate a json string
	 *
	 * @param	$string		json string
	 * @return	mixed		array when json strin is valid
	 *						error string when json is invalid
	 * @access	private
	 *
	 */
	private function json_validate( $string )
	{
		// 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;
			// PHP >= 5.3.3
			case JSON_ERROR_UTF8:
				$error = 'Malformed UTF-8 characters, possibly incorrectly encoded.';
				break;
			// PHP >= 5.5.0
			case JSON_ERROR_RECURSION:
				$error = 'One or more recursive references in the value to be encoded.';
				break;
			// PHP >= 5.5.0
			case JSON_ERROR_INF_OR_NAN:
				$error = 'One or more NAN or INF values in the value to be encoded.';
				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 );
		}

		// everything is OK
		return $result;
	}

	/* ===============================================================================
	 * build a captcha as defined in captcha_control
	 *
	 * access:	public
	 * param:	array with elements
	 * output:	captcha
	 */
	public function build_captcha( $params = array() )
	{
		// 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( $params )
	{
		// clculate 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 )
	{
		// validate a captcha entry
		if ( false === is_null( $this->oPLUGIN ))
		{
			return $this->oPLUGIN->test_captcha( $value, $section_id );
		}

		return true;
	}
}
