package com.e_gineering.simplegmailclient;

import java.io.IOException;
import java.util.Arrays;
import java.util.Properties;

import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.NoSuchProviderException;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

/**
 * A simple email client that will send and receive email with a hosted Gmail account
 * @author christian.desserich
 */
public class SimpleGmailClient {
    private Session session;
    private Transport transport;
    private Store store;
    private Folder inbox;
    private static final String INBOX = "INBOX";
    
    /**
     * Logs in to a Gmail account
     * @param username
     * @param password
     * @throws SimpleGmailClientException
     */
    public void login(String username, String password) throws SimpleGmailClientException {
        
        session = Session.getInstance(new Properties());
        
        try {
            
            transport = session.getTransport("smtps");
            transport.connect("smtp.gmail.com", username, password);
            
        } catch (NoSuchProviderException nspe) {
            throw new SimpleGmailClientException("Error getting Gmail Transport", nspe);
        } catch (MessagingException me) {
            throw new SimpleGmailClientException("Error connecting to Gmail Transport", me);
        }
        
        try {
            
            store = session.getStore("imaps");
            store.connect("imap.gmail.com", username, password);
            
        } catch (NoSuchProviderException nspe) {
            throw new SimpleGmailClientException("Error getting Gmail Store", nspe);
        } catch (MessagingException me) {
            throw new SimpleGmailClientException("Error connecting to Gmail Store", me);
        }
        
        try {
            
            inbox = store.getFolder(INBOX);
            inbox.open(Folder.READ_WRITE);
            
        } catch (MessagingException me) {
            throw new SimpleGmailClientException("Error opening Gmail Inbox", me);
        }
    }
    
    /**
     * Sends a plain text email
     * @param to
     * @param subject
     * @param text
     * @throws SimpleGmailClientException
     */
    public void sendMessage(String to, String subject, String text) 
            throws SimpleGmailClientException {
        
        Message message = new MimeMessage(session);
        
        try {
            
            message.setFrom(new InternetAddress("cdesserich@gmail.com"));
            message.setRecipient(Message.RecipientType.TO, new InternetAddress(to));
            message.setSubject(subject);
            message.setText(text);
            
        } catch (AddressException ae) {
            throw new SimpleGmailClientException("Invalid internet address", ae);
        } catch (MessagingException me) {
            throw new SimpleGmailClientException("Error creating message", me);
        }
        
        try {
            
            transport.sendMessage(message, message.getAllRecipients());
            
        } catch (MessagingException me) {
            throw new SimpleGmailClientException("Error sending message", me);
        }
    }
    
    /**
     * Reads an email message with a given subject. 
     * Returns null if the subject is not found.
     * @param subject
     * @return A simple String representation of an email message, 
     * null if not found
     * @throws SimpleGmailClientException
     */
    public String readMessage(String subject) throws SimpleGmailClientException {
        
        String messageString = null;
        
        try {
            
            for (Message message : Arrays.asList(inbox.getMessages())) {
                if (message.getSubject().equals(subject)) {
                    messageString = "To: " + Arrays.asList(message.getAllRecipients()) + "n" + 
                                    "From: " + Arrays.asList(message.getFrom()) + "n" + 
                                    "Sent: " + message.getSentDate() + "n" + 
                                    "Subject: " + message.getSubject() + "n" + 
                                    "Text: " + message.getContent();
                    break;
                }
            }
            
        } catch (MessagingException me) {
            throw new SimpleGmailClientException("Error reading Gmail Inbox", me);
        } catch (IOException e) {/* Not using streams, only plain text */}
        
        return messageString;
    }
    
    /**
     * Deletes (permanently) an email message with the given subject
     * @param subject
     * @throws SimpleGmailClientException
     */
    public void deleteMessage(String subject) throws SimpleGmailClientException {
        
        try {
            
            for (Message message : Arrays.asList(inbox.getMessages())) {
                if (message.getSubject().equals(subject)) {
                    message.setFlag(Flags.Flag.DELETED, true);
                    break;
                }
            }
            
        } catch (MessagingException me) {
            throw new SimpleGmailClientException("Error reading Gmail Inbox", me);
        }
        
        try {
            
            inbox.expunge();
            
        } catch (MessagingException me) {
            throw new SimpleGmailClientException("Error deleting messages from Gmail Inbox", me);
        }
    }
    
    /**
     * Logs out of Gmail
     */
    public void logout() {
        if (transport != null) {
            try {transport.close();} catch (MessagingException me) {/* We could log this error */}
        }
        
        if (store != null) {
            try {store.close();} catch (MessagingException me) {/* We could log this error */}
        }
    }
}