<?php
/**
 * @package    VP Advanced User
 * @author     Abhishek Das <info@virtueplanet.com>
 * @copyright  Copyright (C) 2012-2019 VirtuePlanet Services LLP. All rights reserved.
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 * @link       https://www.virtueplanet.com
 */

defined('_JEXEC') or die;

/**
 * Class VPAdvancedUserController
 */
class VPAdvancedUserController extends JControllerLegacy
{
	/**
	 * Method to display a view.
	 *
	 * @param   boolean  $cachable   If true, the view output will be cached
	 * @param   array    $urlparams  An array of safe url parameters and their variable types, for valid values see {@link JFilterInput::clean()}.
	 *
	 * @return  JController  This object to support chaining.
	 */
	public function display($cachable = false, $urlparams = false)
	{
		// Get the document object.
		$document = JFactory::getDocument();
		$user     = JFactory::getUser();

		// Set the default view name and format from the Request.
		$vName   = $this->input->getCmd('view', 'login');
		$vFormat = $document->getType();
		$lName   = $this->input->getCmd('layout', 'default');

		if ($view = $this->getView($vName, $vFormat))
		{
			// Do any specific processing by view.
			switch ($vName)
			{
				// Handle view specific models.
				case 'authenticate':
					$model  = $this->getModel($vName);
					// We authenticate the user on display task
					$result = $this->authenticate($model);
					// If result is boolean that means it has redirection.
					// Therefore we must stop procedings.
					if(in_array($result, array(true, false), true))
					{
						return;
					}
					break;

				case 'profile':
					if ($user->get('guest'))
					{
						// Redirect to login page.
						$this->setRedirect(JRoute::_('index.php?option=com_vpadvanceduser&view=login', false));
						return;
					}
					$model = $this->getModel($vName);
					break;

				case 'resend':
					if (!$user->get('guest'))
					{
						// Redirect to login page.
						$this->setRedirect(JRoute::_('index.php?option=com_vpadvanceduser&view=profile', false));
						return;
					}
					$model = $this->getModel($vName);
					break;

				case 'reset':
					if (!$user->get('guest'))
					{
						// Redirect to login page.
						$this->setRedirect(JRoute::_('index.php?option=com_vpadvanceduser&view=profile', false));
						return;
					}
					$model = $this->getModel($vName);
					break;

				// Handle the default views.
				case 'login':
				default:
					if (!$user->get('guest'))
					{
						// Redirect to login page.
						$this->setRedirect(JRoute::_('index.php?option=com_vpadvanceduser&view=profile', false));
						return;
					}
					$model = $this->getModel('Login');
					// Get registration model
					$registration_model = $this->getModel('Registration');
					// Add registration model to login view 
					$view->setModel($registration_model, false);
					break;
			}

			// Push the model into the view (as default).
			$view->setModel($model, true);
			$view->setLayout($lName);

			// Push document object into the view.
			$view->document = $document;

			$view->display();
		}
	}
	
