<?php
/**
 * @package       RSform!Pro
 * @copyright (C) 2007-2018 www.rsjoomla.com
 * @license       GPL, http://www.gnu.org/copyleft/gpl.html
 */

defined('_JEXEC') or die;

use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Factory;
use Joomla\CMS\Table\Table;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Form\Form;
use Joomla\CMS\Uri\Uri;
use Joomla\CMS\HTML\HTMLHelper;

/**
 * Class plgSystemRSFPCampaignMonitor
 */
class plgSystemRsfpcampaignmonitor extends CMSPlugin
{

	/**
	 * @var bool
	 */
	protected $autoloadLanguage = true;

	/**
	 * @param $form
	 *
	 * @return bool|void
	 */
	public function onRsformFormSave($form)
	{
		$data = Factory::getApplication()->input->post->get('campaignmonitor', array(), 'array');
		$data['form_id'] = $form->FormId;

		$row = $this->getTable();
		if (!$row)
		{
			return false;
		}
		return $row->save($data);
	}

	protected function getTable()
	{
		return Table::getInstance('RSForm_CampaignMonitor', 'Table');
	}
	
	public function onRsformBackendFormCopy($args)
	{
		$formId = $args['formId'];
		$newFormId = $args['newFormId'];

		if ($row = $this->getTable())
		{
			if ($row->load($formId))
			{
				$vars = unserialize($row->vars);

				if (isset($vars['form_id']))
				{
					$vars['form_id'] = $newFormId;
				}

				if (!$row->bind(array('form_id'=>$newFormId, 'vars'=> serialize($vars))))
				{
					return false;
				}

				$row->check();

				return $row->store();
			}
		}
	}

	/**
	 * @param $tabs
	 */
	public function onRsformBackendAfterShowConfigurationTabs($tabs)
	{
		$tabs->addTitle(Text::_('RSFP_CAMPAIGNMONITOR_LABEL'), 'rsfp-campaignmonitor');
		$tabs->addContent($this->configurationScreen());
	}

	/**
	 * @return string
	 */
	protected function configurationScreen()
	{
		ob_start();

		Form::addFormPath(__DIR__ . '/forms');

		$form = Form::getInstance( 'plg_system_rsfpcampaignmonitor.configuration', 'configuration', array('control' => 'rsformConfig'), false, false );
		$form->bind($this->loadFormData());

		?>
		<div id="page-campaignmonitor" class="form-horizontal">
			<?php
			foreach ($form->getFieldsets() as $fieldset)
			{
				if ($fields = $form->getFieldset($fieldset->name))
				{
					foreach ($fields as $field)
					{
						echo $field->renderField();
					}
				}
			}
			?>

			<p><a href="https://help.campaignmonitor.com/api-keys" class="btn btn-primary" target="_blank"><?php echo Text::_('RSFP_CAMPAIGNMONITOR_GETKEY'); ?></a></p>
		</div>
		<?php

		$contents = ob_get_contents();
		ob_end_clean();

		return $contents;
	}

	private function loadFormData()
	{
		$data 	= array();
		$db 	= Factory::getDbo();

		$query = $db->getQuery(true)
			->select('*')
			->from($db->qn('#__rsform_config'))
			->where($db->qn('SettingName') . ' LIKE ' . $db->q('campaignmonitor.%', false));
		if ($results = $db->setQuery($query)->loadObjectList())
		{
			foreach ($results as $result)
			{
				$data[$result->SettingName] = $result->SettingValue;
			}
		}

		return $data;
	}

