<?php

require_once 'modules/clients/models/UserGateway.php';
require_once 'newedge/classes/NE_MailGateway.php';
require_once 'modules/support/models/TicketGateway.php';
require_once 'modules/support/models/Ticket.php';
require_once 'modules/support/models/TicketLog.php';
require_once 'modules/support/models/Ticket_EventLog.php';
require_once 'modules/support/models/TicketNotifications.php';
require_once 'modules/support/models/TicketType.php';
require_once 'modules/support/models/EmailRoutingRuleGateway.php';

class Support_Event_PipedEmail extends NE_Action
{
    var $mailGateway;
    var $userGateway;
    var $ep;
    var $supportdir;
    var $ticketNotifications;

    function dispatch($args)
    {
        if (!$this->settings->get('Email Piping In Use')) {
            $sql = "UPDATE `setting` SET value=1 WHERE name='Email Piping In Use'";
            $result = $this->db->query($sql);
        }
        
        $ep = $args[0];
        $routingType = $args[1];

        $this->supportdir = dirname(__FILE__) . '/../../../uploads/support/';
        $this->userGateway = new UserGateway();
        $this->mailGateway = new NE_MailGateway();
        $this->ep =& $ep;
        $this->ep->parse();
        $this->logger->log(4, 'Processing incoming e-mail from '.$this->ep->getFrom().' with subject "'.$this->_getSubject().'"');

        $company = NE_Registry::getCompany();
        if ($this->configuration['framework']['appName'] == 'SupportExec'
                && preg_match('/support-([a-z0-9]{'.SupportExecCompany::HASHEDID_LENGTH.'})/', $this->ep->getDeliveredTo(), $matches)) {
            require_once 'modules/support/models/SupportExec/SupportExecCompanyGateway.php';
            $matchedCompany = SupportExecCompanyGateway::getByHashedId($matches[1]);
            if ($matchedCompany) {
                $this->logger->log(4, 'Processing rule for company ' . $matchedCompany->getSubdomain());
                NE_Registry::setCompany($matchedCompany);
                $company = $matchedCompany;
            }
        }

        $this->ticketNotifications = new TicketNotifications();

        $userId = $this->userGateway->getUserIdForEmail($this->ep->getFrom());
        $user = new User($userId);
        if (!$userId) {
            $user->setEmail($this->ep->getFrom());
            $user->setCompany(NE_Registry::getCompany());
            $user->setGroupId(ROLE_GUEST);
            $user->setDateCreated(date('Y-m-d'));
            $user->setLastName($this->ep->getFromLabel());
        }
        
        $emailRoutingGateway = new EmailRoutingRuleGateway();
        $emailRoutingIterator = $emailRoutingGateway->getApplicableRules($user, $this->ep->getTo(), $routingType);
        if (isset($args[2])) {
            $emailRoutingRule = $args[2];
            $ruleIsApplicable = false;
            while ($emailRoutingRule2 = $emailRoutingIterator->fetch()) {
                if ($emailRoutingRule->getId() == $emailRoutingRule2->getId()) {
                    $ruleIsApplicable = true;
                    break;
                }
            }
            if (!$ruleIsApplicable) {
                $this->logger->log(4, 'No matching routing rule found. Dropping E-mail');
                return;
            }
        } else {
            $emailRoutingRule = $emailRoutingIterator->fetch();
            if (!$emailRoutingRule) {
                $this->logger->log(4, 'No matching routing rule found. Dropping E-mail');
                return;
            }
        }

        $autoresponderTemplate = $emailRoutingRule->getAutoresponder();

        /**
        * Handle case where this is a response to an existing ticket
        */
        $regex = "/.*\[".$this->settings->get('Ticket Number Prefix').'-';
        if ($company->getId() > 0) {
            $regex .= sprintf('([0-9a-z]{%d})-([0-9a-z]{%d})', SupportExecCompany::HASHEDID_LENGTH, Ticket::HASHEDID_LENGTH);
        } else {
            $regex .= '(\d+)';
        }
        $regex .= '(-tech)?\]/';
        if (preg_match($regex, $this->_getSubject(), $matchid))
        {
            if ($company->getId() > 0) {
                if ($matchid[1] != $company->getHashedId()) {
                    throw new Exception('company ID in ticket subject doesn\'t match company ID in envelope');
                }
                $ticketGateway = new TicketGateway();
                $cTicket = $ticketGateway->getTicketByHashedId($matchid[2]);
            } else {
                $cTicket = new Ticket($matchid[1]);
            }

            if ($user->isAnonymous()
                && (!$this->settings->get('Allow Admins To Reply From Any E-mail Account') || !$this->_isStaffReply($company)))
            {
                return;
            }

            // avoid autoresponders keeping the ticket on an status by ignoring duplicated messages.
            if($cTicket->isDuplicatedReply($user->getId(), utf8_encode($this->_getMessage())))
            {
                return;
            }

            // autoresponders are not sent when replying to a ticket, unless the rule disallows ticket opening
            // and there's a reply coming in anyways (rare case).
            if ($emailRoutingRule->isOpenTicket()) {
                $this->_createNewTicketLog($user, $cTicket, $this->_getMessage());
            } else if ($autoresponderTemplate->getId()) {
                $this->_sendAutoresponder($autoresponderTemplate);
            }

            return;
        }

        /**
        * Handle case where this is a new ticket
        */
        if ($user->isAdmin()) {
            $this->logger->log(4, 'Incoming e-mail corresponds to an admin and it doesn\'t look like a reply to ticket: DISCARDED');
            return;
        }

        $this->logger->log(4, "Applying E-mail routing rule \"".$emailRoutingRule->getName()."\" to incoming e-mail");
        if ($filteringRule = $emailRoutingRule->filterOut($ep)) {
            $this->logger->log(4, "Discarding E-mail. It matches the filtering-out rule \"$filteringRule\"");
            return;
        }

        foreach ($emailRoutingRule->getCopyDestinataries() as $destinatary) {
            $this->logger->log(4, "Forwarding incoming E-mail to $destinatary");
            $this->ticketNotifications->forwardMessageToAlternateAddress(   $destinatary,
                                                                            $this->ep->getFrom(),
                                                                            $this->_getMessage(),
                                                                            $this->_getSubject(),
                                                                            $this->ep->getAttachments());
        }

        if ($emailRoutingRule->isOpenTicket()) {

            // If a ticket is to be opened for a guest customer, we need to add the customer to the db before
            if ($user->isGuest()) {
                $user->add();
            }

            $this->logger->log(4, "Opening new ticket");
            $cTicket = $this->_createNewTicket($user, $emailRoutingRule, $this->_getMessage());

            if ($autoresponderTemplate->getId()) {
                $this->ticketNotifications->sendAutoReply(  $user,
                                                            $cTicket,
                                                            $this->ep->getFrom(),
                                                            $this->_getMessage(),
                                                            array(  'subject'   => $autoresponderTemplate->getSubject(),
                                                                    'HTML'      => $autoresponderTemplate->getContentsHTML(),
                                                                    'plainText' => $autoresponderTemplate->getContents()
                                                            )
                );
            }

            return;
        }

        if ($autoresponderTemplate->getId()) {
            $this->_sendAutoresponder($autoresponderTemplate);
        }

        return;
    }