	/**
	* Method to authenticate user login/registration/link
	* 
	* @param  object  $model VPAdvancedUserModelAuthenticate class instance
	* 
	* @return mixed   (boolean/null) null in case of popup and true/false in case of direct redirection
	*/
	protected function authenticate($model)
	{
		jimport('joomla.session.session');
		
		JTable::addIncludePath(JPATH_COMPONENT_ADMINISTRATOR . '/tables');
		
		$table      = JTable::getInstance('Session_providers', 'VPAdvancedUserTable');
		$session_id = JFactory::getSession()->getId();
		
		!empty($session_id) or jexit(JText::_('JINVALID_TOKEN'));
		
		// Initialize some required variables
		$app                   = JFactory::getApplication();
		$params                = JComponentHelper::getParams('com_vpadvanceduser');
		$method                = $app->input->getMethod();
		$provider              = null;
		$openid_identifier     = '';
		$provider_new          = $this->input->post->getCmd('provider', '');
		$openid_identifier_new = $this->input->post->getString('openid_identifier', '');
		$return                = null;
		$entry                 = null;
		$encodeFilter          = VPAdvancedUserHelperUtility::getEncodeFilter();
		
		if(!JSession::checkToken())
		{
			$table->load($session_id);
			
			if(empty($provider_new) && $table->session_id)
			{
				// This means it is a redirection from Hybrid.
				// We set the provider from previous request.
				$provider          = $table->provider;
				$openid_identifier = !empty($table->openid_identifier) ? @json_decode($table->openid_identifier) : '';
				$entry             = !empty($table->provider_entry) ? VPAdvancedUserHelperUtility::decode($table->provider_entry) : null;
				$return            = !empty($table->provider_return) ? VPAdvancedUserHelperUtility::decode($table->provider_return) : null;
			}
		}
		elseif(!empty($provider_new))
		{
			// We check token only when new authentication request is called
			$this->_checkToken();
			
			// Set the provider from input
			$provider          = $provider_new;
			$openid_identifier = $openid_identifier_new;
		}
		
		if(empty($entry))
		{
			$entry = $this->input->post->get('entry', '', $encodeFilter);
			$entry = !empty($entry) ? VPAdvancedUserHelperUtility::decode($entry) : null;
			
			if(is_numeric($entry))
			{
				$lang = VPAdvancedUserFrontendHelper::getMenuItemLanguageString($entry);
				
				$entry = 'index.php?Itemid=' . $entry . $lang;
			}
			elseif(empty($entry))
			{
				$entry = VPAdvancedUserHelperRoute::getURL('login', 'login', true);
			}
		}
		
		if(empty($return))
		{
			$return = $this->input->post->get('return', '', $encodeFilter);
			$return = !empty($return) ? VPAdvancedUserHelperUtility::decode($return) : null;
			
			if(is_numeric($return))
			{
				$lang = VPAdvancedUserFrontendHelper::getMenuItemLanguageString($return);
				
				$return = 'index.php?Itemid=' . $return . $lang;
			}
			elseif(empty($return))
			{
				$return_menuitem = $params->get('login_redirect_menuitem');
				
				if(!empty($return_menuitem) && is_numeric($return_menuitem))
				{
					$lang = VPAdvancedUserFrontendHelper::getMenuItemLanguageString($return_menuitem);
					
					$return = 'index.php?Itemid=' . $return_menuitem . $lang;
				}
				else
				{
					$return = VPAdvancedUserHelperRoute::getURL('profile');
				}
			}
		}
		
		$tmpl  = $this->input->getWord('tmpl', '');
		$popup = (strtolower($tmpl) == 'component') ? true : false;

		// If no provider is set
		if(empty($provider))
		{
			if(strtolower($method) == 'post' && !JSession::checkToken())
			{
				$this->_checkToken();
			}
			else
			{
				if(strtolower($method) == 'post')
				{
					$app->enqueueMessage(JText::_('COM_VPADVANCEDUSER_ERROR_PROVIDER_NOT_SELECTED'));
					$app->redirect(JRoute::_($entry, false));
					return false;
				}
				
				if(!JFactory::getUser()->get('guest') && !empty($return))
				{
					$app->redirect(JRoute::_($return, false) . '#');
					return false;
				}

				throw new Exception(JText::_('JGLOBAL_AUTH_ACCESS_DENIED'), 403);
			}
		}

		// Save the provider if not saved
		if($table->provider != $provider)
		{
			// Prepare session 
			$session_data = array(
				'session_id' => $session_id,
				'provider' => $provider,
				'openid_identifier' => @json_encode($openid_identifier),
				'provider_entry' => VPAdvancedUserHelperUtility::encode($entry),
				'provider_return' => VPAdvancedUserHelperUtility::encode($return)
			);
			
			if(!$table->bind($session_data))
			{
				if($popup)
				{
					$model->setState('status', false);
					$model->set('message', $table->getError());
					return null;
				}
				
				$app->enqueueMessage($table->getError(), 'error');
				$app->redirect(JRoute::_($entry, false));
				return false;
			}
			
			if(!$table->check())
			{
				if($popup)
				{
					$model->setState('status', false);
					$model->set('message', $table->getError());
					return null;
				}
				
				$app->enqueueMessage($table->getError(), 'error');
				$app->redirect(JRoute::_($entry, false));
				return false;
			}

			if(!$table->store())
			{
				if($popup)
				{
					$model->setState('status', false);
					$model->set('message', $table->getError());
					return null;
				}
				
				$app->enqueueMessage($table->getError(), 'error');
				$app->redirect(JRoute::_($entry, false));
				return false;
			}
		}

		// Set provider for model
		$this->input->set('provider', $provider);
		$model->setState('provider', $provider);
		
		// Ser openid provider
		$this->input->set('openid_identifier', $openid_identifier);
		$model->setState('openid_identifier', $openid_identifier);

		// Get the status for the given provider.
		// This may redirect externally by Hybrid whenever needed.
		if(!$model->getStatus())
		{
			$model->setState('status', false);
			$message_type = 'warning';
			$final_return = $entry;
		}
		else
		{
			$model->setState('status', true);
			$message_type = 'message';
			$final_return = $return;
		}
		
		// Clean session provider.
		// We reach here only after hybrid returns some status.
		if(!$table->delete($session_id))
		{
			if($popup)
			{
				$model->setState('status', false);
				$model->set('message', $table->getError());
				return null;
			}

			$app->enqueueMessage($table->getError(), 'error');
			$app->redirect(JRoute::_($entry, false));
			return false;
		}
		
		// If not popup display messages normally and redirect the user to the return page.
		if(!$popup)
		{
			$message = $model->getState('message', '');
			$errors  = $model->getErrors();
			
			foreach($errors as $error)
			{
				if($error == $message || empty($error))
				{
					continue;
				}
				
				$app->enqueueMessage($error, 'error');
			}
			
			$user = JFactory::getUser();
			
			// If registration in process 
			if($app->getUserState('com_vpadvanceduser.registration.inprocess', false) && $user->guest)
			{
				$final_return = VPAdvancedUserHelperRoute::getURL('login', 'registration', true);
				$message_type = 'notice';
			}
			elseif(empty($final_return))
			{
				if($user->guest)
				{
					$final_return = VPAdvancedUserHelperRoute::getURL('login', 'login', true);
				}
				else
				{
					$return_menuitem = $params->get('login_redirect_menuitem');
					
					if(!empty($return_menuitem) && is_numeric($return_menuitem))
					{
						$lang = VPAdvancedUserFrontendHelper::getMenuItemLanguageString($return_menuitem);
						
						$final_return = 'index.php?Itemid=' . $return_menuitem . $lang;
					}
					else
					{
						$final_return = VPAdvancedUserHelperRoute::getURL('profile');
					}
				}
			}
			
			if(!empty($message))
			{
				$app->enqueueMessage($message, $message_type);
			}
			
			// Dirty hack to remove stupid hash (#_=_) added by Facebook
			$redirect_to = JRoute::_($final_return, false);
			$redirect_to = strpos($redirect_to, '#') === false ? ($redirect_to . '#') : $redirect_to;

			$app->redirect($redirect_to);
			return true;
		}
		
		return null;
	}
	
