<?php

require_once 'library/DateTime.php';
require_once 'library/imap/ImapMailbox.php';
require_once 'library/Stopwatch.php';

class MessageInfo
{
    public $exists;
    public $recent;
    public $unread;

    public function __construct($exists, $recent, $unread)
    {
        $this->exists = $exists;
        $this->recent = $recent;
        $this->unread = $unread;
    }
}

class ImapFolderInfo
{
    public $name;
    public $globalName;
    public $localName;
    public $ref;
    public $delimiter;
    public $attributes;
    public $hasChildren;
    public $isMainFolder;
    public $messagecount;

    /*
    LATT_NOINFERIORS = 1
    LATT_NOSELECT = 2
    LATT_MARKED = 4
    LATT_UNMARKED = 8
    LATT_REFERRAL = 16
    LATT_HASCHILDREN = 32
    LATT_HASNOCHILDREN = 64
    */

    public function __construct($name, $ref, $delimiter, $attributes, $mailboxmsginfo)
    {
        $this->name = $name;
        $this->globalName = $name;
        $this->localName = $name;
        $this->ref = $ref;
        $this->delimiter = $delimiter;
        $this->attributes = $attributes;
        $this->messagecount = new  MessageInfo( $mailboxmsginfo->Nmsgs, $mailboxmsginfo->Recent, $mailboxmsginfo->Unread);

        // $this->hasChildren = ($attributes & LATT_NOINFERIORS) != 0;
        $this->hasChildren = ($attributes & LATT_HASCHILDREN) != 0;
        $this->isMainFolder = in_array( strtolower($name), array('inbox','drafts','sent','spam','trash'))? 1 : 0;
    }
}

class EmailAccountInfo
{
    public $host;
    public $username;
    public $password;
    public $protocol;
    public $mailbox;
    public $imapPath;

    public function __construct($host, $username, $password, $protocol, $mailbox)
    {
        $charterSSO = new CharterSSO();
        $password = $charterSSO->decodeString($password);

        $mailbox = imap_utf7_encode($mailbox);
        $this->hostname = $host;
        $this->username = $username;
        $this->password = $password;
        $this->protocol = $protocol;
        $this->mailbox  = $mailbox;
        $this->imapPath = '{' . $host . '/' . $protocol . '/ssl}' . $mailbox;
    }
}

class inbox
{
    private $_dbTables;
    private $_dbAdapter;
    private $_config;
    private $_maxRows;

    public function __construct()
    {
        $this->_dbTables = new dbTables();
        $this->_dbAdapter = Zend_Registry::get('dbAdapter');
        $this->_config = Zend_Registry::get('config');
        $this->_maxRows = 20;
    }

    protected function getEmailAccountInfo($accountId, $mailbox = 'INBOX')
    {
        if (DEBUG_FULL) debugLog(__FILE__, __METHOD__, __LINE__, "getEmailAccountInfo accountId: $accountId, mailbox: [$mailbox]");

        $select = $this->_dbAdapter
            ->select()
            ->from('ui_account')
            ->where('id = ' . $this->_dbAdapter->quote($accountId, 'INTEGER'));

        $accountRow = $this->_dbAdapter->fetchRow($select);

        return new EmailAccountInfo($accountRow['serverAddress'], $accountRow['accountEmail'],
                               $accountRow['password'], $accountRow['protocol'],
                               $mailbox);
    }

    public function testConnection($url, $protocol, $email, $password)
    {
        $emailAccountInfo = new EmailAccountInfo($url, $email, $password, $protocol, 'INBOX');
        $imapPath = $emailAccountInfo->imapPath;
        $username = $emailAccountInfo->username;
        $password = $emailAccountInfo->password;

        $mbox = imap_open($imapPath, $username, $password, OP_HALFOPEN);

        $retValue = $mbox ? true : false;

        if ($mbox)
        {
            imap_close($mbox);
        }

        return $retValue;
    }

