<?php

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

class AccountInfo
{
    public $host;
    public $username;
    public $password;
    public $protocol;
    public $imapPath;

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

        $this->hostname = $host;
        $this->username = $username;
        $this->password = $password;
        $this->protocol = $protocol;
        $this->imapPath = '{' . $host . '/' . $protocol . '/ssl}INBOX';
    }
}

class Inbox_AccountController extends Inbox_Controller_Base
{
    public function init()
    {
        parent::init();

        $this->_table = 'ui_account';

        $this->_columns = array(
            'userId'        => '',
            'serverAddress' => '',
            'replyAddress'  => '',
            'accountEmail'  => '',
            'accountName'   => '',
            'signature'     => '',
            'realName'      => '',
            'protocol'      => 'IMAP',
            'password'      => '',
            'nickname'      => '',
            'capacity'      => '1',
            'primary'       => '0',
            'quota'         => '0',
            'port'          => '993',
            'unreadMail'    => '0'
        );
    }

    public function indexAction()
    {
        // todo: add authentication
        // if (!isAuthenticated()) return;

        try
        {
            $userId = $this->_getParam('userid');
            $account = $this->_getParam('account');

            if ($account != null)
            {
                $sql = 'SELECT a.* FROM ui_account a join Users u on (a.userId=u.id) WHERE u.Account = :account';
                $stmt = $this->_dbAdapter->prepare($sql);
                $stmt->bindParam('account', $account);
                $stmt->execute();
                $result = $stmt->fetchAll();

                $result['password'] = '';
                $this->renderJson($result);
            }
            else if ($userId != null)
            {
                $sql = 'SELECT * from ui_account where userId=:userId';
                $stmt = $this->_dbAdapter->prepare($sql);
                $stmt->bindParam('userId', $userId);
                $stmt->execute();
                $result = $stmt->fetchAll();

                $result['password'] = '';
                $this->renderJson($result);
            }
            else
            {
                $this->methodNotAllowed();

//                $sql = 'SELECT * from ui_account';
//                $accounts = $this->_dbAdapter->fetchAll($sql);
//                $this->renderJson($accounts);
            }
        }
        catch (Exception $e)
        {
            $this->renderJson(array('error' => array('text' => $e->getMessage())));
        }
    }

    public function getAction()
    {
        $id = $this->_getParam('id', 0);
        $sql = 'SELECT * from ui_account where id=:id';

        try
        {
            $stmt = $this->_dbAdapter->prepare($sql);
            $stmt->bindParam('id', $id);
            $stmt->execute();
            $result = $stmt->fetchObject();

            if ($result)
            {
                $result['password'] = '';
                $this->renderJson($result);
            }
            else
            {
                $this->renderJson($this->_noResults);
            }
        }
        catch (Exception $e)
        {
            $this->renderJson(array('error' => array('text' => $e->getMessage())));
        }
    }

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

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

        if (DEBUG_FULL) debugLog(__FILE__, __METHOD__, __LINE__, "Getting Account: " . $accountRow['accountName']);

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

    protected function deleteUserHeaders($accountId)
    {
        try
        {
            $result = $this->_dbAdapter->delete('ui_emailheader', 'accountId = ' . $this->_dbAdapter->quote($accountId, 'INTEGER' ));
            return true;
        }
        catch (Exception $e)
        {
            return false;
        }
    }

    protected function populateHeaderParameters($accountId, $emailHeader)
    {
        $this->accountId =  $accountId;
        $this->subject =    $emailHeader->subject;
        $this->from =       $emailHeader->from;
        $this->to =         $emailHeader->to;
        $this->date =       $emailHeader->date;
        $this->message_id = $emailHeader->message_id;
        $this->size =       $emailHeader->size;
        $this->uid =        $emailHeader->uid;
        $this->msgno =      $emailHeader->msgno;
        $this->recent =     $emailHeader->recent;
        $this->flagged =    $emailHeader->flagged;
        $this->answered =   $emailHeader->answered;
        $this->deleted =    $emailHeader->deleted;
        $this->seen =       $emailHeader->seen;
        $this->draft =      $emailHeader->draft;
        $this->udate =      $emailHeader->udate;
    }

