<?php
/**
 * @author       Aicha Vack
 * @package      Joomla.Administrator
 * @subpackage   com_visforms
 * @link         https://www.vi-solutions.de
 * @license      GNU General Public License version 2 or later; see license.txt
 * @copyright    2021 vi-solutions
 * @since        Joomla 1.6
 */

// No direct access
defined('_JEXEC') or die;

use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\Version;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Language\LanguageHelper;
use Joomla\CMS\Filesystem\File;
use Joomla\CMS\Filesystem\Folder;
use Joomla\CMS\Filesystem\Path;
use Joomla\CMS\Log\Log;
use Joomla\CMS\Date\Date;
use Joomla\Component\Menus\Administrator\Helper\MenusHelper;
use Visolutions\Component\Visforms\Administrator\Model\VisformModel;

// example code: the helper visforms.php provides useful functions that Visforms is using itself
// require_once JPATH_ADMINISTRATOR . '/components/com_visforms/helpers/visforms.php';

//
// coding template covering all 30 existing visforms event handler
//

class plgVisformsVfcustomplugin extends CMSPlugin {
	// example code: a class member variable that is used later on
	// public $input = '';
	private string $loggerName;

	public function __construct(&$subject, $config) {
		parent::__construct($subject, $config);
		$this->initializeLogger($config);
		// example code: set Joomla input object to class variable
		// $this->input = Factory::getApplication()->input;
		// example code: get parameter id from the Joomla input object from class variable
		// $id = $this->input->getInt('id', 0);
	}

	// common for both: form submit and data edit

	public function onVisformsEmailPrepare($context, $mail, $form): bool {
		// context = 'com_visforms.form.resultmail'
		// context = 'com_visforms.form.receiptmail'
		// triggered in VisformsModel after the mail object is instantiated and directly before the mail is sent:
		// can be used to modify the mail object: mail object is instantiated and all properties are set and can be modified

		// example code: simply change email text
		// $mail->Body = '<p>My new result mail body.</p>';

		// example code:  add user selected mail recipients to result mail
		// selected by multi-selection form field 'email-select'

		return true;
	}

    public function onVisformsBeforeEmailPrepare($context, $form): bool {
	    // context = 'com_visforms.form.resultmail'
	    // context = 'com_visforms.form.receiptmail'
	    // triggered in VisformsModel before the mail object is instantiated:
	    // can be used to modify the form object (i.e. to stop sending the mail or change addresses)

		return true;
    }

	// form submit specific

	public function onVisformsBeforeFormSave($context, $form, $fields): bool {
        // context = 'com_visforms.form'

		// example code: exit, if we are in administration
		/*$app = Factory::getApplication();
		if ($app->isClient('administrator')) {
			return true;
		}*/

		return true;
	}

	public function onVisformsAfterFormSave($context, $form, $fields): bool {
        // context = 'com_visforms.form'
        return true;
    }

	public function onVisformsAfterFormSaveError($context, $form, $fields): bool {
	    // context = 'com_visforms.form'
		return true;
	}

	public function onVisformsBeforeSuccessAction($context, $form, $fields): bool {
	    // override properties in $visforms (i.e. redirect url, successmessage)
        // context = 'com_visforms.form'
		// triggered in VisformsController before form result text is parameter processed and before running of all content plugins

		// example code: simply change the result text before all parameters are processed
		// $form->textresult = "<div class=\"my-text-result-class\">Mein neuer Ergebnis-Text.</div>";
		return true;
	}

	public function onVisformsMessageText($context, $form, $fields, &$msg): bool {
		// context = 'com_visforms.form'
		// triggered in VisformsController after form result text is parameter processed and before running of all content plugins

		// example code: simply change the result text after all parameters are processed
		// $msg = preg_replace('#search-me#', '${0} and replace-me', $msg);
		return true;
	}

	// data edit specific

	public function onVisformsAfterEditFormSaveError($context, $form, $fields): bool {
	    // clean up, saving form results in an error (i.e. delete uploaded files)
		// context = 'com_visforms.form'
		return true;
	}

	public function onVisformsEditFormPrepare($context, $form, $menu_params): bool {
		// context = 'com_visforms.form'
		return true;
	}

	public function onVisformsBeforeEditSave($context, $form, $fields): bool {
		// context = 'com_visforms.form'
		return true;
	}