    function _sendAutoresponder($autoresponderTemplate)
    {
        $this->mailGateway->mailMessageEmail(   array(  'HTML'      => $this->ticketNotifications->replaceBasicTags($autoresponderTemplate->getContentsHTML()),
                                                        'plainText' => $this->ticketNotifications->replaceBasicTags($autoresponderTemplate->getContents())),
                                                $this->settings->get('Support E-mail'),
                                                $this->settings->get('Support E-mail'),
                                                $this->ep->getFrom(),
                                                '',
                                                $autoresponderTemplate->getSubject(),
                                                3,
                                                false,
                                                '',
                                                '',
                                                MAILGATEWAY_CONTENTTYPE_HTML
        );
    }

    function _processAttachments($userId, &$ccTicket, &$filename, &$fileattach, $message)
    {
        $validExtensions = explode(',',$this->settings->get('Allowed File Extensions'));

        if ($this->ep->getNumAttachments() > 0 && is_writable($this->supportdir) && $this->settings->get('Allow Customer File Uploads')) {
            for ($i = 0; $i < $this->ep->getNumAttachments(); $i++) {
                $attachment = $this->ep->getAttachment($i);
                $filekey = $ccTicket->generateFileKey();
                if (($pos = strrpos($attachment['name'], '.')) !== false) {
                    $len = strlen($attachment['name']) - ($pos+1);
                    $ext = mb_substr($attachment['name'], -$len);
                    if (in_array($ext, $validExtensions) || in_array('*',$validExtensions)) {
                        $fp = @fopen($this->supportdir.$filekey, "w");
                        fwrite($fp, $attachment['string']);
                        fclose($fp);
                        chmod($this->supportdir.$filekey, 0666);
                        $ccTicket->addFile($attachment['name'],$filekey,$userId);
                        $message = "** File Attached: ".$attachment['name']." **\n\n".$message;
                        $fileattach[] = $attachment['string'];
                        $filename[] = $attachment['name'];
                    }
                }
            }
        }

        return $message;
    }