	/**
	 * Checks for a form token in the request.
	 *
	 * Use in conjunction with JHtml::_('form.token') or JSession::getFormToken.
	 *
	 * @param   string   $method    The request method in which to look for the token key.
	 *
	 * @return  boolean  True if found and valid, otherwise return false or redirect to referrer page.
	 */
	protected function _checkToken($method = 'post')
	{
		$app    = JFactory::getApplication();
		$doc    = JFactory::getDocument();
		$input  = $app->input;
		$method = !empty($method) ? $method : $input->getMethod();
		$method = !empty($method) ? $method : 'post';
		$valid  = JSession::checkToken($method);
		
		if(!$valid)
		{
			$format = strtoupper($doc->getType());
			
			if($format == 'JSON')
			{
				VPAdvancedUserHelperUtility::jsonResponse(array('error' => true, 'result' => false, 'message' => JText::_('JINVALID_TOKEN_NOTICE')));
			}
			
			if($format != 'HTML')
			{
				die(JText::_('JINVALID_TOKEN_NOTICE'));
			}
			
			$entry = $input->post->get('entry', '', $encodeFilter);
			$entry = !empty($entry) ? VPAdvancedUserHelperUtility::decode($entry) : null;
			$referrer = null;
			
			if(is_numeric($entry))
			{
				$lang = VPAdvancedUserFrontendHelper::getMenuItemLanguageString($entry);
				
				$entry = 'index.php?Itemid=' . $entry . $lang;
			}

			if($entry && JUri::isInternal($entry))
			{
				$referrer = $entry;
			}
			
			if(empty($referrer))
			{
				$referrer = $input->server->getString('HTTP_REFERER');
				
				if(!JUri::isInternal($referrer))
				{
					$referrer = 'index.php';
				}
			}
			
			$app->enqueueMessage(JText::_('JINVALID_TOKEN_NOTICE'), 'warning');
			$app->redirect($referrer);
		}
		
		return $valid;
	}
}