	// JForm events: Visforms
    // Triggered in Administration only, Overrides for the Joomla default events

	public function onVisformsPrepareJForm($form): bool {
		return true;
	}

	public function onVisformsBeforeJFormSave($context, &$table, $isNew, $data = array()): bool {
		return true;
	}

	public function onVisformsAfterJFormSave($context, &$table, $isNew, $data = array()): bool {
		// context = 'com_visforms.visfield'
		// context = 'com_visforms.visform'

		// example code: reaction only to selected contexts
		/*if (($context === 'com_visforms.visfield') || ($context === 'com_visforms.visform')) {
			return true;
		}*/

		return true;
	}

	public function onVisformsBeforeJFormDelete($context, $table): bool {
		// context = 'com_visforms.visfield'
		// context = 'com_visforms.visform'

		// example code: reaction only when deleting a field
		/*if ($context == 'com_visforms.visfield') {
			return true;
		}*/

		// example code: skip plugin if we are deleting something other than a visforms form or field
		/*if (($context != 'com_visforms.visfield') && ($context != 'com_visforms.visform')) {
			return true;
		}*/

		// example code: we ware deleting a form
		// delete fields in visfields table
		// delete datatable if table exists
		// delete pdfs in vispdf table
		/*if ($context == 'com_visforms.visform') {
			return true;
		}*/

		return true;
	}

	public function onVisformsAfterJFormDelete($context, $table): bool {
		// context = 'com_visforms.visfield'
		// context = 'com_visforms.visform'

		// example code: reaction only to selected contexts
		/*if (($context === 'com_visforms.visform') || ($context === 'com_visforms.visfield')) {
			return true;
		}*/

		return true;
	}

	public function onVisformsJFormChangeState($context, $pks, $value): bool {
		// context = 'com_visforms.visfield'
		// context = 'com_visforms.visform'

		// example code: reaction only to selected context
		/*if ($context === 'com_visforms.visform') {
			return true;
		}*/

		// example code: reaction only to selected context
		/*if ($context === 'com_visforms.visfield') {
			return true;
		}*/

		return true;
	}

	public function onVisformsSaveJFormExtraData($data, $fid, $isNew): bool {
		return true;
	}

    public function onVisformsAfterBatchCopyForm($pk, $newId): bool {
        return true;
    }

    // JForm events: Visforms data

	public function onVisformsdataAfterJFormSave($context, $table, $isNew, $data = array()): bool {
		// context = 'com_visforms.visdata'
		// event is triggered from administration and from site

		// example code: we only want to react if the event comes from administration, because the site is handled by onVisformsAfterEditFormSave
		/*$app = Factory::getApplication();
		if ($app->isClient('site')) {
			return true;
		}*/

		// example code: reaction only to selected context
		/*if ($context === 'com_visforms.visdata') {
			return true;
		}*/

		return true;
	}

	public function onVisformsdataAfterJFormDelete($context, $table): bool {
		// context = 'com_visforms.visdata'
		return true;
	}

	public function onVisformsdataJFormChangeState($context, $pks, $value): bool {
		// context = 'com_visforms.visdata'

		// example code: reaction only to selected context
		/*if ($context === 'com_visforms.visdata') {
			return true;
		}*/

		return true;
	}

	// mixed singles

	public function onVisformsFormPrepare($context, $visforms, $menu_params): bool {
		// context = 'com_visforms.form'
		// context = 'mod_visforms.form'
		// context = 'plg_vfformview.form'
		// triggered almost immediately before the layout file (component/module/plugin) is loaded
		return true;
	}