    public function getMailHeaders($accountId, $acct, $folder)
    {
        /*
                $list = $this->_dbAdapter
                    ->select()
                    ->from('ui_emailheader')
                    ->where("accountId = $accountId")
                    ->limit($this->_maxRows)
                    ->query()
                    ->fetchAll();
        */

        if ($acct == -1)
        {
            $sql = 'SELECT h.*, a.accountName as acctName FROM ui_account a, ui_emailheader h where a.id = h.accountId and a.userId = :userId LIMIT 100';
            $stmt = $this->_dbAdapter->prepare($sql);
            $stmt->bindParam('userId', $accountId);
            $stmt->execute();
            $list = $stmt->fetchAll();
        }
        else
        {
            if ($folder && strcasecmp($folder, 'inbox') == 0)
            {
                $sql = 'SELECT h.*, a.accountName as acctName FROM ui_account a, ui_emailheader h where a.id = h.accountId and a.userId = :userId and h.accountId = :acct LIMIT 100';
                $stmt = $this->_dbAdapter->prepare($sql);
                $stmt->bindParam('userId', $accountId);
                $stmt->bindParam('acct', $acct);
                $stmt->execute();
                $list = $stmt->fetchAll();
            }
            else
            {
                try
                {
                    $emailAccountInfo = $this->getEmailAccountInfo($acct, $folder);
                    $imapPath = $emailAccountInfo->imapPath;
                    $username = $emailAccountInfo->username;
                    $password = $emailAccountInfo->password;
                    $attachmentDir = users::getTmpFolder();

                    $mailbox = new ImapMailbox($imapPath, $username, $password, $attachmentDir, 'utf-8');

                    $mailsIds = $mailbox->searchAndSortMails('ALL');

                    $list = array();

                    if ($mailsIds && !empty($mailsIds))
                    {
                        // for every email...
                        foreach($mailsIds as $mailId)
                        {
                            // get header information
                            $mailsInfo = $mailbox->getMailsInfo(array($mailId));
                            $email = $mailbox->getMail($mailId);

                            $row = array(
                                'accountId' =>  $acct,
                                'subject' =>    $mailsInfo[0]->subject,
                                'from' =>       $mailsInfo[0]->from,
                                'to' =>         $mailsInfo[0]->to,
                                'date' =>       $mailsInfo[0]->date,
                                'message_id' => $mailsInfo[0]->message_id,
                                'size' =>       $mailsInfo[0]->size,
                                'uid' =>        $mailsInfo[0]->uid,
                                'msgno' =>      $mailsInfo[0]->msgno,
                                'recent' =>     $mailsInfo[0]->recent,
                                'flagged' =>    $mailsInfo[0]->flagged,
                                'answered' =>   $mailsInfo[0]->answered,
                                'deleted' =>    $mailsInfo[0]->deleted,
                                'seen' =>       $mailsInfo[0]->seen,
                                'draft' =>      $mailsInfo[0]->draft,
                                'udate' =>      $mailsInfo[0]->udate,
                                'preview' =>    substr($email->textPlain, 0, 80),
                            );

                            array_push($list, $row);

                            // $this->insertHeader($accountId, $mailsInfo[0], substr($email->textPlain, 0, 80));

                        }
                    }
                }
                catch (Exception $e)
                {
                    $list = array();
                }
            }
        }

        return $list;
    }

    public function createFolder($emailAcct, $folderName)
    {
        $emailAccountInfo = $this->getEmailAccountInfo($emailAcct, '');

        $imapPath = $emailAccountInfo->imapPath;
        $username = $emailAccountInfo->username;
        $password = $emailAccountInfo->password;

        $mbox = imap_open($imapPath, $username, $password, OP_HALFOPEN);

        $newFolder = "{$imapPath}$folderName";

        $result = @imap_createmailbox($mbox, imap_utf7_encode($newFolder));
        imap_close($mbox);

        return $result;
    }

    public function deleteFolder($emailAcct, $folderName)
    {
        $emailAccountInfo = $this->getEmailAccountInfo($emailAcct, '');

        $imapPath = $emailAccountInfo->imapPath;
        $username = $emailAccountInfo->username;
        $password = $emailAccountInfo->password;

        $mbox = imap_open($imapPath, $username, $password, OP_HALFOPEN);

        $deleteFolder = "{$imapPath}$folderName";

        $result = @imap_deletemailbox($mbox, imap_utf7_encode($deleteFolder));
        imap_close($mbox);

        return $result;
    }

    public function getImapFolders($emailAcct)
    {
        $emailAccountInfo = $this->getEmailAccountInfo($emailAcct, '');

        $imapPath = $emailAccountInfo->imapPath;
        $username = $emailAccountInfo->username;
        $password = $emailAccountInfo->password;

        $mbox = imap_open($imapPath, $username, $password, OP_HALFOPEN);

        $list = imap_getmailboxes($mbox, $imapPath, "*");
        imap_close($mbox);

        $pos = strlen($imapPath);

        $imapFolders = array();

        if (is_array($list))
        {
            foreach ($list as $key => $val)
            {
                $name = substr(imap_utf7_decode($val->name), $pos);
                $ref = imap_utf7_decode($val->name);
                $delimiter = $val->delimiter;
                $attributes = $val->attributes;

                $mbox = imap_open($ref, $username, $password, OP_HALFOPEN);

                $mailboxmsginfo = imap_mailboxmsginfo($mbox);

                array_push($imapFolders, new ImapFolderInfo($name, $ref, $delimiter, $attributes, $mailboxmsginfo));
                imap_close($mbox);
            }
        }
        else
        {
            echo "imap_getmailboxes failed: " . imap_last_error() . "\n";
        }

        return $imapFolders;
    }

