public function remove(Horde_Imap_Client_Ids $ids)
    {
        /* For sequence numbers, we need to reindex anytime we have an index
         * that appears equal to or after a previously seen index. If an IMAP
         * server is smart, it will expunge in reverse order instead. */
        if ($ids->sequence) {
            $remove = $ids->ids;
        } else {
            $ids->sort();
            $remove = array_reverse(array_keys($this->lookup($ids)));
        }

        if (empty($remove)) {
            return;
        }

        $this->sort();

        if (count($remove) == count($this->_ids) &&
            !array_diff($remove, array_keys($this->_ids))) {
            $this->_ids = array();
            return;
        }

        /* Find the minimum sequence number to remove. We know entries before
         * this are untouched so no need to process them multiple times. */
        $first = min($remove);
        $edit = $newids = array();
        foreach (array_keys($this->_ids) as $i => $seq) {
            if ($seq >= $first) {
                $i += (($seq == $first) ? 0 : 1);
                $newids = array_slice($this->_ids, 0, $i, true);
                $edit = array_slice($this->_ids, $i + (($seq == $first) ? 0 : 1), null, true);
                break;
            }
        }

        if (!empty($edit)) {
            foreach ($remove as $val) {
                $found = false;
                $tmp = array();

                foreach (array_keys($edit) as $i => $seq) {
                    if ($found) {
                        $tmp[$seq - 1] = $edit[$seq];
                    } elseif ($seq >= $val) {
                        $tmp = array_slice($edit, 0, ($seq == $val) ? $i : $i + 1, true);
                        $found = true;
                    }
                }

                $edit = $tmp;
            }
        }

        $this->_ids = $newids + $edit;
    }