<?php

/**
 * eSales Media Formilicious for Contao Open Source CMS
 *
 * Copyright (C) 2013-2014 eSalesMedia
 *
 * @package    eSM_formilicious
 * @link       http://www.esales-media.de
 * @license    http://www.gnu.org/licenses/lgpl-3.0.html LGPL
 *
 * @author     Benjamin Roth <benjamin@esales-media.de>
 */


/**
 * Run in a custom namespace, so the class can be replaced
 */
namespace eSM_formilicious;


/**
 * Class ModulePersonalData
 *
 * Front end module "personal data".
 * @copyright  Leo Feyer 2005-2014
 * @author     Leo Feyer <https://contao.org>
 * @package    Core
 */
class ModulePersonalData extends \Contao\ModulePersonalData
{

	/**
	 * Generate the module
	 */
	protected function compile()
	{
		global $objPage;
		$this->import('FrontendUser', 'User');

		$GLOBALS['TL_LANGUAGE'] = $objPage->language;

		\System::loadLanguageFile('tl_member');
		$this->loadDataContainer('tl_member');

		// Call onload_callback (e.g. to check permissions)
		if (is_array($GLOBALS['TL_DCA']['tl_member']['config']['onload_callback']))
		{
			foreach ($GLOBALS['TL_DCA']['tl_member']['config']['onload_callback'] as $callback)
			{
				if (is_array($callback))
				{
					$this->import($callback[0]);
					$this->$callback[0]->$callback[1]();
				}
				elseif (is_callable($callback))
				{
					$callback();
				}
			}
		}

		// Set the template
		if ($this->memberTpl != '')
		{
			$this->Template = new \FrontendTemplate($this->memberTpl);
			$this->Template->setData($this->arrData);
		}

		$this->Template->fields = '';
		$this->Template->tableless = $this->tableless;

		$arrFields = array();
		$doNotSubmit = false;
		$hasUpload = false;
		$row = 0;

		$blnModified = false;
		$objMember = \MemberModel::findByPk($this->User->id);

		// Build the form
		foreach ($this->editable as $fielddata)
		{
			// Split formilicious editable data in single vars
			list($field,$fieldWidth,$fieldClr,$fieldMandatory) = array_values($fielddata);
			$arrData = &$GLOBALS['TL_DCA']['tl_member']['fields'][$field];

			// Map checkboxWizards to regular checkbox widgets
			if ($arrData['inputType'] == 'checkboxWizard')
			{
				$arrData['inputType'] = 'checkbox';
			}

			$strClass = $GLOBALS['TL_FFL'][$arrData['inputType']];

			// Continue if the class does not exist
			if (!$arrData['eval']['feEditable'] || !class_exists($strClass))
			{
				continue;
			}

			$strGroup = $arrData['eval']['feGroup'];

			$arrData['eval']['required'] = false;
			$arrData['eval']['tableless'] = $this->tableless;

			// Use strlen() here (see #3277)
			if ($arrData['eval']['mandatory'])
			{
				if (is_array($this->User->$field))
				{
					if (empty($this->User->$field))
					{
						$arrData['eval']['required'] = true;
					}
				}
				else
				{
					if (!strlen($this->User->$field))
					{
						$arrData['eval']['required'] = true;
					}
				}
			}

			$varValue = $this->User->$field;

			// Call the load_callback
			if (isset($arrData['load_callback']) && is_array($arrData['load_callback']))
			{
				foreach ($arrData['load_callback'] as $callback)
				{
					if (is_array($callback))
					{
						$this->import($callback[0]);
						$varValue = $this->$callback[0]->$callback[1]($varValue, $this->User, $this);
					}
					elseif (is_callable($callback))
					{
						$varValue = $callback($varValue, $this->User, $this);
					}
				}
			}

			$objWidget = new $strClass($strClass::getAttributesFromDca($arrData, $field, $varValue, '', '', $this));

			$objWidget->storeValues = true;
			$objWidget->rowClass = 'row_'.$row . (($row == 0) ? ' row_first' : '') . ((($row % 2) == 0) ? ' even' : ' odd');

			// Extend with formilicious data
			$objWidget->eSM_fl_width = $fieldWidth;
			$objWidget->eSM_fl_clear = $fieldClr;
			if ($fieldMandatory)
			{
				$objWidget->required = $fieldMandatory;
				$objWidget->mandatory = $fieldMandatory;
			} else {
				$objWidget->required = false;
				$objWidget->mandatory = false;
			}
			if (in_array($arrData['eval']['rgxp'], array('date','time','datim')))
			{
				$strDateFormatFunc = 'getNumeric'.ucfirst($arrData['eval']['rgxp']).'Format';
				$objWidget->placeholder = \Date::getInputFormat(\Date::$strDateFormatFunc());
				$objWidget->maxlength = strlen($objWidget->placeholder);
			}

			// Increase the row count if it is a password field
			if ($objWidget instanceof \FormPassword)
			{
				++$row;
				$objWidget->rowClassConfirm = 'row_'.$row . ((($row % 2) == 0) ? ' even' : ' odd');
			}

			// Validate the form data
			if (\Input::post('FORM_SUBMIT') == 'tl_member_' . $this->id)
			{
				$objWidget->validate();
				$varValue = $objWidget->value;

				$rgxp = $arrData['eval']['rgxp'];

				// Convert date formats into timestamps (check the eval setting first -> #3063)
				if (($rgxp == 'date' || $rgxp == 'time' || $rgxp == 'datim') && $varValue != '')
				{
					try
					{
						$objDate = new \Date($varValue);
						$varValue = $objDate->tstamp;
					}
					catch (\OutOfBoundsException $e)
					{
						$objWidget->addError(sprintf($GLOBALS['TL_LANG']['ERR']['invalidDate'], $varValue));
					}
				}

				// Make sure that unique fields are unique (check the eval setting first -> #3063)
				if ($arrData['eval']['unique'] && $varValue != '' && !$this->Database->isUniqueValue('tl_member', $field, $varValue, $this->User->id))
				{
					$objWidget->addError(sprintf($GLOBALS['TL_LANG']['ERR']['unique'], $arrData['label'][0] ?: $field));
				}

				// Trigger the save_callback (see #5247)
				if ($objWidget->submitInput() && !$objWidget->hasErrors() && is_array($arrData['save_callback']))
				{
					foreach ($arrData['save_callback'] as $callback)
					{
						try
						{
							if (is_array($callback))
							{
								$this->import($callback[0]);
								$varValue = $this->$callback[0]->$callback[1]($varValue, $this->User, $this);
							}
							elseif (is_callable($callback))
							{
								$varValue = $callback($varValue, $this->User, $this);
							}
						}
						catch (\Exception $e)
						{
							$objWidget->class = 'error';
							$objWidget->addError($e->getMessage());
						}
					}
				}

				// Do not submit the field if there are errors
				if ($objWidget->hasErrors())
				{
					$doNotSubmit = true;
				}
				elseif ($objWidget->submitInput())
				{
					// Store the form data
					$_SESSION['FORM_DATA'][$field] = $varValue;

					// Set the correct empty value (see #6284, #6373)
					if ($varValue === '')
					{
						$varValue = $objWidget->getEmptyValue();
					}

					// Set the new value
					$this->User->$field = $varValue;

					// Set the new field in the member model
					$blnModified = true;
					$objMember->$field = $varValue;
				}
			}

			if ($objWidget instanceof \uploadable)
			{
				$hasUpload = true;
			}

			$temp = $objWidget->parse();

			$this->Template->fields .= $temp;
			$arrFields[$strGroup][$field] .= $temp;
			++$row;
		}

		// Save the model
		if ($blnModified)
		{
			$objMember->save();
		}

		$this->Template->hasError = $doNotSubmit;

		// Redirect or reload if there was no error
		if (\Input::post('FORM_SUBMIT') == 'tl_member_' . $this->id && !$doNotSubmit)
		{
			// HOOK: updated personal data
			if (isset($GLOBALS['TL_HOOKS']['updatePersonalData']) && is_array($GLOBALS['TL_HOOKS']['updatePersonalData']))
			{
				foreach ($GLOBALS['TL_HOOKS']['updatePersonalData'] as $callback)
				{
					$this->import($callback[0]);
					$this->$callback[0]->$callback[1]($this->User, $_SESSION['FORM_DATA'], $this);
				}
			}

			// Call the onsubmit_callback
			if (is_array($GLOBALS['TL_DCA']['tl_member']['config']['onsubmit_callback']))
			{
				foreach ($GLOBALS['TL_DCA']['tl_member']['config']['onsubmit_callback'] as $callback)
				{
					if (is_array($callback))
					{
						$this->import($callback[0]);
						$this->$callback[0]->$callback[1]($this->User, $this);
					}
					elseif (is_callable($callback))
					{
						$callback($this->User, $this);
					}
				}
			}

			// Check whether there is a jumpTo page
			if (($objJumpTo = $this->objModel->getRelated('jumpTo')) !== null)
			{
				$this->jumpToOrReload($objJumpTo->row());
			}

			$this->reload();
		}

		$this->Template->loginDetails = $GLOBALS['TL_LANG']['tl_member']['loginDetails'];
		$this->Template->addressDetails = $GLOBALS['TL_LANG']['tl_member']['addressDetails'];
		$this->Template->contactDetails = $GLOBALS['TL_LANG']['tl_member']['contactDetails'];
		$this->Template->personalData = $GLOBALS['TL_LANG']['tl_member']['personalData'];

		// Add groups
		foreach ($arrFields as $k=>$v)
		{
			$this->Template->$k = $v;
		}

		$this->Template->formId = 'tl_member_' . $this->id;
		$this->Template->slabel = specialchars($GLOBALS['TL_LANG']['MSC']['saveData']);
		$this->Template->action = \Environment::get('indexFreeRequest');
		$this->Template->enctype = $hasUpload ? 'multipart/form-data' : 'application/x-www-form-urlencoded';
		$this->Template->rowLast = 'row_' . $row . ((($row % 2) == 0) ? ' even' : ' odd');

		// HOOK: add memberlist fields
		if (in_array('memberlist', \ModuleLoader::getActive()))
		{
			$this->Template->profile = $arrFields['profile'];
			$this->Template->profileDetails = $GLOBALS['TL_LANG']['tl_member']['profileDetails'];
		}

		// HOOK: add newsletter fields
		if (in_array('newsletter', \ModuleLoader::getActive()))
		{
			$this->Template->newsletter = $arrFields['newsletter'];
			$this->Template->newsletterDetails = $GLOBALS['TL_LANG']['tl_member']['newsletterDetails'];
		}

		// HOOK: add helpdesk fields
		if (in_array('helpdesk', \ModuleLoader::getActive()))
		{
			$this->Template->helpdesk = $arrFields['helpdesk'];
			$this->Template->helpdeskDetails = $GLOBALS['TL_LANG']['tl_member']['helpdeskDetails'];
		}
	}
}