<?php
/**
* @version	$Id: addresses_event_handler.php 16562 2017-07-16 14:01:17Z alex $
* @package	In-Commerce
* @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license	Commercial License
* This software is protected by copyright law and international treaties.
* Unauthorized reproduction or unlicensed usage of the code of this program,
* or any portion of it may result in severe civil and criminal penalties,
* and will be prosecuted to the maximum extent possible under the law
* See http://www.in-portal.org/commercial-license for copyright notices and details.
*/
	defined('FULL_PATH') or die('restricted access!');

	class AddressesEventHandler extends kDBEventHandler {

		/**
		 * Allows to override standard permission mapping
		 *
		 * @return void
		 * @access protected
		 * @see kEventHandler::$permMapping
		 */
		protected function mapPermissions()
		{
			parent::mapPermissions();

			$permissions = Array (
				// user can view any form on front-end
				'OnItemBuild' => Array ('subitem' => true),
				'OnUpdate' => Array ('subitem' => true),
				'OnCreate' => Array ('subitem' => true),
				'OnDelete' => Array ('subitem' => true),
			);

			$this->permMapping = array_merge($this->permMapping, $permissions);
		}

		/**
		 * Returns special of main item for linking with sub-item
		 *
		 * @param kEvent $event
		 * @return string
		 * @access protected
		 */
		protected function getMainSpecial(kEvent $event)
		{
			return '';
		}

		/**
		 * Apply any custom changes to list's sql query
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 * @see kDBEventHandler::OnListBuild()
		 */
		protected function SetCustomQuery(kEvent $event)
		{
			parent::SetCustomQuery($event);

			if ( $this->Application->isAdminUser ) {
				return;
			}

			/** @var kDBList $object */
			$object = $event->getObject();

			$user_id = $this->Application->RecallVar('user_id');
			$object->addFilter('myitems_user', '%1$s.PortalUserId = ' . $user_id);
		}

		/**
		 * Makes "use as $type" mark unique among user addresses
		 *
		 * @param kDBItem $object
		 * @param string $type
		 */
		protected function processLastUsed(&$object, $type)
		{
			$is_last = $object->GetDBField('LastUsedAs' . $type);

			if ( $is_last ) {
				$fields_hash = Array ('LastUsedAs' . $type => 0);

				$this->Conn->doUpdate($fields_hash, $object->TableName, 'PortalUserId = ' . $object->GetDBField('PortalUserId'));
			}
		}

		/**
		 * Ensures, that user have only one "use as billing" / "use as shipping" address
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function OnBeforeItemUpdate(kEvent $event)
		{
			parent::OnBeforeItemUpdate($event);

			/** @var kDBItem $object */
			$object = $event->getObject();

			if ( !$object->isLoaded()
				|| (!$this->Application->permissionCheckingDisabled() && !$this->checkItemStatus($event))
			) {
				// Not trivially loaded object OR not current user address.
				$event->status = kEvent::erPERM_FAIL;
				return ;
			}

			/** @var kCountryStatesHelper $cs_helper */
			$cs_helper = $this->Application->recallObject('CountryStatesHelper');

			$cs_helper->CheckStateField($event, 'State', 'Country');
			$cs_helper->PopulateStates($event, 'State', 'Country');

			$this->processLastUsed($object, 'Shipping');
			$this->processLastUsed($object, 'Billing');
		}

		/**
		 * Updates kDBItem
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function OnUpdate(kEvent $event)
		{
			parent::OnUpdate($event);

			$this->setNextTemplate($event);
		}

		/**
		 * Creates new kDBItem
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function OnCreate(kEvent $event)
		{
			parent::OnCreate($event);

			$this->setNextTemplate($event);
		}

		/**
		 * Sets next template to be shown after address is added/updated
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function setNextTemplate(kEvent $event)
		{
			if ( $this->Application->isAdminUser ) {
				return;
			}

			$event->SetRedirectParam('opener', 's');
			$next_template = $this->Application->GetVar('next_template');

			if ( $next_template ) {
				$event->redirect = $next_template;
			}
		}

		/**
		 * Fills states for object country
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function OnAfterItemLoad(kEvent $event)
		{
			parent::OnAfterItemLoad($event);

			/** @var kCountryStatesHelper $cs_helper */
			$cs_helper = $this->Application->recallObject('CountryStatesHelper');

			$cs_helper->PopulateStates($event, 'State', 'Country');
		}

		/**
		 * [HOOK] Update Users table when address marked as ProfileAddress is changed via addr prefix object
		 *
		 * @param kEvent $event
		 * @return bool
		 * @access protected
		 */
		protected function OnUpdateProfileAddress(kEvent $event)
		{
			/** @var kDBItem $object */
			$object = $event->getObject(Array ('skip_autoload' => true));

			if ( !$this->Application->isAdmin ) {
				$address_id = $this->getOrderAddressId();

				if ( !$address_id ) {
					return true;
				}

				$object->Load($address_id);
			}

			if ( !$object->GetDBField('IsProfileAddress') ) {
				return true;
			}

			$field_map = Array (
				'Company'		=>	1,
				'Phone'			=>	1,
				'Fax'			=>	1,
				'Email'			=>	1,
				'Address1'		=>	'Street',
				'Address2'		=>	'Street2',
				'City'			=>	1,
				'State'			=>	1,
				'Zip'			=>	1,
				'Country'		=>	1,
			);

			/** @var UsersItem $user */
			$user = $this->Application->recallObject($this->Application->isAdmin ? 'u' : 'u.current');

			$user->setName( $object->GetDBField('To') );

			foreach ($field_map as $src_field => $dst_field) {
				if ( $dst_field == 1 ) {
					$dst_field = $src_field;
				}

				$user->SetDBField($dst_field, $object->GetDBField($src_field));
			}

			return $user->Update();
		}

		/**
		 * Returns ID of address, that is selected in address dropdown on shipping/billing step of checkout
		 *
		 * @return int
		 * @access protected
		 */
		protected function getOrderAddressId()
		{
			$ret = false;

			if ( $this->Application->GetVar('billing_address_id') > 0 ) {
				$ret = $this->Application->GetVar('billing_address_id');
			}
			elseif ( $this->Application->GetVar('shipping_address_id') > 0 ) {
				$ret = $this->Application->GetVar('shipping_address_id');
			}

			return $ret;
		}

		/**
		 * [HOOK] Create user profile address based on Users table data
		 *
		 * @param kEvent $event
		 * @return bool
		 * @access protected
		 */
		protected function OnUpdateUserProfile(kEvent $event)
		{
			/** @var UsersItem $user */
			$user = $event->MasterEvent->getObject();

			$load_keys = Array ('PortalUserId' => $user->GetID(), 'IsProfileAddress' => 1);

			/** @var kDBItem $object */
			$object = $this->Application->recallObject($event->Prefix . '.-item', null, Array ('skip_autoload' => true));

			$object->Load($load_keys);

			$field_map = Array (
				'PortalUserId'	=>	1,
				'Company'		=>	1,
				'Phone'			=>	1,
				'Fax'			=>	1,
				'Email'			=>	1,
				'Address1'		=>	'Street',
				'Address2'		=>	'Street2',
				'City'			=>	1,
				'State'			=>	1,
				'Zip'			=>	1,
				'Country'		=>	1,
			);

			$full_name = trim($user->GetDBField('FirstName') . ' ' . $user->GetDBField('LastName'));
			$object->SetDBField('To', $full_name);
			$object->SetDBField('IsProfileAddress', 1);

			foreach ($field_map as $dst_field => $src_field) {
				if ( $src_field == 1 ) {
					$src_field = $dst_field;
				}

				$object->SetDBField($dst_field, $user->GetDBField($src_field));
			}

			$sql = 'SELECT SUM(IF(LastUsedAsBilling = 1, 1, 0 )) AS HasBilling, SUM(IF(LastUsedAsShipping = 1, 1, 0)) AS HasShipping
					FROM ' . $object->TableName . '
					WHERE PortalUserId = ' . $user->GetID();
			$address_status = $this->Conn->GetRow($sql);

			if ( !$address_status['HasBilling'] ) {
				$object->SetDBField('LastUsedAsBilling', 1);
			}

			if ( !$address_status['HasShipping'] ) {
				$object->SetDBField('LastUsedAsShipping', 1);
			}

			return $object->isLoaded() ? $object->Update() : $object->Create();
		}

		/**
		 * Checks if user trying to manipulate address that he Owns (exception for Admins)
		 * (non permission-based)
		 *
		 * @param kEvent $event
		 * @return bool
		 * @access protected
		 */
		protected function checkItemStatus(kEvent $event)
		{
			if ( $this->Application->isAdminUser ) {
				return true;
			}

			if ( !$this->Application->LoggedIn() ) {
				return false;
			}

			/** @var kDBItem $object */
			$object = $event->getObject();

			if ( !$object->isLoaded() ) {
				return true;
			}

			return $object->GetDBField('PortalUserId') == $this->Application->RecallVar('user_id');

		}

		/**
		 * Ensures, that user have only one "use as billing" / "use as shipping" address
		 * Disables Guest ability to create addresses
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function OnBeforeItemCreate(kEvent $event)
		{
			parent::OnBeforeItemCreate($event);

			if ( !$this->Application->LoggedIn() ) {
				$event->status = kEvent::erPERM_FAIL;
				return ;
			}

			/** @var kDBItem $object */
			$object = $event->getObject();

			if ( !$this->Application->isAdmin ) {
				$object->SetDBField('PortalUserId', $this->Application->RecallVar('user_id'));
			}

			/** @var kCountryStatesHelper $cs_helper */
			$cs_helper = $this->Application->recallObject('CountryStatesHelper');

			$cs_helper->CheckStateField($event, 'State', 'Country');
			$cs_helper->PopulateStates($event, 'State', 'Country');

			$this->processLastUsed($object, 'Shipping');
			$this->processLastUsed($object, 'Billing');
		}

		/**
		 * Occurs before deleting item, id of item being
		 * deleted is stored as 'id' event param
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function OnBeforeItemDelete(kEvent $event)
		{
			parent::OnBeforeItemDelete($event);

			/** @var kDBItem $object */
			$object = $event->getObject();

			if ( !$object->isLoaded()
				|| (!$this->Application->permissionCheckingDisabled() && !$this->checkItemStatus($event))
			) {
				// Not trivially loaded object OR not current user address.
				$event->status = kEvent::erPERM_FAIL;
				return;
			}
		}

		/**
		 * Sets default country for new addresses to Latvia
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function OnAfterConfigRead(kEvent $event)
		{
			parent::OnAfterConfigRead($event);

			/** @var SiteHelper $site_helper */
			$site_helper = $this->Application->recallObject('SiteHelper');

			$fields = $this->Application->getUnitOption($event->Prefix, 'Fields');
			$fields['Country']['default'] = $site_helper->getDefaultCountry('Shipping');
			$this->Application->setUnitOption($event->Prefix, 'Fields', $fields);
		}

		/**
		 * [HOOK] Creates user addresses editing tab
		 *
		 * @param kEvent $event
		 */
		function OnModifyUsersConfig($event)
		{
			$title_presets = $this->Application->getUnitOption($event->MasterEvent->Prefix, 'TitlePresets');

			$title_presets['user_edit_addresses'] = Array (
				'prefixes' => Array ('u', $event->Prefix . '_List'),
				'format' => "#u_status# '#u_titlefield#' - !la_title_Addresses! (#" . $event->Prefix . "_recordcount#)"
			);

			$title_presets['user_address_edit'] = Array (
				'prefixes' => Array ('u', $event->Prefix),
				'new_status_labels' => Array ($event->Prefix => '!la_title_AddingAddress!'),
				'edit_status_labels' => Array ($event->Prefix => '!la_title_EditingAddress!'),
				'new_titlefield' => Array ($event->Prefix => '!la_title_NewAddress!'),
				'format' => "#u_status# '#u_titlefield#' - #{$event->Prefix}_status#"
			);
			$this->Application->setUnitOption($event->MasterEvent->Prefix, 'TitlePresets', $title_presets);

			$edit_tab_presets = $this->Application->getUnitOption($event->MasterEvent->Prefix, 'EditTabPresets');

			$edit_tab_presets['Default']['addresses'] = Array (
				'title' => 'la_tab_Addresses', 't' => 'in-commerce/users/user_edit_addresses', 'priority' => 6
			);

			$this->Application->setUnitOption($event->MasterEvent->Prefix, 'EditTabPresets', $edit_tab_presets);
		}
	}
