/*
 * Copyright 2006-2007 Queplix Corp.
 *
 * Licensed under the Queplix Public License, Version 1.1.1 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.queplix.com/solutions/commercial-open-source/queplix-public-license/
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 *
 */

package com.queplix.core.modules.inbox.utils;

import com.queplix.core.utils.DateHelper;

import javax.mail.FetchProfile;
import javax.mail.Message;
import javax.mail.MessagingException;
import java.text.ParseException;
import java.util.Date;
import java.util.TimeZone;

/**
 * POP3 Inbox Provider.
 *
 * @author [ALB] Baranov Andrey
 * @version $Revision: 1.3 $ $Date: 2006/06/04 00:15:09 $
 */

public class POP3InboxProvider
        extends AbstractInboxProvider {

    // ----------------------------------------------------- constants

    /**
     * Mail date header patterns.
     */
    protected static final String XOriginalArrivalTimePattern =
            "d MMM yyyy HH:mm:ss.S (z)";

    protected static final String[] ReceivedPatterns = {
            "EEE, d MMM yyyy HH:mm:ss Z",
            "EEE, d MMM yyyy HH:mm:ss Z (z)"
    };

    // ----------------------------------------------------- getters

    /*
     * No javadoc
     * @see InboxProvider#getJavaMailProto
     */

    public String getJavaMailProto() {
        return "pop3";
    }

    // ----------------------------------------------------- public methods

    /*
     * No javadoc
     * @see AbstractInboxProvider#getResultSet
     */

    public ResultSet getResultSet(MessageFilter filter)
            throws MessagingException {

        if(rs == null) {
            Message[] messages = null;
            if(folder.getMessageCount() > 0) {
                messages = folder.getMessages();

                /** @todo [alb] analyse it */
                FetchProfile fp = new FetchProfile();
                fp.add(FetchProfile.Item.FLAGS);
                fp.add("X-OriginalArrivalTime");
                fp.add("Received");
                folder.fetch(messages, fp);
            }

            // Create new ResultSet.
            rs = new InboxResultSet(messages);
            rs.setMessageFilter(filter);
        }

        return rs;
    }

    /*
     * No javadoc
     * @see InboxProvider#getUID
     */
    public String getUID(Message message)
            throws MessagingException {

        if(folder instanceof com.sun.mail.pop3.POP3Folder) {
            com.sun.mail.pop3.POP3Folder pf
                    = (com.sun.mail.pop3.POP3Folder) folder;
            try {
                return pf.getUID(message);
            } catch (Exception ex) {
                // Ignore any POP3 exceptions.
                return null;
            }
        } else {
            return null;
        }
    }

    /*
     * No javadoc
     * @see InboxProvider#getServerDate
     */
    public Date getServerDate(Message message)
            throws MessagingException {

        Date d = null;

        // 1. Use following header:
        // X-OriginalArrivalTime: 16 Sep 2002 20:02:18.0515 (UTC)
        if(d == null) {
            String[] ss = message.getHeader("X-OriginalArrivalTime");
            if(ss != null && ss.length > 0) {
                String s = ss[0];

                DEBUG(logName + "Found 'X-OriginalArrivalTime' = '" + s + "'");

                // getting first part
                int pos = s.indexOf(")");
                if(pos > 0) {
                    String dateS = s.substring(0, pos + 1).trim();
                    try {
                        d = DateHelper.parseDate(dateS,
                                XOriginalArrivalTimePattern);
                    } catch (ParseException ex) {
                        String msg =
                                "Cannot parse date from 'X-OriginalArrivalTime' header: "
                                        +
                                        dateS + " using pattern: "
                                        + XOriginalArrivalTimePattern;
                        publisher.WARN(msg, new Long(account.getAccountID()));
                        WARN(logName + msg);
                    }
                }
            }
        }

        // 2.Use following headers:
        // Received: by localhost
        //	            id <01C61C6F.68EC5FFE@localhost>; Wed, 18 Jan 2006 15:40:25 -050
        // Received: id 949608F0F3; Mon, 23 Jan 2006 23:53:09 +0300
        if(d == null) {
            String[] ss = message.getHeader("Received");
            if(ss != null && ss.length > 0) {
                for(int i = 0; i < ss.length; i++) {
                    String s = ss[i];

                    DEBUG(logName + "Found 'Received' = '" + s + "'");

                    // getting last part
                    int pos = s.lastIndexOf(";");
                    if(pos < 0) {
                        continue;
                    }
                    String dateS = s.substring(pos + 1).trim();

                    // apply patterns in cycle
                    int patterns = ReceivedPatterns.length;
                    for(int j = 0; j < patterns; j++) {
                        String pattern = ReceivedPatterns[j];

                        try {
                            d = DateHelper.parseDate(dateS, pattern);
                            break;
                        } catch (ParseException ex) {
                            if(j == patterns - 1) {
                                String msg =
                                        "Cannot parse date from 'Received' header: "
                                                +
                                                dateS + " using pattern "
                                                + pattern;
                                publisher.WARN(msg, new Long(
                                        account.getAccountID()));
                                WARN(logName + msg);
                            }
                        }
                    } // for
                } // for
            } // if
        } // if

        // If header value not found - use 'Sent Date'.
        if(d == null) {
            d = message.getSentDate();
        }
        // Convert to system.
        if(d != null) {
            d = new Date(DateHelper.toSystem(d.getTime(),
                    TimeZone.getDefault()));
        }

        DEBUG(logName + " found date = " + d);

        return d;
    }

    /*
     * No javadoc
     * @see InboxProvider#getMessage
     */
    public Message getMessage(String uid)
            throws MessagingException {

        long l;
        try {
            l = Long.parseLong(uid);
        } catch (NumberFormatException ex) {
            ERROR(ex);
            return null;
        }

        if(folder instanceof com.sun.mail.pop3.POP3Folder) {
            // Use SingleMessageFilter and #getResultSet.
            SingleMessageFilter filter = new SingleMessageFilter(uid, this);
            ResultSet rs = getResultSet(filter);
            return rs.next();
        } else {
            return null;
        }
    }

}
