<?php
/**
 * A class for composing emails.
 *
 * This class is a thin wrapper over swift message.
 */
class email
{
    /**
     * @var Swift_Message The swift message.
     */
    protected $message;
    
    /**
     * @var email_transport The email transport.
     */
    protected $transport;

    ////////////////////////////////////////////////////////////////////////////
    // Construct and destruct functions.

    /**
     * @param email_transport (optional) $transport The email transport.
     */
    public function __construct(email_transport $transport = null)
    {
        Swift::init();
        $this->message = new Swift_Message();
        $this->transport = $transport;
    }

    ////////////////////////////////////////////////////////////////////////////
    // Overload functions.

    /**
     * Gets the wrapped swift message object.
     *
     * @return Swift_Message The object.
     */
    public function __toswift()
    {
        return $this->message;
    }

    ////////////////////////////////////////////////////////////////////////////
    // Interface functions.

    /**
     * Sends an email.
     *
     * @param array (optional) $failed The failed recipients.
     * @return email A fluent interface.
     */
    public function send(&$failed = array())
    {
        if (!$this->transport)
        {
            $this->transport = new email_transport_php;
        }
        
        $this->transport->send($this, $failed);
        return $this;
    }

    /**
     * Sets one or more recipients.
     *
     * @param string $address The email address.
     * @param string (optional) $name The owner.
     * -
     * @param array $address The email addresses.
     * @return email A fluent interface.
     */
    public function to($address, $name = null)
    {
        $this->message->addTo($address, $name);
        return $this;
    }

    /**
     * Sets one or more recipients (cc).
     *
     * @param string $address The email address.
     * @param string (optional) $name The owner.
     * -
     * @param array $address The email addresses.
     * @return email A fluent interface.
     */
    public function cc($address, $name = null)
    {
        $this->message->addCC($address, $name);
        return $this;
    }

    /**
     * Sets one or more recipients (bcc).
     *
     * @param string $address The email address.
     * @param string (optional) $name The owner.
     * -
     * @param array $address The email addresses.
     * @return email A fluent interface.
     */
    public function bcc($address, $name = null)
    {
        $this->message->addBCC($address, $name);
        return $this;
    }

    /**
     * Sets an author address (from).
     *
     * @param string $address The email address.
     * @param string (optional) $name The owner.
     * @return email A fluent interface.
     */
    public function from($address, $name = null)
    {
        $this->message->setFrom($address, $name);
        return $this;
    }
    
    /**
     * Sets a reply address (reply-to).
     *
     * @param string $address The email address.
     * @param string (optional) $name The owner.
     * @return email A fluent interface.
     */
    public function reply_to($address, $name = null)
    {
        $this->message->setReplyTo($address, $name);
        return $this;
    }
    
    /**
     * Sets a sender address (sender).
     *
     * @param string $address The email address.
     * @return email A fluent interface.
     */
    public function sender($address)
    {
        $this->message->setSender($address);
        return $this;
    }
    
    /**
     * Sets a return path address (return-path).
     *
     * @param string $address The email address.
     * @return email A fluent interface.
     */
    public function return_path($address)
    {
        $this->message->setReturnPath($address);
        return $this;
    }
    
    /**
     * Sets a receipt address (receipt-to).
     *
     * @param string $address The email address.
     * @return email A fluent interface.
     */
    public function receipt_to($address)
    {
        $this->message->setReadReceiptTo($address);
        return $this;
    }
    
    /**
     * Sets a subject.
     *
     * @param string $subject The subject.
     * @return email A fluent interface.
     */
    public function subject($subject)
    {
        $this->message->setSubject($subject);
        return $this;
    }
    
    /**
     * Sets a body.
     *
     * @param string $content The content.
     * @param string (optional) $type The type.
     * @param string (optional) $charset The charset.
     * @return email A fluent interface.
     */
    public function body($content, $type = 'text/html', $charset = null)
    {
        $this->message->setBody($content, $type, $charset);
        return $this;
    }
    
    /**
     * Sets an alternative body.
     *
     * @param string $content The content.
     * @param string (optional) $type The type.
     * @param string (optional) $charset The charset.
     * @return email A fluent interface.
     */
    public function alternative($content, $type = 'text/plain', $charset = null)
    {
        $this->message->addPart($content, $type, $charset);
        return $this;
    }

    /**
     * Sets an attached file from dynamic content.
     *
     * @param string $data The data.
     * @param string $name The filename.
     * @param string $type The content type.
     * @param string (optional) $disposition The content disposition.
     * @return email A fluent interface.
     */
    public function attach($data, $name, $type, $disposition = null)
    {
        $attachment = new Swift_Attachment($data);
        $this->attachment($attachment, 'attach', $name, $type, $disposition);
        return $this;
    }
    
    /**
     * Sets an attached file.
     *
     * @param string $file The file.
     * @param string (optional) $name The filename.
     * @param string (optional) $type The content type.
     * @param string (optional) $disposition The disposition.
     * @return email A fluent interface.
     */
    public function attach_file($file, $name = null, $type = null, $disposition = null)
    {
        $attachment = Swift_Attachment::fromPath($file);
        $this->attachment($attachment, 'attach', $name, $type, $disposition);
        return $this;
    }
    
    /**
     * Sets an embedded file from dynamic content.
     *
     * @param string $data The data.
     * @param string $name The filename.
     * @param string $type The content type.
     * @param string (optional) $disposition The content disposition.
     * @return string The file cid.
     */
    public function embed($data, $name, $type, $disposition = null)
    {
        $attachment = new Swift_EmbeddedFile($data);
        return $this->attachment($attachment, 'embed', $name, $type, $disposition);
    }
    
    /**
     * Sets an embedded file.
     *
     * @param string $file The file.
     * @param string (optional) $name The filename.
     * @param string (optional) $type The content type.
     * @param string (optional) $disposition The disposition.
     * @return string The file cid.
     */
    public function embed_file($file, $name = null, $type = null, $disposition = null)
    {
        $attachment = Swift_EmbeddedFile::fromPath($file);
        return $this->attachment($attachment, 'embed', $name, $type, $disposition);
    }

    /**
     * Sets a priority (priority).
     *
     * @param integer $priority The priority.
     * @return email A fluent interface.
     */
    public function priority($priority)
    {
        $this->message->setPriority($priority);
        return $this;
    }
    
    /**
     * Sets a charset (charset).
     *
     * @param string $charset The charset.
     * @return email A fluent interface.
     */
    public function charset($charset)
    {
        $this->message->setCharset($charset);
        return $this;
    }
    
    ////////////////////////////////////////////////////////////////////////////
    // Internal functions.
    
    /**
     * Sets an attachment.
     *
     * @param Swift_Mime_MimeEntity $attachment The attachment object.
     * @param string $function The way to attach it.
     * @param string (optional) $name The filename.
     * @param string (optional) $type The content type.
     * @param string (optional) $disposition The disposition.
     * @return email A fluent interface.
     */
    protected function attachment($attachment, $function, $name = null, $type = null, $disposition = null)
    {
        if ($name !== null)
        {
            $attachment->setFilename($name);
        }
        
        if ($type !== null)
        {
            $attachment->setContentType($type);
        }
        
        if ($disposition !== null)
        {
            $attachment->setDisposition($disposition);
        }
        
        return $this->message->$function($attachment);
    }
}
