<?php

namespace EesyPHP;

use PEAR;
use Mail;
use Mail_mime;

use finfo;

class Email {

  /**
   * Default sender
   * @var string|null;
   */
  protected static $sender = null;

  /**
   * Sending method :
   *  - mail : use PHP mail function
   *  - sendmail : use sendmail system command
   *  - smtp : use an SMTP server (PHP PEAR Net_SMTP required)
   * @var string
   */
  protected static $send_method = 'mail';

  /**
   * Sending parameters
   * @see http://pear.php.net/manual/en/package.mail.mail.factory.php
   * @var array|null
   */
  protected static $send_params = null;

  /**
   * Catch all sent email recipient
   * @var string|array<string>|null
   */
  protected static $catch_all = null;

  /**
   * Default headers to add on all sent emails
   * @var array<string>
   */
  protected static $headers = array();

  /**
   * PHP PEAR Mail lib path
   * @var string
   */
  protected static $php_mail_path = 'Mail.php';

  /**
   * PHP PEAR Mail lib path
   * @var string
   */
  protected static $php_mail_mime_path = 'Mail/mime.php';


  /**
   * Initialization
   * @param string|null $php_mail_path PHP PEAR Mail lib path (optional, default: from
   *                    email.php_mail_path config key if set, 'Mail.php' otherwise)
   * @param string|null $php_mail_mime_path PHP PEAR Mail lib path (optional, default: from
   *                    email.php_mail_mime_path config key if set, 'Mail/mime.php' otherwise)
   * @return void
   */
  public static function init($sender=null, $send_method=null, $send_params=null, $catch_all=null,
                              $headers=null, $php_mail_path=null, $php_mail_mime_path=null) {
    if (is_null($sender))
      $sender = App::get('email.sender', null, 'string');
    if ($sender) self :: $sender = $sender;

    if (is_null($send_method))
      $send_method = App::get('email.send_method', null, 'string');
    if ($send_method) self :: $send_method = $send_method;

    if (is_null($send_params))
      $send_params = App::get('email.send_params', null, 'array');
    if ($send_params) self :: $send_params = $send_params;

    if (is_null($catch_all))
      $catch_all = App::get('email.catch_all');
    if ($catch_all) self :: $catch_all = $catch_all;

    if (is_null($headers))
      $headers = App::get('email.headers', null, 'array');
    if ($headers) self :: $headers = $headers;

    if (is_null($php_mail_path))
      $php_mail_path = App::get('email.php_mail_path', null, 'string');
    if ($php_mail_path) self :: $php_mail_path = $php_mail_path;

    if (is_null($php_mail_mime_path))
      $php_mail_mime_path = App::get('email.php_mail_mime_path', null, 'string');
    if ($php_mail_mime_path) self :: $php_mail_mime_path = $php_mail_mime_path;
  }


  /**
   * Send an email
   *
   * @param string|null $from Email sender
   * @param string|array<string> $to Email recipient(s)
   * @param string $subject Email subject
   * @param string $msg Email body
   * @param boolean $html Set to true to send an HTML email (default: false)
   * @param array<string,string>|null $attachments Email attachments as an array with
   *                                  filepath as key and filename as value
   * @param array<string,string>|null $headers Email headers
   * @param string|null $encoding Email encoding (default: utf8)
   * @param string|null $eol End of line string (default : \n)
   *
   * @return boolean true If mail was sent, false otherwise
   */
  public static function send($from, $to, $subject, $msg, $html=false, $attachments=null,
                                   $headers=null, $encoding=null, $eol=null) {
    if (!class_exists('Mail'))
      require_once(self :: $php_mail_path);
    if (!class_exists('Mail_mime'))
      require_once(self :: $php_mail_mime_path);

    $mail_obj = Mail::factory(self :: $send_method, self :: $send_params);

    if (!$headers) $headers = array();
    $headers = array_merge($headers, self :: $headers);

    Log :: trace(
      'Mail catch all: %s',
        self :: $catch_all?
        vardump(self :: $catch_all):'not set'
    );
    if (self :: $catch_all) {
      Log :: debug(
        'Mail catch to %s',
        is_array(self :: $catch_all)?implode(',', self :: $catch_all):self :: $catch_all
      );
      $msg .= sprintf(
        (
          $html?
          I18n::_("</hr><p><small>Mail initialy intended for %s.</small></p>"):
          I18n::_("\n\n\nMail initialy intended for %s.")
        ),
        (is_array($to)?implode(',', $to):$to));
      $headers["X-Orig-To"] = $to;
      $to = (
        is_array(self :: $catch_all)?
        implode(',', self :: $catch_all):self :: $catch_all
      );
    }

    if ($subject) {
      $headers["Subject"] = $subject;
    }

    if (isset($headers['From'])) {
      if (!$from)
        $from = $headers['From'];
      unset($headers['From']);
    }
    elseif (!$from) {
      $from = self :: $sender;
    }

    $headers["To"] = $to;

    $to = array (
      'To' => $to
    );

    foreach(array_keys($headers) as $header) {
      if(in_array(strtoupper($header), array('BCC', 'CC'))) {
        if (self :: $catch_all) {
          Log :: debug("Mail catched: remove $header header");
          $msg .= sprintf(
            (
              $html?
              I18n::_("<p><small>%s: %s</small></p>"):
              I18n::_("\n%s: %s")
            ),
            strtoupper($header),
            (is_array($headers[$header])?implode(',', $headers[$header]):$headers[$header]));
          unset($headers[$header]);
          continue;
        }
        $to[strtoupper($header)] = $headers[$header];
      }
    }

    if (!$encoding) $encoding = "utf8";
    $mime = new Mail_mime(
      array(
        'eol' => ($eol?$eol:"\n"),
        ($html?'html_charset':'text_charset') => $encoding,
        'head_charset' => $encoding,
      )
    );

    if ($from)
        $mime->setFrom($from);

    if ($subject)
      $mime->setSubject($subject);

    if ($html)
      $mime->setHTMLBody($msg);
    else
      $mime->setTXTBody($msg);

    if (is_array($attachments) && !empty($attachments)) {
      $finfo = new finfo(FILEINFO_MIME_TYPE);
      foreach ($attachments as $file => $filename) {
        $mime->addAttachment($file, $finfo->file($file), $filename);
      }
    }

    $body = $mime->get();
    $headers = $mime->headers($headers);

    $ret = $mail_obj -> send($to, $headers, $body);

    if (PEAR::isError($ret)) {
      $msg = "Error sending email: ".$ret -> getMessage();
      Log :: error($msg);
      return false;
    }
    return true;
  }
}

# vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab
