001    /*
002     * Copyright 2010 the original author or authors.
003     * 
004     *  Licensed under the Apache License, Version 2.0 (the "License");
005     *  you may not use this file except in compliance with the License.
006     *  You may obtain a copy of the License at
007     *
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     *
010     *  Unless required by applicable law or agreed to in writing, software
011     *  distributed under the License is distributed on an "AS IS" BASIS,
012     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     *  See the License for the specific language governing permissions and
014     *  limitations under the License.
015     */
016    package com.hs.mail.imap.mailbox;
017    
018    import java.util.List;
019    
020    import com.hs.mail.imap.dao.DaoFactory;
021    
022    /**
023     * Convert Unique Identifier (UID) to Message Sequence Number (MSN) and vice
024     * versa.
025     * 
026     * @author Won Chul Doh
027     * @since Mar 22, 2010
028     * 
029     */
030    public class UidToMsnMapper {
031    
032            protected SelectedMailbox selected = null;
033            protected List<Long> uids;
034            protected boolean useUID = false;
035    
036            public UidToMsnMapper(SelectedMailbox selected, List<Long> uids, boolean useUID) {
037                    this.selected = selected;
038                    this.uids = uids;
039                    this.useUID = useUID;
040            }
041    
042            public UidToMsnMapper(SelectedMailbox selected, boolean useUID) {
043                    this(selected, selected.getCachedUids(), useUID);
044            }
045    
046            public long getUID(int msgnum) {
047                    long uid = selected.getUID(msgnum);
048                    if (uid == -1) {
049                            prepare();
050                            uid = (msgnum <= uids.size()) ? (Long) uids.get(msgnum - 1) : -1;
051                            if (uid != -1)
052                                    selected.add(msgnum, uid);
053                    }
054                    return uid;
055            }
056    
057            public int getMessageNumber(long uid) {
058                    int msgnum = selected.getMessageNumber(uid);
059                    if (msgnum == -1) {
060                            prepare();
061                            if (uid == Long.MAX_VALUE) {    // *
062                                    msgnum = (uids.size() > 0) ? uids.size() : -1;
063                            } else {
064                                    int i = uids.indexOf(uid);
065                                    msgnum = (i >= 0) ? i + 1 : -1;
066                                    if (msgnum != -1)
067                                            selected.add(msgnum, uid);
068                            }
069                    }
070                    return msgnum;
071            }
072    
073            public List<Long> getUIDList() {
074                    return uids;
075            }
076            
077            /**
078             * Find the smallest message sequence number whose corresponding unique
079             * identifier is equal or greater than the given unique identifier.
080             * 
081             * @param min
082             *            the key UID to be searched for
083             * @return the smallest message sequence number if found; otherwise -1
084             */
085            public long getMinMessageNumber(long min) {
086                    if (useUID) {
087                            int msgnum = getMessageNumber(min);
088                            if (msgnum == -1) {
089                                    if ((msgnum = search(uids, min)) != -1) {
090                                            return (uids.get(msgnum) >= min) ? msgnum + 1 : msgnum + 2;
091                                    }
092                            }
093                            return msgnum;
094                    } else {
095                            return min;
096                    }
097            }
098    
099            /**
100             * Find the largest message sequence number whose corresponding unique
101             * identifier is equal or less than the given unique identifier.
102             * 
103             * @param max
104             *            the key UID to be searched for
105             * @return the largest message sequence number if found; otherwise -1
106             */
107            public long getMaxMessageNumber(long max) {
108                    if (useUID) {
109                            int msgnum = getMessageNumber(max);
110                            if (msgnum == -1) {
111                                    if ((msgnum = search(uids, max)) != -1) {
112                                            return (uids.get(msgnum) <= max) ? msgnum + 1: msgnum;
113                                    }
114                            }
115                            return msgnum;
116                    } else {
117                            return max;
118                    }
119            }
120            
121            protected int search(List<Long> v, long t) {
122                    int low = 0;
123                    int mid = -1;
124                    int high = v.size() - 1;
125                    while (low <= high) {
126                            mid = (low + high) / 2;
127                            long c = v.get(mid) - t;
128                            if (c > 0)
129                                    high = mid - 1;
130                            else if (c < 0)
131                                    low = mid + 1;
132                            else
133                                    break;
134                    }
135                    return mid;
136            }
137            
138            private void prepare() {
139                    if (uids == null)
140                            uids = DaoFactory.getMessageDao().getMessageIDList(
141                                            selected.getMailboxID());
142            }
143    
144    }