	// example code: add a custom submit handler
	// the handler onVisformsFormPrepare() is commented out (will not get called) by using function name prefix '__': __onVisformsFormPrepare
	// attention: only one function with the same name is allowed in this PHP class 'plgVisformsVfcustomplugin'
	public function __onVisformsFormPrepare($context, $form, $menu_params)	{
		// Skip plugin if context is wrong
		$allowedContexts = array('com_visforms.form', 'mod_visforms.form', 'plg_vfformview.form');
		if (!in_array($context, $allowedContexts)) {
			return true;
		}
		$app = JFactory::getApplication();
		// only perform action, if we are in front end
		if ($app->isAdmin()) {
			return true;
		}
		//if $form->parentFormId is not set, Visforms or Content Plugin Form View version is to old
		if (!isset($form->parentFormId)) {
			return true;
		}
		// get value of id attribute of the form which is going to be displayed
		$parentFormId = $form->parentFormId;
		// add custom submit handler function to the form
		$script = 'jQuery(document).ready(function () {
            //add custom submit action function to form
            window["' . $parentFormId . 'SubmitAction"] = function (form) {
            // your code in here
            //return false to prevent form from being submitted, return true, if submit-handler performs another action but form should be send
                return true;
            };
        });';
		JFactory::getDocument()->addScriptDeclaration($script);
	}

	public function onVisformsAfterCustomtextPrepare($context, &$html, $layout): bool {
		// context = 'com_visforms.field'
		// can be used to modify the visfield custom text property late, after all visforms sepecific processing is complete
		return true;
	}

	public function onVisformsPrepareDoiMailText($context, &$text, $visform): bool {
		// context = 'com_visforms.form.receiptmail'
		// used to replace custom placeholder for Double-Opt-In Link
		return true;
	}

	public function onVisformsSpambotCheck($context): bool {
		// context = 'com_visforms.visformedit'
        // context = 'com_visforms.visform'

		// return false = continue visforms action
		// return true  = aboard visforms action
		return false;
	}

	// mixed pairs: before, after

	public function onVisformsBeforeHtmlPrepare($context, &$field, $layout): bool {
		// context = 'com_visforms.field'
		// allow changes on field properties before control html is created
		return true;
	}

	public function onVisformsAfterHtmlPrepare($context, &$field, &$html, $layout): bool {
		// context = 'com_visforms.field'
		// allow changes on field properties after control html is created
		return true;
	}

	public function onVisformsBeforeConfirmDoi($context, $fid, $recordId): bool {
		// context = 'com_visforms'
		// use in double-opt-in confirmation process
		// implement an individual action before the confirmation is validated and database changes are made
		return true;
	}

	public function onVisformsAfterConfirmDoi($context, $fid, $recordId): bool {
		// context = 'com_visforms'
		// used to implement an individual action performed after successful double-opt-in
		return true;
	}

	// special (standard Joomla event used in a Visforms plugin) should not be in mentioned in this plugin

	public function onPreprocessMenuItems($context, $children, $param, $enabled): bool {
		return true;
	}

	// not an event
	protected function removeUploadedFiles($context, $form, $fields): bool {
		if ($context != 'com_visforms.form') {
			return true;
		}
		$app = Factory::getApplication();
		if ($app->isClient('administrator')) {
			return true;
		}
		return true;
	}

	// implementation: helper functions

	private function getField(&$form, $name): null | object {
		if (is_array($form->fields)) {
			foreach ($form->fields as $field) {
				$fieldName = (!empty($form->context)) ? str_replace($form->context, '', $field->name) : $field->name;
				if ($name === $fieldName) {
					return $field;
				}
			}
		}
		return null;
	}

	private function getFieldValue(&$form, $name): string {
		$field = $this->getField($form, $name);
		if (isset($field)) {
			return is_null($field->dbValue) ? '' : $field->dbValue;
		}
		return '';
	}

	private function getFieldByID(&$form, string $ID): null | object {
		if (is_array($form->fields)) {
			foreach ($form->fields as $field) {
				$fieldID = (!empty($form->context)) ? str_replace($form->context, '', $field->id) : $field->id;
				if ($ID === $fieldID) {
					return $field;
				}
			}
		}
		return null;
	}

	private function getFieldValueByID(&$form, string $ID): string {
		$field = $this->getFieldByID($form, $ID);
		if (isset($field)) {
			return is_null($field->dbValue) ? '' : $field->dbValue;
		}
		return '';
	}

	// logging

	private function initializeLogger($config) {
		$this->loggerName               = $config['type'] . '-' . $config['name'];
		$options['format']              = "{CODE}\t{MESSAGE}";
		$options['text_entry_format']   = "{PRIORITY}\t{MESSAGE}";
		$options['text_file']           = $config['type'] . '_' . $config['name'] . '.php';
		try {
			Log::addLogger($options, Log::ALL, array($this->loggerName, 'jerror'));
		}
		catch (RuntimeException $e) {}
	}

	private function addLogEntry($message, $code = Log::ERROR) {
		try {
			Log::add($message, $code, $this->loggerName);
		}
		catch (RuntimeException $exception) {
			// prevent routine from failing due to problems with logger
		}
	}
}