<?php
	namespace Mocha\UI\Pages;
	
	use Mocha\Core\KnownAttributeGuids;
	use Mocha\Core\KnownClassGuids;
	use Mocha\Core\KnownInstanceGuids;
	use Mocha\Core\KnownMethodBindingGuids;
	use Mocha\Core\KnownRelationshipGuids;

	use Mocha\Core\OmsContext;
	
	use Mocha\UI\Renderers\HTML\HTMLRenderer;
	use Phast\CancelEventArgs;
	use Phast\EventArgs;
	use Phast\RenderingEventArgs;
	use Phast\System;
	use Phast\WebPage;

	use Mocha\Oms\MySQLDatabaseOms;
	class LoginPage extends WebPage
	{
		protected function OnInitializing(CancelEventArgs $e)
		{
			$this->Page->MasterPage->ClassReference->RequireLogin = false;
			return true;
		}

		/**
		 * Thanks https://stackoverflow.com/a/31107425
		 * 
		 * Generate a random string, using a cryptographically secure 
		 * pseudorandom number generator (random_int)
		 *
		 * This function uses type hints now (PHP 7+ only), but it was originally
		 * written for PHP 5 as well.
		 * 
		 * For PHP 7, random_int is a PHP core function
		 * For PHP 5.x, depends on https://github.com/paragonie/random_compat
		 * 
		 * @param int $length      How many characters do we want?
		 * @param string $keyspace A string of all possible characters
		 *                         to select from
		 * @return string
		 */
		private function random_str(int $length = 64, string $keyspace = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' ) : string
		{
			if ($length < 1)
			{
				throw new \RangeException("Length must be a positive integer");
			}
			$pieces = [];
			$max = \mb_strlen($keyspace, '8bit') - 1;
			for ($i = 0; $i < $length; ++$i)
			{
				$pieces[] = $keyspace[\random_int(0, $max)];
			}
			return \implode('', $pieces);
		}

		protected function OnRendering(RenderingEventArgs $re)
		{
			parent::OnRendering($re);
			
			/**
			 * @var MySQLDatabaseOms
			 */
			$oms = mocha_get_oms();

			//mocha_init_spot_timer($this);

			$path =  System::GetVirtualPath();
			$tenantName = "";
			if ($path[0] == "madi")
			{
				$tenantName = $path[2];
			}
			else
			{
				$tenantName = $path[0];
			}
			$oms->setTenant($oms->getTenantByName($tenantName));

			$pageElement = $oms->getInstanceByGlobalIdentifier(KnownInstanceGuids::Element__LoginPage);
			if ($pageElement === null)
			{
				print ("could not find element 'LoginPage'");
				die();
			}

			$context = new OmsContext();
			
			$renderer = new HTMLRenderer($context);
			$renderer->IncludeTopNavigationBar = false;
			
			# $contents = $pageElement->getRelatedInstances($oms->getInstanceByGlobalIdentifier(KnownRelationshipGuids::Element__has__Element_Content));
			$renderer->ProcessUpdatesFunction = function($sender, $element)
			{
				/**
				 * @var MySQLDatabaseOms
				 */
				$oms = mocha_get_oms();
	
				$ec_UserName = $oms->getInstanceByGlobalIdentifier(KnownInstanceGuids::ElementContent__UserNameForLoginPage);
				$ec_Password = $oms->getInstanceByGlobalIdentifier(KnownInstanceGuids::ElementContent__PasswordForLoginPage);
	
				// $ct = $oms->getRelatedInstance($element, $oms->getInstanceByGlobalIdentifier(KnownRelationshipGuids::Element__processed_by__Control_Transaction_Method));
				// Login Page@ Login Page Edit(CT)*S
				// uses Build Response Method Binding...
				// 
	
				$userName = $sender->getElementContentValue($ec_UserName); // $_POST["ec_56$4"];
				$password = $sender->getElementContentValue($ec_Password); // $_POST["ec_56$5"];
				
				$mbUser__get__User_for_User_Name_parm = $oms->getInstanceByGlobalIdentifier(KnownMethodBindingGuids::User__get__User_for_User_Name_parm);
				if ($mbUser__get__User_for_User_Name_parm === null)
				{
					echo("`User@get User for User Name parm`: method not found ('" . KnownMethodBindingGuids::User__get__User_for_User_Name_parm . "')");die();
				}
				$mbUser__get__User_for_User_Name_parm = $mbUser__get__User_for_User_Name_parm->asMethodBinding();
				
				$instUser = $mbUser__get__User_for_User_Name_parm->executeReturningInstanceSet(array( KnownAttributeGuids::UserName => $userName ));
				if ($instUser !== null)
				{
					$passwordSalt = $oms->getAttributeValue($instUser, $oms->getInstanceByGlobalIdentifier(KnownAttributeGuids::PasswordSalt));
					$passwordHashExpected = $oms->getAttributeValue($instUser, $oms->getInstanceByGlobalIdentifier(KnownAttributeGuids::PasswordHash));
					$passwordHashActual = hash('sha512', $password . $passwordSalt);
					
					if ($passwordHashExpected == $passwordHashActual)
					{
						$token = $this->random_str();
	
						// create the instance of `System Account Signon`
						$instLogin = $oms->createInstanceOf($oms->getInstanceByGlobalIdentifier(KnownClassGuids::UserLogin));
						if ($instLogin !== null)
						{
							// FIXME:  these attribute should be defined in the Mocha/ZQ
							// FIXME:  they should be wrapped in a conditional which checks if we are serving in a GDPR compliant region
							// should we be storing this information then? probably not...
							
							$oms->setAttributeValue($instLogin, KnownAttributeGuids::Token, $token);
							$oms->setAttributeValue($instLogin, KnownAttributeGuids::IPAddress, $_SERVER["REMOTE_ADDR"]);
							$oms->assignRelationship($instLogin, $oms->getInstanceByGlobalIdentifier(KnownRelationshipGuids::User_Login__has__User), $instUser);
						}
						
						$_SESSION["user_token_" . $oms->getTenant()->ID] = $token;
						System::RedirectFromLoginPage();
						exit();
					}
					else
					{
						//$this->Page->GetControlByID("literal1")->EnableRender = true;
	
						//System::RedirectToLoginPage(true);
					}
				}
				$ecPasswordMsg = $oms->getInstanceByGlobalIdentifier("684f1e039ecd43d58acadcf5b84c71f8");
				$sender->Context->setElementParm($ecPasswordMsg, "visible", true);
			};

			$renderer->IsPostback = $this->Page->IsPostback;
			$renderer->StyleClasses[] = "mcx-loginpage";
			if ($this->Page->IsPostback)
			{
				$renderer->processPostback($pageElement);
			}
			$renderer->SubmitButtonText = "Log In";
			$renderer->renderInitialElement($pageElement);
			exit();
			
		}

	}
?>