    public function getEmail($emailAcct, $emailFolder, $emailUid)
    {
        try
        {
            $emailAccountInfo = $this->getEmailAccountInfo($emailAcct, $emailFolder);

            $imapPath = $emailAccountInfo->imapPath;
            $username = $emailAccountInfo->username;
            $password = $emailAccountInfo->password;

            $attachmentDir = users::getTmpFolder();

            $mailbox = new ImapMailbox($imapPath, $username, $password, $attachmentDir, 'utf-8');

            $emailInfoArr = $mailbox->getMailsInfo(array($emailUid));
            $emailInfo = $emailInfoArr[0];
            $email = $mailbox->getMail($emailUid);

            require_once 'library/imap/htmlpurifier/library/HTMLPurifier.auto.php';

            $config = HTMLPurifier_Config::createDefault();
            $purifier = new HTMLPurifier($config);
            $email->textHtml = $purifier->purify($email->textHtml);

            $messageArray = array();
            $messageArray['headersOriginal'] = array();
            $messageArray['bodyPreparedText'] = $email->textPlain;
            $messageArray['bodyPreparedHtml'] = $email->textHtml;
            $messageArray['forcedInlines'] = array();
            $messageArray['forcedAttachments'] = array();
            $messageArray['cids'] = array();
            $messageArray['UID'] = $emailInfo->uid;

            $messageArray['headers'] = array(
                'return-path' => $email->fromAddress,
                'mime-version' => '1.0',
                'received' => 'todo: received',
                'date' => $email->date,
                'delivered-to' => $emailInfo->to,
                'message-id' => $emailInfo->message_id,
                'subject' => $emailInfo->subject,
                'from' => $emailInfo->from,
                'to' => $emailInfo->to,
                'content-type' => 'todo: content-type',
                'uniqueid' => $emailInfo->uid,
                'sizeraw' => 'todo: sizeraw',
                'size' => $emailInfo->size,
                'dateraw' => $emailInfo->date,
                'epoch' => $emailInfo->udate,
                'hasattachments' => count($email->getAttachments()) == 0 ? 'no' : 'yes',
                'reply-to' => $emailInfo->from,
                'fromOrigional' => $emailInfo->from,
                'priority' => 'normal',
                'name' => 'todo: name',
                'email' => $email->fromAddress,
                'UserPhoto' => 'todo: UserPhoto',
                'to_display' => array($email->fromName) // ']'"todo: to_display"')
            );

            return $messageArray;
        }
        catch (Exception $e)
        {
            $this->renderJson(array('error' => array('text' => $e->getMessage())));
        }
    }

    public function append($emailAcct, $message, $emailFolder = 'Drafts')
    {
        $emailAccountInfo = $this->getEmailAccountInfo($emailAcct, $emailFolder);
        $imapPath = $emailAccountInfo->imapPath;
        $username = $emailAccountInfo->username;
        $password = $emailAccountInfo->password;
        $attachmentDir = users::getTmpFolder();

        $mailbox = new ImapMailbox($imapPath, $username, $password, $attachmentDir, 'utf-8');
        return $mailbox->append($message);
    }

    public function updateFlag($emailAcct, $emailFolder, $emailUid, $flags, $mode)
    {
        // todo: make this code common
        $emailAccountInfo = $this->getEmailAccountInfo($emailAcct, $emailFolder);

        $imapPath = $emailAccountInfo->imapPath;
        $username = $emailAccountInfo->username;
        $password = $emailAccountInfo->password;

        $attachmentDir = users::getTmpFolder();

        $mailbox = new ImapMailbox($imapPath, $username, $password, $attachmentDir, 'utf-8');

        if(!is_array($emailUid))
        {
            $UidsParam = array($emailUid);
        }
        else
        {
            $UidsParam = $emailUid;
        }

        if ($mode == '-')
        {
            foreach($flags as $flag)
            {
                $mailbox->clearFlag($UidsParam, $flag);
                $this->setCacheFlag($emailAcct, $UidsParam, $flag, 0);
            }
        }
        else
        {
            foreach($flags as $flag)
            {
                $mailbox->setFlag($UidsParam, $flag);
                $this->setCacheFlag($emailAcct, $UidsParam, $flag, 1);
            }
        }
    }

    protected function setCacheFlag($emailAcct, $UidsParam, $flag, $value)
    {
        try
        {
            foreach ($UidsParam as $uid)
            {
                $flag = substr($flag, 1);
                $result = $this->_dbAdapter->update(
                    'ui_emailheader',
                    array(
                        $flag => $value
                    ),
                    "accountId = " . $this->_dbAdapter->quote($emailAcct, Zend_Db::INT_TYPE) . " AND " .
                    "uid = " . $this->_dbAdapter->quote($uid, Zend_Db::INT_TYPE)
                );
            }
        }
        catch (Exception $e)
        {
            //$this->renderJson(array('error' => array('text' => $e->getMessage())));
        }
    }

    public function moveMessage($emailAcct, $emailUid, $fromFolder, $emailFolder)
    {
        $emailAccountInfo = $this->getEmailAccountInfo($emailAcct, $fromFolder);

        $imapPath = $emailAccountInfo->imapPath;
        $username = $emailAccountInfo->username;
        $password = $emailAccountInfo->password;
        $attachmentDir = users::getTmpFolder();

        $mailbox = new ImapMailbox($imapPath, $username, $password, $attachmentDir, 'utf-8');
        $result = $mailbox->moveMail($emailUid, $emailFolder);
        return $result;
    }
}
