diff --git a/include/class.ticket.php b/include/class.ticket.php
index 6518d12eae5722401bb1f96a4932ed00e14473c0..2535f16be9f8dfa81297559ecc4422b43b8e6c12 100644
--- a/include/class.ticket.php
+++ b/include/class.ticket.php
@@ -43,6 +43,7 @@ class Ticket {
 
     var $lastMsgId;
 
+    var $status;
     var $dept;  //Dept obj
     var $sla;   // SLA obj
     var $staff; //Staff obj
@@ -91,6 +92,7 @@ class Ticket {
         $this->loadDynamicData();
 
         //Reset the sub classes (initiated ondemand)...good for reloads.
+        $this->status= null;
         $this->staff = null;
         $this->client = null;
         $this->team  = null;
@@ -118,16 +120,32 @@ class Ticket {
         return $this->load();
     }
 
+    function hasState($state) {
+        return  (strcasecmp($this->getState(), $state)==0);
+    }
+
     function isOpen() {
-        return (strcasecmp($this->getStatus(),'Open')==0);
+        return $this->hasState('open');
     }
 
     function isReopened() {
         return ($this->getReopenDate());
     }
 
+    function isResolved() {
+        return $this->hasState('resolved');
+    }
+
     function isClosed() {
-        return (strcasecmp($this->getStatus(),'Closed')==0);
+         return $this->hasState('closed');
+    }
+
+    function isArchived() {
+         return $this->hasState('archived');
+    }
+
+    function isDeleted() {
+         return $this->hasState('deleted');
     }
 
     function isAssigned() {
@@ -291,8 +309,24 @@ class Ticket {
         return $this->ht['closed'];
     }
 
+    function getStatusId() {
+        return $this->ht['status_id'];
+    }
+
     function getStatus() {
-        return $this->ht['status'];
+
+        if (!$this->status && $this->getStatusId())
+            $this->status = TicketStatus::lookup($this->getStatusId());
+
+        return $this->status;
+    }
+
+    function getState() {
+
+        if (!$this->getStatus())
+            return '';
+
+        return $this->getStatus()->getState();
     }
 
     function getDeptId() {
@@ -785,20 +819,61 @@ class Ticket {
 
     //Status helper.
     function setStatus($status) {
+        global $thisstaff;
 
-        if(strcasecmp($this->getStatus(), $status)==0)
-            return true; //No changes needed.
+        if ($status && is_numeric($status))
+            $status = TicketStatus::lookup($status);
 
-        switch(strtolower($status)) {
-            case 'open':
-                return $this->reopen();
-                break;
+        if (!$status || !$status instanceof TicketStatus)
+            return false;
+
+        if ($this->getStatusId() == $status->getId())
+            return true;
+
+        $sql = 'UPDATE '.TICKET_TABLE.' SET updated=NOW() '.
+               ' ,status_id='.db_input($status->getId());
+
+        $ecb = null;
+        switch($status->getState()) {
             case 'closed':
-                return $this->close();
+                $sql.=', closed=NOW(), duedate=NULL ';
+                if ($thisstaff)
+                    $sql.=', staff_id='.db_input($thisstaff->getId());
+
+                $ecb = function($t) {
+                    $t->reload();
+                    $t->logEvent('closed');
+                    $t->deleteDrafts();
+                };
+                break;
+            case 'open':
+                if ($this->isClosed()) {
+                    $sql.= ',closed=NULL, reopened=NOW() ';
+
+                    $ecb = function ($t) {
+                        $t->logEvent('reopened', 'closed');
+                    };
+                }
                 break;
         }
 
-        return false;
+        $sql.=' WHERE ticket_id='.db_input($this->getId());
+
+        if (!db_query($sql) || !db_affected_rows())
+            return false;
+
+        // Log status change b4 reload
+        $note= sprintf('Status changed from %s to %s by %s',
+                $this->getStatus(),
+                $status,
+                $thisstaff ?: 'SYSTEM');
+
+        $this->logNote('Status Changed', $note, $thisstaff, false);
+
+        // Log events via callback
+        if ($ecb) $ecb($this);
+
+        return true;
     }
 
     function setState($state, $alerts=false) {
@@ -840,42 +915,11 @@ class Ticket {
         return (db_query($sql) && db_affected_rows());
     }
 
-    //Close the ticket
-    function close() {
-        global $thisstaff;
-
-        $sql='UPDATE '.TICKET_TABLE.' SET closed=NOW(),isoverdue=0, duedate=NULL, updated=NOW(), status='.db_input('closed');
-        if($thisstaff) //Give the closing  staff credit.
-            $sql.=', staff_id='.db_input($thisstaff->getId());
-
-        $sql.=' WHERE ticket_id='.db_input($this->getId());
-
-        if(!db_query($sql) || !db_affected_rows())
-            return false;
-
-        $this->reload();
-        $this->logEvent('closed');
-        $this->deleteDrafts();
-
-        return true;
-    }
-
     //set status to open on a closed ticket.
     function reopen($isanswered=0) {
+        global $cfg;
 
-        $sql='UPDATE '.TICKET_TABLE.' SET closed=NULL, updated=NOW(), reopened=NOW() '
-            .' ,status='.db_input('open')
-            .' ,isanswered='.db_input($isanswered)
-            .' WHERE ticket_id='.db_input($this->getId());
-
-        if (!db_query($sql) || !db_affected_rows())
-            return false;
-
-        $this->logEvent('reopened', 'closed');
-        $this->ht['status'] = 'open';
-        $this->ht['isanswerd'] = $isanswered;
-
-        return true;
+        return $this->setStatus($cfg->getDefaultTicketStatusId());
     }
 
     function onNewTicket($message, $autorespond=true, $alertstaff=true) {
@@ -1732,9 +1776,10 @@ class Ticket {
         if(!($response = $this->getThread()->addResponse($vars, $errors)))
             return null;
 
-        //Set status - if checked.
-        if(isset($vars['reply_ticket_status']) && $vars['reply_ticket_status'])
-            $this->setStatus($vars['reply_ticket_status']);
+        // Set status - if checked.
+        if ($vars['reply_status_id']
+                && $vars['reply_status_id'] != $this->getStatusId())
+            $this->setStatus($vars['reply_status_id']);
 
         if($thisstaff && $this->isOpen() && !$this->getStaffId()
                 && $cfg->autoClaimTickets())
@@ -1742,7 +1787,7 @@ class Ticket {
 
         $this->onResponse(); //do house cleaning..
 
-        /* email the user??  - if disabled - the bail out */
+        /* email the user??  - if disabled - then bail out */
         if(!$alert) return $response;
 
         $dept = $this->getDept();
@@ -1861,9 +1906,9 @@ class Ticket {
         // Get assigned staff just in case the ticket is closed.
         $assignee = $this->getStaff();
 
-        //Set state: Error on state change not critical!
-        if(isset($vars['state']) && $vars['state']) {
-            if($this->setState($vars['state']))
+        if ($vars['note_status_id']
+                && ($status=TicketStatus::lookup($vars['note_status_id']))) {
+            if ($this->setStatus($status))
                 $this->reload();
         }
 
@@ -2401,6 +2446,7 @@ class Ticket {
         // members can always add more forms now
 
         // OK...just do it.
+        $statusId = $vars['statusId'];
         $deptId = $vars['deptId']; //pre-selected Dept if any.
         $source = ucfirst($vars['source']);
 
@@ -2431,6 +2477,7 @@ class Ticket {
         // Intenal mapping magic...see if we need to override anything
         if (isset($topic)) {
             $deptId = $deptId ?: $topic->getDeptId();
+            $statusId = $statusId ?: $topic->getStatusId();
             $priority = $form->getAnswer('priority');
             if (!$priority || !$priority->getIdValue())
                 $form->setAnswer('priority', null, $topic->getPriorityId());
@@ -2466,6 +2513,7 @@ class Ticket {
         if (!$priority || !$priority->getIdValue())
             $form->setAnswer('priority', null, $cfg->getDefaultPriorityId());
         $deptId = $deptId ?: $cfg->getDefaultDeptId();
+        $statusId = $statusId ?: $cfg->getDefaultTicketStatusId();
         $topicId = $vars['topicId'] ?: 0;
         $ipaddress = $vars['ip'] ?: $_SERVER['REMOTE_ADDR'];
 
@@ -2477,6 +2525,7 @@ class Ticket {
             .' ,`number`='.db_input($number)
             .' ,dept_id='.db_input($deptId)
             .' ,topic_id='.db_input($topicId)
+            .' ,status_id='.db_input($statusId)
             .' ,ip_address='.db_input($ipaddress)
             .' ,source='.db_input($source);
 
diff --git a/include/staff/ticket-view.inc.php b/include/staff/ticket-view.inc.php
index a63df79ea83538377ed3c84512c1fddac1077807..e8a78540f68aa5c0b4c9d532eaa6b51913666c4d 100644
--- a/include/staff/ticket-view.inc.php
+++ b/include/staff/ticket-view.inc.php
@@ -585,28 +585,32 @@ $tcount+= $ticket->getNumNotes();
                     } ?>
                 </td>
             </tr>
-            <?php
-            if($ticket->isClosed() || $thisstaff->canCloseTickets()) { ?>
             <tr>
                 <td width="120">
                     <label><strong>Ticket Status:</strong></label>
                 </td>
                 <td>
+                    <select name="reply_status_id">
                     <?php
-                    $statusChecked=isset($info['reply_ticket_status'])?'checked="checked"':'';
-                    if($ticket->isClosed()) { ?>
-                        <label><input type="checkbox" name="reply_ticket_status" id="reply_ticket_status" value="Open"
-                            <?php echo $statusChecked; ?>> Reopen on Reply</label>
-                   <?php
-                    } elseif($thisstaff->canCloseTickets()) { ?>
-                         <label><input type="checkbox" name="reply_ticket_status" id="reply_ticket_status" value="Closed"
-                              <?php echo $statusChecked; ?>> Close on Reply</label>
-                   <?php
-                    } ?>
+                    $statusId = $info['reply_status_id'] ?: $ticket->getStatusId();
+                    $states = array('open', 'resolved');
+                    if ($thisstaff->canCloseTickets())
+                        $states = array_merge($states,
+                                array('closed', 'archived'));
+
+                    foreach (TicketStatusList::getAll($states) as $s) {
+                        if (!$s->isEnabled()) continue;
+                        echo sprintf('<option value="%d" %s>%s</option>',
+                                $s->getId(),
+                                ($statusId == $s->getId())
+                                 ? 'selected="selected"' : '',
+                                $s->getName()
+                                );
+                    }
+                    ?>
+                    </select>
                 </td>
             </tr>
-            <?php
-            } ?>
          </tbody>
         </table>
         <p  style="padding-left:165px;">
@@ -677,47 +681,26 @@ $tcount+= $ticket->getNumNotes();
                 </td>
                 <td>
                     <div class="faded"></div>
-                    <select name="state">
+                    <select name="note_status_id">
                         <option value="" selected="selected">&mdash; unchanged &mdash;</option>
                         <?php
-                        $state = $info['state'];
-                        if($ticket->isClosed()){
-                            echo sprintf('<option value="open" %s>Reopen Ticket</option>',
-                                    ($state=='reopen')?'selected="selelected"':'');
-                        } else {
-                            if($thisstaff->canCloseTickets())
-                                echo sprintf('<option value="closed" %s>Close Ticket</option>',
-                                    ($state=='closed')?'selected="selelected"':'');
-
-                            /* Ticket open - states */
-                            echo '<option value="" disabled="disabled">&mdash; Ticket States &mdash;</option>';
-
-                            //Answer - state
-                            if($ticket->isAnswered())
-                                echo sprintf('<option value="unanswered" %s>Mark As Unanswered</option>',
-                                    ($state=='unanswered')?'selected="selelected"':'');
-                            else
-                                echo sprintf('<option value="answered" %s>Mark As Answered</option>',
-                                    ($state=='answered')?'selected="selelected"':'');
-
-                            //overdue - state
-                            // Only department manager can set/clear overdue flag directly.
-                            // Staff with edit perm. can still set overdue date & change SLA.
-                            if($dept && $dept->isManager($thisstaff)) {
-                                if(!$ticket->isOverdue())
-                                    echo sprintf('<option value="overdue" %s>Flag As Overdue</option>',
-                                        ($state=='answered')?'selected="selelected"':'');
-                                else
-                                    echo sprintf('<option value="notdue" %s>Clear Overdue Flag</option>',
-                                        ($state=='notdue')?'selected="selelected"':'');
-
-                                if($ticket->isAssigned())
-                                    echo sprintf('<option value="unassigned" %s>Release (Unassign) Ticket</option>',
-                                        ($state=='unassigned')?'selected="selelected"':'');
-                            }
-                        }?>
+                        $statusId = $info['note_status_id'] ?: $ticket->getStatusId();
+                        $states = array('open', 'resolved');
+                        if ($thisstaff->canCloseTickets())
+                            $states = array_merge($states,
+                                    array('closed', 'archived'));
+                        foreach (TicketStatusList::getAll($states) as $s) {
+                            if (!$s->isEnabled()) continue;
+                            echo sprintf('<option value="%d" %s>%s</option>',
+                                    $s->getId(),
+                                    ($statusId == $s->getId())
+                                     ? 'selected="selected"' : '',
+                                    $s->getName()
+                                    );
+                        }
+                        ?>
                     </select>
-                    &nbsp;<span class='error'>*&nbsp;<?php echo $errors['state']; ?></span>
+                    &nbsp;<span class='error'>*&nbsp;<?php echo $errors['note_status_id']; ?></span>
                 </td>
             </tr>
             </div>
@@ -927,12 +910,41 @@ $tcount+= $ticket->getNumNotes();
     <h3><?php echo sprintf('%s Ticket #%s', ($ticket->isClosed()?'Reopen':'Close'), $ticket->getNumber()); ?></h3>
     <a class="close" href=""><i class="icon-remove-circle"></i></a>
     <hr/>
-    <?php echo sprintf('Are you sure you want to <b>%s</b> this ticket?', $ticket->isClosed()?'REOPEN':'CLOSE'); ?>
+    <?php
+        echo sprintf('Are you sure you want to <b>%s</b> this ticket?',
+                $ticket->isClosed()?'REOPEN':'CLOSE');
+        $action = $ticket->isClosed() ? 'reopen': 'close';
+     ?>
+    <br><br>
     <form action="tickets.php?id=<?php echo $ticket->getId(); ?>" method="post" id="status-form" name="status-form">
         <?php csrf_token(); ?>
         <input type="hidden" name="id" value="<?php echo $ticket->getId(); ?>">
         <input type="hidden" name="a" value="process">
-        <input type="hidden" name="do" value="<?php echo $ticket->isClosed()?'reopen':'close'; ?>">
+        <input type="hidden" name="do" value="<?php echo $action; ?>">
+        <fieldset>
+            <div><strong>Ticket Status </strong>
+                <select name="status_id">
+                    <?php
+                    $statusId = $info['status_id'] ?: 0;
+                    if (!$ticket->isOpen())
+                        $states = array('open');
+                    else
+                        $states = array('resolved', 'closed');
+
+                    foreach (TicketStatusList::getAll($states) as $s) {
+                        if (!$s->isEnabled()) continue;
+                        echo sprintf('<option value="%d" %s>%s</option>',
+                                $s->getId(),
+                                ($statusId == $s->getId())
+                                 ? 'selected="selected"' : '',
+                                $s->getName()
+                                );
+                    }
+                    ?>
+                </select>
+                &nbsp;<span class='error'>*&nbsp;<?php echo $errors['status_id']; ?></span>
+            </div>
+        </fieldset>
         <fieldset>
             <div style="margin-bottom:0.5em">
             <em>Reasons for status change (internal note). Optional but highly recommended.</em>
diff --git a/include/upgrader/streams/core/8f99b8bf-00000000.patch.sql b/include/upgrader/streams/core/8f99b8bf-00000000.patch.sql
index 337a974067b8f3c4cfa5911c0f820ca341698f97..be64fdfbb82cba0f3ecebfed6131d63e0964dd6a 100644
--- a/include/upgrader/streams/core/8f99b8bf-00000000.patch.sql
+++ b/include/upgrader/streams/core/8f99b8bf-00000000.patch.sql
@@ -21,7 +21,8 @@ CREATE TABLE IF NOT EXISTS `%TABLE_PREFIX%ticket_status` (
   `created` datetime NOT NULL,
   `updated` datetime NOT NULL,
   PRIMARY KEY (`id`),
-  UNIQUE KEY `name` (`name`)
+  UNIQUE KEY `name` (`name`),
+  KEY `state` ( `state` )
 ) DEFAULT CHARSET=utf8;
 
 ALTER TABLE  `%TABLE_PREFIX%help_topic`
@@ -30,6 +31,10 @@ ALTER TABLE  `%TABLE_PREFIX%help_topic`
 ALTER TABLE  `%TABLE_PREFIX%filter`
     ADD  `status_id` INT UNSIGNED NOT NULL DEFAULT  '0' AFTER  `email_id`;
 
+ALTER TABLE  `%TABLE_PREFIX%ticket`
+    ADD  `status_id` INT UNSIGNED NOT NULL DEFAULT  '0' AFTER  `user_email_id`,
+    ADD INDEX (`status_id`);
+
 UPDATE `%TABLE_PREFIX%config`
     SET `value` = 'cbf8c933d6d2eaaa971042eb2efce247'
     WHERE `key` = 'schema_signature' AND `namespace` = 'core';
diff --git a/setup/inc/streams/core/install-mysql.sql b/setup/inc/streams/core/install-mysql.sql
index f3b41bf656b2931fec8a3f9a4e1fa651b2238880..1e83cb45482cd9a4b92dd7c6f3f498a675e47e2e 100644
--- a/setup/inc/streams/core/install-mysql.sql
+++ b/setup/inc/streams/core/install-mysql.sql
@@ -573,12 +573,14 @@ CREATE TABLE `%TABLE_PREFIX%ticket` (
   `number` varchar(20),
   `user_id` int(11) unsigned NOT NULL default '0',
   `user_email_id` int(11) unsigned NOT NULL default '0',
+  `status_id` int(10) unsigned NOT NULL default '0',
   `dept_id` int(10) unsigned NOT NULL default '0',
   `sla_id` int(10) unsigned NOT NULL default '0',
   `topic_id` int(10) unsigned NOT NULL default '0',
   `staff_id` int(10) unsigned NOT NULL default '0',
   `team_id` int(10) unsigned NOT NULL default '0',
   `email_id` int(11) unsigned NOT NULL default '0',
+  `flags` int(10) unsigned NOT NULL default '0',
   `ip_address` varchar(64) NOT NULL default '',
   `status` enum('open','closed') NOT NULL default 'open',
   `source` enum('Web','Email','Phone','API','Other') NOT NULL default 'Other',
@@ -595,8 +597,9 @@ CREATE TABLE `%TABLE_PREFIX%ticket` (
   KEY `user_id` (`user_id`),
   KEY `dept_id` (`dept_id`),
   KEY `staff_id` (`staff_id`),
-  KEY `team_id` (`staff_id`),
   KEY `status` (`status`),
+  KEY `team_id` (`team_id`),
+  KEY `status_id` (`status_id`),
   KEY `created` (`created`),
   KEY `closed` (`closed`),
   KEY `duedate` (`duedate`),
@@ -667,7 +670,8 @@ CREATE TABLE IF NOT EXISTS `%TABLE_PREFIX%ticket_status` (
   `created` datetime NOT NULL,
   `updated` datetime NOT NULL,
   PRIMARY KEY (`id`),
-  UNIQUE KEY `name` (`name`)
+  UNIQUE KEY `name` (`name`),
+  KEY `state` (`state`)
 ) DEFAULT CHARSET=utf8;