'This method will calculate/update the thread-ID and parent-ID of a
given message. Mailpile will group all messages in a thread
together as "replies" to the root message; but it will also keep track
of what is the immediate parent of any given mail.
Note that the "root" message may not be the actual root of the thread;
it\'s just whatever message fit the bill at the time.
See https://www.jwz.org/doc/threading.html for a very nice discussion
and threading algorithm which we\'re not using, but wish we could.'

def set_conversation_ids(self, msg_mid, msg, subject_threading=True):

    parent_mid = None
    parent_idx_pos = None
    msg_thr_mid = None
    in_reply_to = safe_decode_hdr(msg, 'in-reply-to')
    refs = safe_decode_hdr(msg, 'references').replace(',', '    ').strip().split()
    if in_reply_to:
        if ('<' in in_reply_to):
            irt_ref = ('<%s>' % in_reply_to.split('<')[1].split('>')[0])
            while (irt_ref in refs):
                refs.remove(irt_ref)
            refs.append(irt_ref)
    if refs:
        parent_idx_pos = self.MSGIDS.get(self._encode_msg_id(refs[(-1)]))
        if (parent_idx_pos is not None):
            parent_mid = b36(parent_idx_pos)
    enc_refs = [self._encode_msg_id(r) for r in refs]
    ref_idxs = [self.MSGIDS.get(er) for er in enc_refs]
    last_missing = None
    for (i, r) in enumerate(ref_idxs):
        if (r is None):
            last_missing = i
    if (last_missing is not None):
        (g_idx_pos, g_info) = self.add_new_ghost(enc_refs[last_missing])
        ref_idxs[last_missing] = g_idx_pos
    ref_idxs = [r for r in ref_idxs if (r is not None)]
    conversations = set([])
    for ref_idx_pos in (r for r in reversed(ref_idxs) if (r is not None)):
        try:
            ref_info = self.get_msg_at_idx_pos(ref_idx_pos)
            if ref_info[self.MSG_REPLIES]:
                conversations.add(b36(ref_idx_pos))
            msg_thr_mid = ref_info[self.MSG_THREAD_MID].split('/')[0]
            conversations.add(msg_thr_mid)
            if ref_info[self.MSG_THREAD_MID].endswith('/-'):
                break
        except (KeyError, ValueError, IndexError):
            pass
    root = None
    replies = []
    if msg_thr_mid:
        root = self.get_msg_at_idx_pos(int(msg_thr_mid, 36))
        replies = [r for r in root[self.MSG_REPLIES][:(-1)].split(',') if r]
        reparent = []
        conversations.add(msg_mid)
        for t_mid in (c for c in conversations if (c != msg_thr_mid)):
            t_msg_info = self.get_msg_at_idx_pos(int(t_mid, 36))
            reparent.extend(t_msg_info[self.MSG_REPLIES][:(-1)].split(','))
            reparent.append(t_mid)
        for m_mid in set([r for r in reparent if r]):
            m_msg_idx = int(m_mid, 36)
            m_msg_info = self.get_msg_at_idx_pos(m_msg_idx)
            otp = m_msg_info[self.MSG_THREAD_MID].split('/')
            otp[0] = msg_thr_mid
            m_msg_info[self.MSG_THREAD_MID] = '/'.join(otp)
            m_msg_info[self.MSG_REPLIES] = ''
            self.set_msg_at_idx_pos(m_msg_idx, m_msg_info)
            replies.append(m_mid)
    if (msg_thr_mid and root):
        replies.append(msg_mid)
        for ref_idx_pos in (r for r in ref_idxs if (r is not None)):
            ref_mid = b36(ref_idx_pos)
            replies.append(ref_mid)
        root[self.MSG_REPLIES] = (','.join(sorted(list(set(replies)))) + ',')
        self.set_msg_at_idx_pos(int(msg_thr_mid, 36), root)
    msg_idx_pos = int(msg_mid, 36)
    msg_info = self.get_msg_at_idx_pos(msg_idx_pos)
    msg_replies = msg_info[self.MSG_REPLIES][:(-1)].split(',')
    if (subject_threading and (not (msg_thr_mid or refs or msg_replies))):
        subj = msg_info[self.MSG_SUBJECT].lower()
        subj = subj.replace('re:    ', '')
        date = long(msg_info[self.MSG_DATE], 36)
        if (subj.strip() != ''):
            for midx in reversed(range(max(0, (msg_idx_pos - 150)), msg_idx_pos)):
                try:
                    m_info = self.get_msg_at_idx_pos(midx)
                    m_date = long(m_info[self.MSG_DATE], 36)
                    m_subj = m_info[self.MSG_SUBJECT]
                    if ((m_date < date) and (m_subj.lower().replace('re:    ', '') == subj)):
                        msg_thr_mid = m_info[self.MSG_THREAD_MID]
                        msg_thr_mid = msg_thr_mid.split('/')[0]
                        parent = self.get_msg_at_idx_pos(int(msg_thr_mid, 36))
                        replies = parent[self.MSG_REPLIES][:(-1)].split(',')
                        if (len(replies) < 100):
                            if (msg_mid not in replies):
                                replies.append(msg_mid)
                            parent[self.MSG_REPLIES] = (','.join(replies) + ',')
                            self.set_msg_at_idx_pos(int(msg_thr_mid, 36), parent)
                            break
                        else:
                            msg_thr_mid = None
                    if ((date - m_date) > ((5 * 24) * 3600)):
                        break
                except (KeyError, ValueError, IndexError):
                    pass
    if (not msg_thr_mid):
        msg_thr_mid = msg_mid
    if (parent_mid and (parent_mid != msg_thr_mid)):
        msg_info[self.MSG_THREAD_MID] = '/'.join([msg_thr_mid, parent_mid])
    else:
        msg_info[self.MSG_THREAD_MID] = msg_thr_mid
    self.set_msg_at_idx_pos(msg_idx_pos, msg_info)
