<?php

  /**
   * Base notifier helper implementation
   * 
   * @package angie.frameworks.email
   * @subpackage 
   */
  class INotifierImplementation {
    
    /**
     * Parent object instance
     * 
     * @var INotifier
     */
    protected $object;
    
    /**
     * Construct notify helper implementation
     * 
     * @param INotifier $object
     */
    function __construct(INotifier $object) {
      $this->object = $object;
    } // __construct
    
    /**
     * Notify one or more users about an even
     * 
     * @param mixed $users
     * @param INotifierContext $context
     * @param mixed $event
     * @param array $event_params
     * @param array $additional
     */
    function notifyUsers($users, INotifierContext $context, $event, $event_params = null, $additional = null) {
      $to_notify = array();
      if($users instanceof IUser) {
        $to_notify = array($users);
      } elseif(is_foreachable($users)) {
        $to_notify = $users;
      } // if

      // check for additional users
      if (isset($additional['include']) && $additional['include']) {
        if($additional['include'] instanceof IUser) {
          $to_notify[] = $additional['include'];
        } elseif (is_foreachable($additional['include'])) {
          foreach ($additional['include'] as $include) {
            if($include instanceof IUser || (is_string($include) && is_valid_email($include))) {
              $to_notify[] = $include;
            } // if
          } // foreach
        } elseif(is_string($additional['include']) && is_valid_email($additional['include'])) {
          $to_notify[] = $additional['include'];
        } // if
      } // if

      if(is_foreachable($to_notify)) {
        $exclude_emails = array();
        if (!$this->object instanceof AnonymousUser) {
          $exclude_emails[] = $this->object->getEmail();
        } // if

        // check for exclusions list
        if(isset($additional['exclude']) && $additional['exclude']) {
          if($additional['exclude'] instanceof IUser) {
            $exclude_emails[] = $additional['exclude']->getEmail();
          } elseif(is_array($additional['exclude'])) {
            foreach($additional['exclude'] as $v) {
              if($v instanceof IUser) {
                $exclude_emails[] = $v->getEmail();
              } elseif(is_string($v) && is_valid_email($v)) {
                $exclude_emails[] = $v;
              } // if
            } // foreach
          } elseif(is_string($additional['exclude']) && is_valid_email($additional['exclude'])) {
            $exclude_emails[] = $additional['exclude'];
          } // if
        } // if
        
        if(is_string($event)) {
          $event = new NotifierEvent($event);
        } // if
        
        $smarty =& SmartyForAngie::getInstance();
        
        $template = $smarty->createTemplate($event->getTemplatePath());
        $template->assign(array(
          'sender' => $this->object, 
          'context' => $context,
          'style' => array(
            'link' => Theme::getProperty('notifications.link'),
          ),
        ));
        
        if($event_params) {
          $template->assign($event_params);
        } // if

        $default_context_view_url = $context instanceof ApplicationObject && $context instanceof IRoutingContext ? $context->getViewUrl() : null;

        $subscription_codes = array_var($additional, 'subscription_codes', null);
        $sent_to = array();
        foreach($to_notify as $user) {
          if ($user && !($user instanceof IUser)) {
            if (is_valid_email($user)) {
              $user = new AnonymousUser($user, $user);
            } else {
              continue;
            } // if
          } // if

          if(in_array($user->getEmail(), $exclude_emails) || in_array($user->getEmail(), $sent_to)) {
            continue; // Ignore people from exclude list or if 'include' matches someone from default list
          } // if
          
          if($context instanceof IVisibility && $user instanceof User && $user->getMinVisibility() > $context->getVisibility()) {
            continue; // Ignore people who can't see private objects
          } // if

          // Get context view URL for a given user
          $context_view_url = $default_context_view_url;
          EventsManager::trigger('on_notification_context_view_url', array(&$user, &$context, &$context_view_url));
          
          $template->assign(array(
            'recipient' => $user, 
            'language' => $user->getLanguage(),
            'context_view_url' => $context_view_url,
          ));
          
          $content = $template->fetch();
          
          if(strpos($content, '================================================================================')) {
            list($subject, $body) = explode('================================================================================', $content);
            
            $subject = undo_htmlspecialchars(trim($subject)); // Subject does not have to be escaped
            $body = trim($body);
          } else {
            $subject = lang('[No Subject]', null, true, $user->getLanguage());
            $body = trim($content);
          } // if

          $sent_to[] = $user->getEmail();
          
          ApplicationMailer::send($user, $subject, $body, array(
            'sender' => $this->object, 
            'context' => $context,
            'attachments' => array_var($additional, 'attachments', null),
            'subscription_code' => array_var($subscription_codes, $user->getEmail())
          ), array_var($additional, 'method', $user->getMailingMethod()));
        } // foreach
      } // if
    } // notifyUsers
    
    /**
     * Notify subscribers
     * 
     * @param INotifierContext $context
     * @param string $event
     * @param array $event_params
     * @param array $additional
     */
    function notifySubscribers(INotifierContext $context, $event, $event_params = null, $additional = null) {
      if($context instanceof ISubscriptions) {
        $additional = (array) $additional;
        $additional['subscription_codes'] = $context->subscriptions()->getSubscriptionCodesByEmail();
        $this->notifyUsers($context->subscriptions()->get(), $context, $event, $event_params, $additional);
      } else {
        throw new InvalidInstanceError('context', $context, 'ISubscriptions');
      } // if
    } // notifySubscribers
    
    /**
     * Notify assignees
     * 
     * @param INotifierContext $context
     * @param string $event
     * @param array $event_params
     * @param array $additional
     */
    function notifyAssignees(INotifierContext $context, $event, $event_params = null, $additional = null) {
      if($context instanceof IAssignees) {
        $this->notifyUsers($context->assignees()->getAllAssignees(), $context, $event, $event_params, $additional);
      } else {
        throw new InvalidInstanceError('context', $context, 'IAssignees');
      } // if
    } // notifyAssignees
    
    /**
     * Notify administrators
     * 
     * @param INotifierContext $context
     * @param NotifierEvent $event
     * @param mixed $event_params
     * @param mixed $additional
     */
    function notifyAdministrators(INotifierContext $context, $event, $event_params = null, $additional = null) {
      $this->notifyUsers(Users::findAdministrators(), $context, $event, $event_params, $additional);
    } // notifyAdministrators
    
  }