    function _createNewTicket(&$user, &$emailRoutingRule, $message)
    {
        $tTimeStamp = date('Y-m-d H-i-s');
        $cTicket = new Ticket();
        $cTickets = new TicketGateway();
        if ($cTickets->GetTicketCount() == 0) {
             $id = $this->settings->get('Support Ticket Start Number');
             $cTicket->setForcedId($id);
        }

        $cTicket->setUser($user);
        $cTicket->setCompany(NE_Registry::getCompany());
        $cTicket->setSubject($this->_getSubject());
        $cTicket->SetDateSubmitted($tTimeStamp);
        $cTicket->SetLastLogDateTime($tTimeStamp);
        $cTicket->setMethod(2);
        $cTicket->SetPriority($emailRoutingRule->getTargetPriority());

        // if the email was sent to more than one recipient, we can tell which one to pick
        // so we leave this empty. CE will then fall back to the general support email when needed.
        if ($this->getNumEmails($this->ep->getTo()) == 1) {
            $cTicket->SetSupportEmail($this->ep->getTo());
        }

        $cTicket->SetStatus(TICKET_STATUS_WAITINGONTECH);

        $cTicket->SetMessageType($emailRoutingRule->getTargetTypeId());

        if ($emailRoutingRule->getTargetDept() == EMAILROUTINGRULE_DEFAULTASSIGNEE) {
            $ticketType = new TicketType($emailRoutingRule->getTargetTypeId());
            if ($targetDeptId = $ticketType->getTargetDept()) {
                require_once 'modules/support/models/Department.php';
                $dep = new Department($targetDeptId);
                $staff = null;
                if ($targetStaffId = $ticketType->getTargetStaff()) {
                    $staff = new User($targetStaffId);
                }
                $cTicket->assign($dep, $staff);
            }
        } elseif ($emailRoutingRule->getTargetDept() != 0) {
            require_once 'modules/support/models/Department.php';
            $dep = new Department($emailRoutingRule->getTargetDept());
            $staff = null;
            if ($targetStaffId = $emailRoutingRule->getTargetStaff()) {
                $staff = new User($targetStaffId);
            }
            $cTicket->assign($dep, $staff);
        }

        $cTicket->save();

        $supportLog = Ticket_EventLog::newInstance(    $user->getId(),
                                                       $cTicket->getId(),
                                                       TICKET_EVENTLOG_CREATED,
                                                       $user->getId()  // $this->user is an empty user object in this context
                                  );
        $this->logger->addEventLog($supportLog);  

        $filename = array();
        $fileattach = array();
        $message = $this->_processAttachments($user->getId(), $cTicket, $filename, $fileattach, $message);
        
        $cTicket->addInitialLog(utf8_encode($message),$tTimeStamp, $user, true);
        $attachments = false;
        if ($fileattach) {
            $attachments = array(
                'number'    => count($fileattach),
                'name'      => $filename,
                'string'    => $fileattach,
            );
        }
        $cTicket->notifyAssignation($user, $attachments);

        return $cTicket;
    }

    function _createNewTicketLog(&$user, &$cTicket, $message)
    {
        $cTicket->SetStatus($user->isAdmin()? TICKET_STATUS_WAITINGONCUSTOMER : TICKET_STATUS_WAITINGONTECH);
        $timeStamp = date('Y-m-d H-i-s');
        $cTicket->SetLastLogDateTime($timeStamp);
        $cTicket->save();
        $filename = array();
        $fileattach = array();
        $message = $this->_processAttachments($user->getId(), $cTicket, $filename, $fileattach, $message);
        $cTicketLog = new TicketLog();
        $cTicketLog->setUserId($user->getId());
        $cTicketLog->setTroubleTicketID($cTicket->getId());
        $cTicketLog->setMessage(utf8_encode($this->_getMessage()));
        $cTicketLog->setMyDateTime($timeStamp);
        $cTicketLog->setLogAction(0);
        $cTicketLog->setIsExternalEmail(1);
        $cTicketLog->save();

        if ($user->getGroup()->isCustomersMainGroup() || $user->isGuest()) {
            if ($cTicket->GetAssignedToID()!=0) {
                $this->ticketNotifications->notifyAssigneeForTicketReply($user, $cTicket, $message, $fileattach, $filename);
            }
        } else {
            $tClient = new User($cTicket->GetUserID());
            $this->ticketNotifications->notifyCustomerForTicketReply($tClient, $cTicket, $message, $fileattach, $filename);
        }
    }

    function _isStaffReply($company)
    {
        $regex = "/.*\[".$this->settings->get('Ticket Number Prefix').'-';
        if ($company->getId() > 0) {
            $regex .= sprintf('([0-9a-z]{%d})-([0-9a-z]{%d})', SupportExecCompany::HASHEDID_LENGTH, Ticket::HASHEDID_LENGTH);
        } else {
            $regex .= '(\d+)';
        }
        $regex .= '-tech\]/';
        return preg_match($regex, $this->ep->getSubject());
    }
    
    function _getMessage()
    {
        return $this->ep->getMessage();
    }
    
    function _getSubject()
    {
        return $this->ep->getSubject();
    }

    private function getNumEmails($to)
    {
        return count(explode(',', $to));
    }
}

?>