	/**
	 * @throws Exception
	 */
	public function onRsformBackendSwitchTasks()
	{
		$app = Factory::getApplication();

		if ($app->input->getCmd('plugin_task') == 'campaignmonitor.createdefaultlist')
		{
			require_once JPATH_ADMINISTRATOR . '/components/com_rsform/helpers/rsfpcampaignmonitor/csrest_lists.php';
			$campaignmonitor_api    = RSFormProHelper::getConfig('campaignmonitor.api');
			$campaignmonitor_client = RSFormProHelper::getConfig('campaignmonitor.client');

			$auth = array(
				'api_key' => $campaignmonitor_api,
			);

			$rsfp_list = array(
				'Title'              => 'RSForm!Pro Default List',
				'UnsubscribeSetting' => 'OnlyThisList',
			);

			$lists  = new CS_REST_Lists('', $auth);
			$create = $lists->create($campaignmonitor_client, $rsfp_list);

			if ($create->was_successful())
			{
				$url = Uri::root() . '/administrator/index.php?option=com_rsform&task=forms.edit&formId=' . $app->input->get('formId', '') . '&tabposition='. $app->input->get('tabposition', '') .'&tab='.  $app->input->get('tab', '');

				$app->redirect($url, Text::_('RSFP_DEFAULTLISTCREATED'), 'Notice');

			} else {
				throw new Exception(Text::sprintf('RSFP_CAMPAIGNMONITOR_ERROR', $create->response->Code, $create->response->Message));
			}
		}
		elseif ($app->input->getCmd('plugin_task') == 'campaignmonitor.getfields')
		{
			$formId				 = $app->input->post->getInt('formId');
			$list 				 = $app->input->post->getString('list');
			$campaignmonitor_api = RSFormProHelper::getConfig('campaignmonitor.api');
			$merge_vars 		 = $this->standardFields();
			$fields_array 		 = $this->_getFields($formId);
			$fields = array(
				HTMLHelper::_('select.option', '', Text::_('JSELECT')),
			);
			foreach ($fields_array as $field)
			{
				$fields[] = HTMLHelper::_('select.option', '{' . $field . ':value}', $field);
			}

			require_once JPATH_ADMINISTRATOR . '/components/com_rsform/helpers/rsfpcampaignmonitor/csrest_clients.php';
			require_once JPATH_ADMINISTRATOR . '/components/com_rsform/helpers/rsfpcampaignmonitor/csrest_lists.php';

			$auth = array(
				'api_key' => $campaignmonitor_api,
			);

			if ($list)
			{
				$cfields = new CS_REST_Lists($list, $auth);
				$cfields = $cfields->get_custom_fields();

				if (!$cfields->was_successful())
				{
					echo Text::sprintf('RSFP_CAMPAIGNMONITOR_ERROR', $cfields->response->Code, $cfields->response->Message);
				}

				$cfields = $cfields->response;

				if (!empty($cfields))
				{
					foreach ($cfields as $custom_field)
					{
						$merge_vars[$custom_field->FieldName] = $custom_field->FieldName;
					}
				}

				foreach ($merge_vars as $merge_var => $title)
				{
					?>
					<tr class="campaignmonitor_fields">
						<td>
							<label for="<?php echo 'campaignmonitor_vars' . $merge_var ?>"><?php echo $title; ?></label></td>
						<td>
							<?php echo HTMLHelper::_('select.genericlist', $fields, 'campaignmonitor[vars][' . $merge_var . ']', null, 'value', 'text', isset($row->vars[$merge_var]) ? $row->vars[$merge_var] : null); ?>
						</td>
					</tr>
					<?php
				}

				$app->close();
			}
		}
	}

	/**
	 *
	 */
	public function onRsformBackendAfterShowFormEditTabsTab()
	{
		echo '<li><a href="javascript: void(0);" id="rsfpcampaignmonitor"><span class="rsficon rsficon-envelope-square"></span><span class="inner-text">' . Text::_('RSFP_CAMPAIGNMONITOR_LABEL') . '</span></a></li>';
	}

