<?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-2022 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_control extends LEPTON_abstract
{
	public $database;
	public $oCAPTCHA;
	public $oPLUGIN;
	public $pluginSettings = array();
	public $pluginName = NULL;

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

	public function __construct()
	{
	}

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

		// get instance of captcha & plugin
		require_once(LEPTON_PATH . "/modules/captcha_control/classes/captcha.php" );
		$this->oCAPTCHA			= captcha::getInstance();


		$this->pluginName		= $this->oCAPTCHA->pluginName;
		$this->set_plugin( array( "captcha_type" => $this->pluginName ));
	}

	/* ===============================================================================
	 * build list of useable plugins/captchas
	 *
	 * access:	public
	 * param:	data array of last saved settings
	 * output:	array
	 */
	private function set_plugin( $data )
	{
		// get last saved plugin
		$plugin = $data[ "captcha_type" ];

		if ( false === empty( $plugin ))
		{
			// update instance of plugin
			$this->oCAPTCHA->create_plugin_instance( $plugin );
			$this->oPLUGIN			= $this->oCAPTCHA->oPLUGIN;

			// get plugin specific fieldset for capcha_control
			if ( false === is_null( $this->oPLUGIN ))
			{
				$this->pluginSettings	= $this->oPLUGIN->settings;
			}
		}
	}

	/* ===============================================================================
	 * build list of useable plugins/captchas
	 *
	 * access:	public
	 * param:	data array of last saved settings
	 * output:	array
	 */
	public function get_useable_plugins( $data )
	{
		// get all plugins
		$plugins = $this->get_all_plugins();

		// loop available plugins
		$captchas = array();
		foreach ( $plugins as $plugin )
		{
			// update instance of plugin
			$this->oCAPTCHA->pluginName = "";
			$this->set_plugin( array( "captcha_type" => $plugin ) );

			if ( false === is_null( $this->oPLUGIN ))
			{
				if ( true === $this->oPLUGIN->is_useable )
				{
					$captchas[ $plugin ] = array(
						"TEXT"			=> $this->oPLUGIN->language[ strtoupper( $plugin ) ],
						"DEPRECATED"	=> $this->oPLUGIN->is_deprecated,
						"PLAYGROUND"	=> $this->oPLUGIN->show_playground
					);
				}
			}
		}

		// reset to last saved plugin
		$this->set_plugin( array( "captcha_type" => $this->pluginName ));
		$this->oCAPTCHA->pluginName = $this->pluginName;

		return $captchas;
	}

	/* ===============================================================================
	 * build list of plugins
	 *
	 * access:	private
	 * param:	none
	 * output:	array with plugins
	 */
	private function get_all_plugins()
	{
		// traverse the plugins directory
		$path = LEPTON_PATH . "/modules/captcha_control/plugins/";
		$plugins = glob( $path . '*' , GLOB_ONLYDIR);
		foreach ( $plugins as &$plugin )
		{
			$plugin = str_replace( $path, "", $plugin );
		}

		return $plugins;
	}

	/* ===============================================================================
	 * maintain captcha in backend admin module captcha_control
	 *
	 * access:	public
	 * param:	data array of last saved settings
	 * output:	array of captcha specific fields for maintenance
	 */
	public function captcha_control( $data)
	{
		// get last saved plugin
		$plugin = $data[ "captcha_type" ];

		$fieldlist = array();
		if ( false === empty( $plugin ))
		{
			// update instance of plugin
			$this->set_plugin( $data );

			// get plugin specific fieldset for capcha_control
			if ( false === is_null( $this->oPLUGIN ))
			{
				$fieldlist = $this->oPLUGIN->get_control_fieldset();
			}
		}

		// check for backend gui template
		if ( defined( "LEPTON_PATH" ))
		{
			$aLookUpPath = array(
				THEME_PATH . "/backend/captcha_control/plugins/",
				LEPTON_PATH . "/modules/captcha_control/plugins/" . $plugin . "/templates/",
				LEPTON_PATH . "/modules/captcha_control/templates/"
			);

			foreach( $aLookUpPath as $sTempPath )
			{
				// Get canonicalized absolute pathname
				$path = realpath($sTempPath);

				// If it exist, check if it's a directory
				if ( true === is_dir( $sTempPath )) 
				{
					if ( true === file_exists( $sTempPath . "/" . $plugin . ".lte" ) )
					{
						$fieldlist[ "TEMPLATEPATH"] = $sTempPath; 
						break; 	// stop on first file found
					}
				}
			}
		}

		return $fieldlist;
	}

	/* ===============================================================================
	 * save plugin specific data set in captcha_control
	 *
	 * access:	public
	 * param:	data array of last saved settings
	 * output:	true
	 */
	public function captcha_control_save( $data )
	{
		// get last saved plugin
		$plugin = $data[ "captcha_type" ];

		if ( true === empty( $plugin ))
			{ return false; }

		// update instance of plugin
		$this->set_plugin( $data );

		// check if a generic configuration exists
		if ( false === array_key_exists( "GENERIC", $this->pluginSettings[ "all_plugin_config" ] ))
			{ $this->pluginSettings[ "all_plugin_config" ][ "GENERIC" ] = array(); }

		// get input validation class
		$oREQUEST = LEPTON_request::getInstance();

		// set generic specific configuration (and defaults if missing)
		$generic_fields = array(
			'reload_type'			=> array( "type" => "string_clean", "default" => "IFRAME" ),
			'captcha_speech'		=> array( "type" => "integer+", "default" => 1, "range" => array( "min" => 0, "max" => 1 ) ),
			'captcha_speech_rate'	=> array( "type" => "float", "default" => 0.9, "range" => array( "min" => 0.1, "max" => 10 ) ),
			'captcha_speech_pitch'	=> array( "type" => "float", "default" => 0.7, "range" => array( "min" => 0.1, "max" => 2 ) )
		);
		// do input validation
		$validate_fields = array();
		foreach( $generic_fields as $key => $value )
		{
			$validate_fields[ $key ] = $value;
		}
		$valid_fields = $oREQUEST->testPostValues( $validate_fields );
		// set to save array
		foreach( $valid_fields as $key => $value )
		{
			$this->pluginSettings[ "all_plugin_config" ][ "GENERIC" ][ $key ] = $value;
		}

		// get list of plugin specific fields for save
		$validate_fields = $this->oPLUGIN->get_db_fields();
		if(!empty( $validate_fields ))
		{
			// do validation
			$valid_fields = $oREQUEST->testPostValues( $validate_fields );

			// check if a configuration for this plugin exists
			if ( false === array_key_exists( $plugin, $this->pluginSettings[ "all_plugin_config" ] ))
				{ $this->pluginSettings[ "all_plugin_config" ][ $plugin ] = array(); }

			// set plugin specific configuration
			foreach( $valid_fields as $key => $value )
			{
				$this->pluginSettings[ "all_plugin_config" ][ $plugin ][ $key ] = $value;
			}

			// do plugin specific actions before save
			$this->pluginSettings[ "all_plugin_config" ][ $plugin ] = $this->oPLUGIN->settings_save( $this->pluginSettings[ "all_plugin_config" ][ $plugin ] );
		}

		// prepare for save
		$all_plugin_config = json_encode( $this->pluginSettings[ "all_plugin_config" ] );

		// update database
		$this->database->build_and_execute(
			"UPDATE",
			TABLE_PREFIX . "mod_captcha_control",
			array( "ct_text" => $all_plugin_config ),
			""
		);

		// update plugin class settings
		$this->oPLUGIN->set_settings( $this->pluginSettings );
		$this->pluginSettings	= $this->oPLUGIN->settings;

		return true;
	}

	/* ===============================================================================
	 * get generic configuration settings valid for all captchas
	 *
	 * access:	public
	 * param:	data array of last plugin settings
	 * output:	array with generic
	 */
	public function get_generic_config( $data )
	{
		// get last saved plugin
		$plugin = $data[ "captcha_type" ];

		if ( true === empty( $plugin ))
			{ return array(); }

		// update instance of plugin
		$this->set_plugin( $data );

		// return defaults
		return $this->pluginSettings[ "GENERIC" ];
	}

	/* ===============================================================================
	 * get plugin defaults for captcha generation
	 *
	 * access:	public
	 * param:	data array of last plugin settings
	 * output:	array with defaults
	 */
	public function get_plugin_defaults( $data )
	{
		// get last saved plugin
		$plugin = $data[ "captcha_type" ];

		if ( true === empty( $plugin ))
			{ return false; }

		// update instance of plugin
		$this->set_plugin( $data );

		// get defaults
		$defaults = $this->oPLUGIN->defaults;

		// convert sub array to strings
		foreach( $defaults as $key => &$value )
		{
			switch( $key )
			{
				case "TEXT_ATTR":
				case "IMAGE_ATTR":
				case "INPUT_ATTR":
					$value = $this->oPLUGIN->concat_attributes( $defaults, $key );
					break;
			}
		}

		// return defaults
		return $defaults;
	}

	/* ===============================================================================
	 * build all available captchas of a plugin
	 *
	 * access:	public
	 * param:	array with elements
	 * output:	array with captcha
	 */
	public function build_captcha( $params = array() )
	{
		// get plugin supported actions
		$actions = $this->oPLUGIN->supported_actions;

		// set default action if missing or invalid
		if (( true === array_key_exists( "action", $params ))
		 && ( false === empty( $params[ "action" ])))
		{
			$action = $params[ "action" ];
			if ( false === in_array( $action, $actions ) )
				{ $action =  $this->oPLUGIN->default_action; }
		}
		else
			{ $action = $this->oPLUGIN->default_action; }

		// prepare creation
		unset( $params[ "action" ] );
		$params[ "ACTION" ]		= $action;

		// create captcha
		$captcha = $this->oCAPTCHA->build_captcha( $params );

		// validation allowed
		$do_validate = false;
		switch( $action )
		{
			case "all":
			case "all_js":
				$do_validate = true;
				break;
			case "data":
				$captcha = print_r( $captcha, true );
				break;
			default:
				if ( $this->oPLUGIN->plugin_name == "google_recaptcha" )
					{ $do_validate = true; }
				break;
		}

		// return data set for test.lte
		$captcha = array(
			"CAPTCHA"		=> $captcha,
			"CAPTCHA_PRE"	=> $this->create_pre_source( $captcha ),
			"ACTION"		=> $action,
			"LABEL"			=> $this->language[ "CCL_ITEM_" . strtoupper( $action ) ],
			"PARAMS"		=> $this->get_action_params( $action ),
			"DO_VALIDATE"	=> $do_validate,
			"ACTIONS"		=> $actions
		);

		return $captcha;
	}

	/* ===============================================================================
	 * create captcha prepared string to be shown in backend pre section
	 *
	 * access:	private
	 * param:	captcha string or array
	 * output:	converted string
	 */
	private function create_pre_source( $captcha = "" )
	{
		// array handling
		if ( true === is_array( $captcha ))
			{ return print_r( $captcha, true ); }

		// string handling
		return str_replace( "<", "&lt;", $captcha );
	}

	/* ===============================================================================
	 * create action parameter string to be shown in backend
	 *
	 * access:	private
	 * param:	action
	 * output:	prepared string
	 */
	private function get_action_params( $action )
	{
		// get params
		$action_params = $this->oPLUGIN->action_params;

		// array handling
		if ( true === is_array( $action_params ))
		{
			// Add action & section_id
			$action_params[ "ACTION" ]		= $action;
			$action_params[ "SECTION_ID" ]	= "&dollar;section_id";
			
			return print_r( $action_params, true );
		}

		// no data available
		return "";
	}

	/* ===============================================================================
	 * test/validate a captcha
	 *
	 * access:	public
	 * param:	captcha value
	 * output:	captcha
	 */
	public function test_captcha( $value, $section_id )
	{
		// validate a captcha entry
		if ( false === is_null( $this->oCAPTCHA ))
		{
			return $this->oCAPTCHA->test_captcha( $value, $section_id );
		}

		return true;
	}

}

?>