    protected function insertHeader($accountId, $emailHeader, $preview)
    {
        try
        {
            $sql = <<<EOD
INSERT INTO ui_emailheader (
`accountId`,
`subject`,
`from`,
`to`,
`date`,
`message_id`,
`size`,
`uid`,
`msgno`,
`recent`,
`flagged`,
`answered`,
`deleted`,
`seen`,
`draft`,
`udate`,
`preview`
) VALUES (
:accountId,
:subject,
:from,
:to,
:date,
:message_id,
:size,
:uid,
:msgno,
:recent,
:flagged,
:answered,
:deleted,
:seen,
:draft,
:udate,
:preview
);
EOD;

            $this->populateHeaderParameters($accountId, $emailHeader);

            $stmt = $this->_dbAdapter->prepare($sql);

            $stmt->bindParam('accountId',  $this->accountId);
            $stmt->bindParam('subject',    $this->subject);
            $stmt->bindParam('from',       $this->from);
            $stmt->bindParam('to',         $this->to);
            $stmt->bindParam('date',       $this->date);
            $stmt->bindParam('message_id', $this->message_id);
            $stmt->bindParam('size',       $this->size);
            $stmt->bindParam('uid',        $this->uid);
            $stmt->bindParam('msgno',      $this->msgno);
            $stmt->bindParam('recent',     $this->recent);
            $stmt->bindParam('flagged',    $this->flagged);
            $stmt->bindParam('answered',   $this->answered);
            $stmt->bindParam('deleted',    $this->deleted);
            $stmt->bindParam('seen',       $this->seen);
            $stmt->bindParam('draft',      $this->draft);
            $stmt->bindParam('udate',      $this->udate);
            $stmt->bindParam('preview',    $preview);

            $success = $stmt->execute();

            $id = $this->_dbAdapter->lastInsertId();
        }
        catch (Exception $e)
        {
            $this->renderJson(array('error' => array('text' => $e->getMessage())));
        }
    }

    protected function loadAccountHeaders($accountId)
    {
        try
        {
            if (DEBUG_FULL) debugLog(__FILE__, __METHOD__, __LINE__, time() . ' Start loadAccount header for account: ' . $accountId);

            $stopwatch = new Stopwatch();

            $accountInfo = $this->getAccountInfo($accountId);

            $this->deleteUserHeaders($accountId);

            if (DEBUG_FULL) debugLog(__FILE__, __METHOD__, __LINE__, time() . ' Remove old account headers: ' . $stopwatch->clock());

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

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

            if (DEBUG_FULL) debugLog(__FILE__, __METHOD__, __LINE__, time() . ' Connect to mailbox: ' . $stopwatch->clock());

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

            if (DEBUG_FULL) debugLog(__FILE__, __METHOD__, __LINE__, time() . ' Search for headers: ' . $stopwatch->clock());

            if(!$mailsIds)
            {
                return true;
            }

            if (!empty($mailsIds))
            {
                // for every email...
                foreach($mailsIds as $mailId)
                {
                    // get header information
                    $mailsInfo = $mailbox->getMailsInfo(array($mailId));
                    $email = $mailbox->getMail($mailId);
                    $this->insertHeader($accountId, $mailsInfo[0], substr($email->textPlain, 0, 80));

                    if (DEBUG_FULL) debugLog(__FILE__, __METHOD__, __LINE__, time() . ' Get header: ' . $stopwatch->clock());
               }
            }

            if (DEBUG_FULL) debugLog(__FILE__, __METHOD__, __LINE__, time() . ' Done: ' . $stopwatch->elapsed());

            return true;
        }
        catch (Exception $e)
        {
            if (DEBUG_FULL) debugLog(__FILE__, __METHOD__, __LINE__, time() . ' Error: ' . $e);
            return false;
        }
    }

    public function postAction()
    {
        try
        {
            $this->populateParameters();

            $key = 'userId';
            $accountId = users::getAccountId();

            $charterSSO = new CharterSSO();
            $password = $charterSSO->encodeString($this->_restParameters['password']);
            $this->_restParameters['password'] = $password;
            $this->_columns['password'] = $password;

            $this->_restParameters[$key] = $accountId;
            $this->_columns[$key] = $accountId;

            $sql = $this->getInsertStatement();

            $stmt = $this->_dbAdapter->prepare($sql);

            foreach($this->_columns as $key => $val)
            {
                $stmt->bindParam($key, $this->_columns[$key]);
            }

            $success = $stmt->execute();
            $id = $this->_dbAdapter->lastInsertId();

            // Load header cache
            $this->loadAccountHeaders($id);

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

            $this->renderJson($this->_dbAdapter->fetchRow($select));
        }
        catch (Exception $e)
        {
            $this->renderJson(array('error' => array('text' => $e->getMessage())));
        }
    }

    public function putAction()
    {
        $id = $this->_getParam('id', 0);

        try
        {
            $this->populateParameters();
            $sql = $this->getUpdateStatement();

            $stmt = $this->_dbAdapter->prepare($sql);
            $stmt->bindParam('id', $id);

            foreach ($this->_restParameters as $key => $val)
            {
                $stmt->bindParam($key, $this->_restParameters[$key]);
            }

            $success = $stmt->execute();

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

            $results = $this->_dbAdapter->fetchRow($select);
            $results['password'] = '';
            $this->renderJson($results);
        }
        catch (Exception $e)
        {
            $this->renderJson(array(
                'error' => array('text' => $e->getMessage(),
                'sql'   => $sql
                )
            ));
        }
    }

    public function deleteAction()
    {
        $id = $this->_getParam('id', 0);

        try
        {
            $sql = 'DELETE FROM ui_account WHERE id=:id';

            $stmt = $this->_dbAdapter->prepare($sql);
            $stmt->bindParam('id', $id);
            $success = $stmt->execute();
            $this->renderJson($this->_statusOK);
        }
        catch (Exception $e)
        {
            $this->renderJson(array('error' => array('text' => $e->getMessage())));
        }
    }
}
