<?php
namespace SabaiApps\Directories\Component\Notification;

use SabaiApps\Directories\Component\AbstractComponent;
use SabaiApps\Directories\Component\Directory\Model\Directory;
use SabaiApps\Directories\Component\System;
use SabaiApps\Directories\Context;
use SabaiApps\Directories\Application;

class NotificationComponent extends AbstractComponent implements
	System\IAdminRouter,
	IEvents,
	ISenders,
	System\ITools {

	const VERSION = '2.0.6', PACKAGE = 'directories-pro';

	public static function description() {
		return 'Notify anyone about any event triggered on your site.';
	}

	public function systemAdminRoutes() {
		return array(
			'/directories/settings/notifications'     => array(
				'controller'      => 'Notifications',
				'access_callback' => true,
				'title_callback'  => true,
				'callback_path'   => 'notifications',
			),
			'/directories/settings/notifications/add' => array(
				'controller'     => 'AddNotification',
				'callback_path'  => 'add_notification',
				'title_callback' => true,
			),
			'/directories/settings/notifications/:notification_id' => array(
				'controller'      => 'EditNotification',
				'callback_path'   => 'edit_notification',
				'title_callback'  => true,
				'access_callback' => true,
				'format'          => array( ':notification_id' => '\d+' ),
			),
			'/directories/settings/notifications/:notification_id/delete' => array(
				'controller'      => 'DeleteNotification',
				'title_callback'  => true,
				'access_callback' => true,
				'callback_path'   => 'delete_notification',
			),
			'/directories/settings/notifications/set_status' => array(
				'controller' => 'SetNotificationStatus',
				'type'       => Application::ROUTE_CALLBACK,
				'method'     => 'post',
			),
		);
	}

	public function systemOnAccessAdminRoute( Context $context, $path, $accessType, array &$route ) {
		switch ( $path ) {
			case 'notifications':
				return $this->_application->getUser()->isAdministrator();
			case 'edit_notification':
				if ( $accessType === Application::ROUTE_ACCESS_LINK ) {
					if ( ( ! $notification_id = $context->getRequest()->asInt( 'notification_id' ) )
						|| ( ! $notification = $this->getModel( 'Notification' )->fetchById( $notification_id ) )
					) {
						return false;
					}

					$context->notification = $notification;
				}
				return true;
			case 'delete_notification':
				return ! $context->notification->system;
		}
	}

	public function systemAdminRouteTitle( Context $context, $path, $titleType, array $route ) {
		switch ( $path ) {
			case 'notifications':
				return __( 'Notifications', 'directories-pro' );
			case 'add_notification':
				return __( 'Add Notification', 'directories-pro' );
			case 'edit_notification':
				return $context->notification->getLabel();
			case 'delete_notification':
				return __( 'Delete Notification', 'directories-pro' );
		}
	}

	public function notificationGetEventNames() {
		$ret = array();
		foreach ( $this->_application->Entity_BundleTypes_byFeatures( array( 'public' ), 'post' ) as $bundle_type ) {
			$ret[] = 'post_pending_' . $bundle_type;
			$ret[] = 'post_published_' . $bundle_type;
		}
		foreach ( $this->_application->Entity_BundleTypes_byFeatures( array( 'expirable' ), 'post' ) as $bundle_type ) {
			$ret[] = 'post_expired_' . $bundle_type;
		}
		return $ret;
	}

	public function notificationGetEvent( $name ) {
		if ( strpos( $name, 'post_pending_' ) === 0 ) {
			return new Event\PostPendingEvent( $this->_application, $name, substr( $name, strlen( 'post_pending_' ) ) );
		} elseif ( strpos( $name, 'post_published_' ) === 0 ) {
			return new Event\PostPublishedEvent( $this->_application, $name, substr( $name, strlen( 'post_published_' ) ) );
		} elseif ( strpos( $name, 'post_expired_' ) === 0 ) {
			return new Event\PostExpiredEvent( $this->_application, $name, substr( $name, strlen( 'post_expired_' ) ) );
		}
	}

	public function notificationGetSenderNames() {
		$ret = array( 'email' );
		if ( $this->_application->getPlatform()->getName() === 'WordPress'
			&& ( function_exists( 'twl_send_sms' ) || function_exists( 'wp_sms_send' ) )
		) {
			$ret[] = 'wpsms';
		}
		return $ret;
	}

	public function notificationGetSender( $name ) {
		switch ( $name ) {
			case 'email':
				return new Sender\EmailSender( $this->_application, $name );
			case 'wpsms':
				return new Sender\WordPressSmsSender( $this->_application, $name );
		}
	}

	protected function _getActionToEventMap() {
		if ( ! $map = $this->_application->getPlatform()->getCache( 'notification_action_event_map' ) ) {
			$map = array();
			foreach ( $this->getModel( 'Notification' )->active_is( 1 )->fetch() as $notification ) {
				if ( ! $event = $this->_application->Notification_Services_event( $notification->event, true ) ) {
					continue;
				}

				foreach ( (array) $event->notificationEventInfo( 'actions' ) as $action ) {
					$_action                                 = str_replace( '_', '', strtolower( $action ) );
					$map[ $_action ][ $notification->event ] = 1;
					$map[ $_action ]['_action']              = $action;
				}
			}
			$this->_application->getPlatform()->setCache( $map, 'notification_action_event_map', 0 );
		}

		return $map;
	}

	public function onCoreComponentsLoaded() {
		// Listen to actions for events
		if ( $map = $this->_getActionToEventMap() ) {
			foreach ( array_keys( $map ) as $action ) {
				$this->_application->addEventListener( $action, $this->_name );
			}
		}
	}

	public function handleEvent( $eventType, array $eventArgs ) {
		// Trigger event on action listened
		if ( ( $map = $this->_getActionToEventMap() )
			&& ! empty( $map[ $eventType ] )
		) {
			$event_args = $eventArgs + array( '_action' => $map[ $eventType ]['_action'] );
			unset( $map[ $eventType ]['_action'] );
			foreach ( array_keys( $map[ $eventType ] ) as $event_name ) {
				$this->_application->Notification_Services_triggerEvent( $event_name, $event_args );
			}
		}

		return parent::handleEvent( $eventType, $eventArgs );
	}

	public function onNotificationIEventsInstallSuccess( AbstractComponent $component ) {
		$this->_application->Notification_Services_createDefaultNotifications( $component->notificationGetEventNames() );
	}

	public function onNotificationIEventsUpgradeSuccess( AbstractComponent $component ) {
		$this->_application->Notification_Services_createDefaultNotifications( $component->notificationGetEventNames() );
	}

	public function onDirectoryAdminDirectoryAdded( Directory $directory, $values ) {
		$this->_application->Notification_Services_createDefaultNotifications( array_keys( $this->_application->Notification_Services( 'event' ) ), $directory );
	}

	public function systemGetToolNames() {
		return array( 'notification_send' );
	}

	public function systemGetTool( $name ) {
		return new SystemTool\SendNotificationsSystemTool( $this->_application, $name );
	}

	public function onDirectoryAdminSettingsFormFilter( &$form ) {
		// Moved from Directory to System component
		$this->onSystemAdminSettingsFormFilter( $form );
	}

	public function onSystemAdminSettingsFormFilter( &$form ) {
		$form['tabs'][ $this->_name ]   = array(
			'#title'      => __( 'Notifications', 'directories-pro' ),
			'#weight'     => 23,
			'#attributes' => array( 'data-no-submit' => 1 ),
		);
		$form['fields'][ $this->_name ] = array(
			'#tab'   => $this->_name,
			'#title' => __( 'Manage Notifications', 'directories-pro' ),
		) + $this->_application->Notification_SettingsForm( '/directories/settings/notifications' );
	}
}