	/**
	 * @throws Exception
	 */
	public function onRsformBackendAfterShowFormEditTabs()
	{
		$formId = Factory::getApplication()->input->getInt('formId', 0);
		$row    = $this->getTable();

		$campaignmonitor_api    = RSFormProHelper::getConfig('campaignmonitor.api');
		$campaignmonitor_client = RSFormProHelper::getConfig('campaignmonitor.client');

		$app = Factory::getApplication();

		if ($campaignmonitor_api == '' || $campaignmonitor_client == '')
		{
			?>
			<div id="rsfpcampaignmonitordiv">
				<div class="alert alert-warning"><?php echo Text::_('RSFP_CAMPAIGNMONITOR_NOTOKEN') ?></div>
			</div>
			<?php
			return;
		}

		if (!$row)
		{
			return;
		}

		$row->load($formId);

		if ($row->vars)
		{
			$row->vars = unserialize($row->vars);
		}

		$fields_array = $this->_getFields($formId);
		$fields = array(
			HTMLHelper::_('select.option', '', Text::_('JSELECT')),
		);
		foreach ($fields_array as $field)
		{
			$fields[] = HTMLHelper::_('select.option', '{' . $field . ':value}', $field);
		}

		$lists = array();

		$lists['published'] = RSFormProHelper::renderHTML('select.booleanlist', 'campaignmonitor[enable_campaignmonitor]', '', $row->enable_campaignmonitor);
		$lists['update'] = RSFormProHelper::renderHTML('select.booleanlist', 'campaignmonitor[campaignmonitor_update]', '', $row->campaignmonitor_update);
		$lists['track_consent'] = RSFormProHelper::renderHTML('select.booleanlist', 'campaignmonitor[track_consent]', '', $row->campaignmonitor_track_consent);

		// Action
		$lists['cm_action'] = HTMLHelper::_('select.genericlist', array(
			HTMLHelper::_('select.option', 1, Text::_('RSFP_CAMPAIGNMONITOR_ACTION_SUBSCRIBE')),
			HTMLHelper::_('select.option', 2, Text::_('RSFP_CAMPAIGNMONITOR_LET_USER_DECIDE'))
		), 'campaignmonitor[cm_action]', 'onchange="changeCmAction(this.value);"', 'value', 'text', $row->cm_action);

		// Action Field
		$lists['cm_action_field'] = HTMLHelper::_('select.genericlist', $fields, 'campaignmonitor[cm_action_field]', $row->cm_action != 2 ? 'disabled="disabled"' : '', 'value', 'text', $row->cm_action_field);

		// Merge Vars
		$merge_vars = $this->standardFields();

		try
		{
			require_once JPATH_ADMINISTRATOR . '/components/com_rsform/helpers/rsfpcampaignmonitor/csrest_clients.php';
			require_once JPATH_ADMINISTRATOR . '/components/com_rsform/helpers/rsfpcampaignmonitor/csrest_lists.php';

			$auth 		= array('api_key' => $campaignmonitor_api);
			$cmlists 	= array();
			$client 	= new CS_REST_Clients($campaignmonitor_client, $auth);
			$response 	= $client->get_lists();

			if (!$response->was_successful())
			{
				$app->enqueueMessage(Text::sprintf('RSFP_CAMPAIGNMONITOR_ERROR', $response->response->Code, $response->response->Message), 'warning');
			}
			else
			{
				if ($response->response)
				{
					// Set a default list
					if (empty($row->campaignmonitor_list))
					{
						$list = reset($response->response);
						$row->campaignmonitor_list = $list->ListID;
					}

					foreach ($response->response as $list)
					{
						$cmlists[] = HTMLHelper::_('select.option', $list->ListID, $list->Name);
					}
				}
			}

			if (!empty($row->campaignmonitor_list))
			{
				$cfields = new CS_REST_Lists($row->campaignmonitor_list, $auth);
				$cfields = $cfields->get_custom_fields();

				if (!$cfields->was_successful())
				{
					throw new Exception(Text::sprintf('RSFP_CAMPAIGNMONITOR_ERROR', $cfields->response->Code, $cfields->response->Message));
				}

				$cfields = $cfields->response;

				if (!empty($cfields))
				{
					foreach ($cfields as $custom_field)
					{
						$merge_vars[$custom_field->FieldName] = $custom_field->FieldName;
					}
				}
			}
		}
		catch (Exception $e)
		{
			$app->enqueueMessage($e->getMessage(), 'warning');
		}

		Factory::getDocument()->addScriptDeclaration("
function changeCmAction(value) {
	jQuery('#campaignmonitorcm_action_field').prop('disabled', value !== '2');
}

function cmChangeList(value) {
	jQuery.ajax({
		url: 'index.php?option=com_rsform&task=plugin&plugin_task=campaignmonitor.getfields',
		method: 'POST',
		data: {'list': value, 'formId': document.getElementById('formId').value},
		dataType: 'html'
	}).done(function (response) {
		var table = jQuery('.campaignmonitor_fields').parents('table');
		jQuery('.campaignmonitor_fields').remove();
		table.append(response);			
	});
}");
		?>
		<div id="rsfpcampaignmonitordiv">
			<table class="table table-bordered">
				<tr>
					<td>
						<label for="enable_campaignmonitor"><?php echo Text::_('RSFP_CAMPAIGNMONITOR_ENABLE'); ?></label>
					</td>
					<td><?php echo $lists['published']; ?></td>
				</tr>
				<tr>
					<td>
						<span class="hasTooltip" title="<?php echo Text::_('RSFP_CAMPAIGNMONITOR_ACTION_DESC'); ?>"><?php echo Text::_('RSFP_CAMPAIGNMONITOR_ACTION'); ?></span>
					</td>
					<td><?php echo $lists['cm_action']; ?><?php echo $lists['cm_action_field']; ?>
						<p><?php echo Text::_('RSFP_CAMPAIGNMONITOR_ACTION_WARNING'); ?></p></td>
				</tr>
				<tr>
					<td>
						<label for="campaignmonitor_update"><?php echo Text::_('RSFP_CAMPAIGNMONITOR_UPDATE_IF_EXISTS'); ?></label>
					</td>
					<td><?php echo $lists['update']; ?></td>
				</tr>
				<tr>
					<td>
						<label for="campaignmonitor_track_consent"><?php echo Text::_('RSFP_CAMPAIGNMONITOR_USE_TRACKING_CONSENT'); ?></label>
					</td>
					<td><?php echo $lists['track_consent']; ?></td>
				</tr>
				<tr>
					<td>
						<label for="campaignmonitor_list"><?php echo Text::_('RSFP_CAMPAIGNMONITOR_LISTS'); ?></label>
					</td>
					<?php
					if (!empty($cmlists))
					{
						?>
						<td>
							<select name="campaignmonitor[campaignmonitor_list]" id="campaignmonitor_list" onchange="cmChangeList(this.value);">
								<?php echo HTMLHelper::_('select.options',
									$cmlists,
									'value', 'text', RSFormProHelper::htmlEscape($row->campaignmonitor_list));
								?>
							</select>
						</td>
						<?php
					}
					else
					{
						$url = Uri::current() . '?option=com_rsform&task=forms.edit&formId=' . $app->input->get('formId', '') . '&tabposition='. $app->input->get('tabposition', '') .'&tab='.  $app->input->get('tab', '') .'&plugin_task=campaignmonitor.createdefaultlist&task=plugin';
						?>
						<td>
							<a class="btn btn-primary" href="<?php echo $url ?>"><?php echo Text::_('RSFP_CAMPAIGNMONITOR_CREATEDEFAULTLIST'); ?></a>
						</td>
						<?php
						$app->enqueueMessage(Text::_('RSFP_CAMPAIGNMONITOR_NOLIST'),'warning');
					} ?>
				</tr>
				<?php
				foreach ($merge_vars as $merge_var => $title)
				{
					?>
					<tr class="campaignmonitor_fields">
						<td>
							<label for="<?php echo 'campaignmonitor_vars' . $merge_var ?>"><?php echo $title; ?></label></td>
						<td>
							<?php echo HTMLHelper::_('select.genericlist', $fields, 'campaignmonitor[vars][' . $merge_var . ']', null, 'value', 'text', isset($row->vars[$merge_var]) ? $row->vars[$merge_var] : null); ?>
						</td>
					</tr>
					<?php
				}
				?>
			</table>
		</div>
		<?php
	}

	/**
	 * @param $args
	 *
	 * @throws Exception
	 */
	public function onRsformFrontendAfterFormProcess($args)
	{

		$db                     = Factory::getDbo();
		$formId                 = (int) $args['formId'];
		$SubmissionId           = (int) $args['SubmissionId'];
		$campaignmonitor_api    = RSFormProHelper::getConfig('campaignmonitor.api');

		if (!$campaignmonitor_api)
		{
			return;
		}

		$query = $db->getQuery(true);
		$query->select('*')
			->from($db->qn('#__rsform_campaignmonitor'))
			->where($db->qn('form_id') . ' = ' . $db->q($formId))
			->where($db->qn('enable_campaignmonitor') . ' = ' . $db->q(1));

		$db->setQuery($query);
		if ($row = $db->loadObject())
		{
			try
			{
				require_once JPATH_ADMINISTRATOR . '/components/com_rsform/helpers/rsfpcampaignmonitor/csrest_subscribers.php';
				require_once JPATH_ADMINISTRATOR . '/components/com_rsform/helpers/rsfpcampaignmonitor/csrest_lists.php';

				// Get replacements
				list($args['placeholders'], $args['values']) = RSFormProHelper::getReplacements($SubmissionId);

				if ($row->cm_action == 2)
				{
					$value = str_replace($args['placeholders'], $args['values'], $row->cm_action_field);
					if ($value != 'subscribe')
					{
						return;
					}
				}

				$auth = array(
					'api_key' => $campaignmonitor_api,
				);
				$response = new CS_REST_Subscribers($row->campaignmonitor_list, $auth);

				// Grab configured fields
				$fields = array();
				if ($row->vars)
				{
					$fields = unserialize($row->vars);
				}

				if (!is_array($fields))
				{
					$fields = array();
				}

				$element = array();

				$use_tracking_consent = (bool) $row->campaignmonitor_track_consent;

				// See if multiple selection fields are being used so we can send the correct data
				$allFields = array();
				foreach ($fields as $field => $value)
				{
					if ($value)
					{
						if (preg_match('/{(.*?):.*}/is', $value, $match))
						{
							$allFields[] = $match[1];
						}
					}
				}

				$multiplePlaceholders = array();

				if ($allFields)
				{
					$query = $db->getQuery(true)
						->select($db->qn('c.ComponentId'))
						->from($db->qn('#__rsform_components', 'c'))
						->join('left', $db->qn('#__rsform_properties', 'p') . ' ON (' . $db->qn('c.ComponentId') . ' = ' . $db->qn('p.ComponentId') . ')')
						->where($db->qn('c.FormId') . ' = ' . $db->q($formId))
						->where($db->qn('p.PropertyName') . ' = ' . $db->q('NAME'))
						->where($db->qn('p.PropertyValue') . ' IN (' . implode(',', $db->q($allFields)) . ')');

					if ($componentIds = $db->setQuery($query)->loadColumn())
					{
						if ($all_data = RSFormProHelper::getComponentProperties($componentIds))
						{
							// Load our form
							$query = $db->getQuery(true)
								->select($db->qn('MultipleSeparator'))
								->from($db->qn('#__rsform_forms'))
								->where($db->qn('FormId') . ' = ' . $db->q($formId));

							// Multiple items separator
							$separator = str_replace(array('\n', '\r', '\t'), array("\n", "\r", "\t"), $db->setQuery($query)->loadResult());

							foreach ($all_data as $componentId => $data)
							{
								if (isset($data['ITEMS']))
								{
									$pos = array_search('{' . $data['NAME'] . ':value}', $args['placeholders']);

									if ($pos !== false)
									{
										$multiplePlaceholders[$data['NAME']] = explode($separator, $args['values'][$pos]);
									}
								}
							}
						}
					}
				}

				foreach ($fields as $field => $value)
				{
					if (!$use_tracking_consent && $field == 'ConsentToTrack') {
						continue;
					}
					// Custom fields should be in a separate array
					if ($field == 'Name' || $field == 'EmailAddress' || $field == 'ConsentToTrack')
					{
						$element[$field] = str_replace($args['placeholders'], $args['values'], $value);
					}
					else
					{
						if ($value !== '')
						{
							/*
							 * Replace multiple fields first so we can send multiple values as per their docs:
							 * Multi-Valued Select Many custom fields are set by providing multiple Custom Field array items with the same key
							*/
							if (isset($multiplePlaceholders[$field]))
							{
								foreach ($multiplePlaceholders[$field] as $multipleValue)
								{
									$customField = array(
										'Key'   => $field,
										'Value' => $multipleValue
									);

									$element['CustomFields'][] = $customField;
								}
							}
							else
							{
								// Replace the usual placeholders
								$customField = array(
									'Key'   => $field,
									'Value' => str_replace($args['placeholders'], $args['values'], $value)
								);

								$element['CustomFields'][] = $customField;
							}
						}
					}
				}

				if (isset($element['ConsentToTrack'])) {
					// the consent must be a string (1 or 0)
					if (is_numeric($element['ConsentToTrack'])) {
						$enable_tracking = (bool) $element['ConsentToTrack'];

						// we must send literally ("yes", "no")
						$element['ConsentToTrack'] = ($enable_tracking ? "yes" : "no");
					} else {
						// if it has any other value than 0/1 or an empty value this is set to "no"
						$element['ConsentToTrack'] = "no";
					}
				}

				// if the consent is not used, then we must force the "unchanged" (alias "unknown") status
				if (!$use_tracking_consent) {
					$element['ConsentToTrack'] = "unchanged";
				}

				$search = $response->get($element['EmailAddress'], true); // must always send the tracking preferences with the new API

				if ($search->was_successful() && $row->campaignmonitor_update)
				{
					$contact = $response->update($element['EmailAddress'], $element);
				}
				elseif ($search->was_successful() && !$row->campaignmonitor_update)
				{
					$getListName = new CS_REST_Lists($row->campaignmonitor_list, $auth);
					$getListName = $getListName->get();

					throw new Exception(Text::sprintf('RSFP_CAMPAIGNMONITOR_ALREADY_SUBSCRIBED', $element['EmailAddress'], $getListName->response->Title));
				}
				else
				{
					$contact = $response->add($element);
				}

				if (!$contact->was_successful())
				{
					throw new Exception(Text::sprintf('RSFP_CAMPAIGNMONITOR_ERROR', $contact->response->Code, $contact->response->Message));
				}
			}
			catch (Exception $e)
			{
				Factory::getApplication()->enqueueMessage($e->getMessage(), 'error');
			}

		}

	}

	/**
	 * @param $formId
	 *
	 * @return mixed
	 */
	protected function _getFields($formId)
	{
		$db    = Factory::getDbo();
		$query = $db->getQuery(true)
			->select($db->qn('p.PropertyValue'))
			->from($db->qn('#__rsform_components', 'c'))
			->join('LEFT', $db->qn('#__rsform_properties', 'p') . ' ON (' . $db->qn('c.ComponentId') . '=' . $db->qn('p.ComponentId') . ')')
			->where($db->qn('c.FormId') . '=' . $db->q($formId))
			->where($db->qn('p.PropertyName') . '=' . $db->q('NAME'))
			->order($db->qn('c.Order') . ' ' . $db->escape('ASC'));

		return $db->setQuery($query)->loadColumn();
	}

	/**
	 * @return array
	 */
	public function standardFields()
	{
		return array(
			'Name'         => Text::_('RSFP_CAMPAIGNMONITOR_NAME'),
			'EmailAddress' => Text::_('RSFP_CAMPAIGNMONITOR_EMAIL'),
			'ConsentToTrack' => Text::_('RSFP_CAMPAIGNMONITOR_TRACK_CONSENT'),
		);
	}

	/**
	 * @param $formId
	 */
	public function onRsformFormDelete($formId)
	{
		if ($row = $this->getTable())
		{
			$row->delete($formId);
		}
	}

	/**
	 * @param $form
	 * @param $xml
	 * @param $fields
	 */
	public function onRsformFormBackup($form, $xml, $fields)
	{
		if ($row = $this->getTable())
		{
			if ($row->load($form->FormId))
			{
				$row->check();

				$data = $row->getProperties();
				unset($data['form_id']);

				$xml->add('campaignmonitor');
				foreach ($data as $property => $value)
				{
					$xml->add($property, $value);
				}
				$xml->add('/campaignmonitor');
			}
		}
	}

	/**
	 * @param $form
	 * @param $xml
	 * @param $fields
	 */
	public function onRsformFormRestore($form, $xml, $fields)
	{
		if (isset($xml->campaignmonitor))
		{
			$data = array(
				'form_id' => $form->FormId
			);
			foreach ($xml->campaignmonitor->children() as $property => $value)
			{
				$data[$property] = (string) $value;
			}
			$row = $this->getTable();
			$row->save($data);
		}
	}

	/**
	 *
	 */
	public function onRsformBackendFormRestoreTruncate()
	{
		Factory::getDbo()->truncateTable('#__rsform_campaignmonitor');
	}
}