package net.oni2.aeinstaller.gui.reporter;

import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;
import java.util.ResourceBundle;
import java.util.regex.Pattern;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.AuthenticationFailedException;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.Message.RecipientType;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.swing.AbstractAction;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.KeyStroke;

import net.oni2.aeinstaller.backend.LogPrintStream;
import net.oni2.aeinstaller.backend.Paths;
import net.oni2.aeinstaller.backend.StringDataSource;
import net.oni2.resourcebundle.UTF8ResourceBundleLoader;
import net.oni2.swingcomponents.HTMLLinkLabel;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.io.filefilter.NameFileFilter;
import org.apache.commons.io.filefilter.NotFileFilter;
import org.apache.commons.io.filefilter.TrueFileFilter;
import org.javabuilders.BuildResult;
import org.javabuilders.annotations.DoInBackground;
import org.javabuilders.event.BackgroundEvent;
import org.javabuilders.swing.SwingJavaBuilder;

/**
 * @author Christian Illy
 */
public class ReporterDialog extends JDialog {
	private static final long serialVersionUID = -5719515325671846620L;

	private ResourceBundle bundle = UTF8ResourceBundleLoader
			.getBundle("net.oni2.aeinstaller.localization."
					+ getClass().getSimpleName());
	@SuppressWarnings("unused")
	private BuildResult result = SwingJavaBuilder.build(this, bundle);

	private HTMLLinkLabel lblInfo;
	private HTMLLinkLabel lblFiles;
	private JTextField txtMail;
	private JTextArea txtMessage;
	private JCheckBox chkGetCopy;

	private final String SMTP_HOST_NAME = "mail.illy.bz";
	private final String SMTP_AUTH_USER = "aei_reports@oni2.net";
	private final String SMTP_AUTH_PWD = "mb0NkjHuWrDFfMDe2BkUDU2Dknkkvq";
	private final String EMAIL_SUBJECT = "AE support request";
	private final String EMAIL_TO = "ae-support@oni2.net";

	/**
	 * Open the settings
	 */
	public ReporterDialog() {
		lblInfo.setText(bundle.getString("lblInfo"));
		lblFiles.setText(bundle.getString("lblFiles"));

		AbstractAction closeAction = new AbstractAction() {

			private static final long serialVersionUID = 1L;

			public void actionPerformed(ActionEvent arg0) {
				dispose();
			}
		};
		KeyStroke ksCtrlW = KeyStroke
				.getKeyStroke('W', KeyEvent.CTRL_DOWN_MASK);
		getRootPane()
				.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
				.put(ksCtrlW, "close");
		getRootPane().getActionMap().put("close", closeAction);

		setLocationRelativeTo(null);

		initFields();
	}

	private void initFields() {
	}

	private class SMTPAuthenticator extends Authenticator {
		public PasswordAuthentication getPasswordAuthentication() {
			String username = SMTP_AUTH_USER;
			String password = SMTP_AUTH_PWD;
			return new PasswordAuthentication(username, password);
		}
	}

	@DoInBackground(progressMessage = "send.title", cancelable = false, indeterminateProgress = true)
	private boolean send(final BackgroundEvent evt) {
		try {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

			StringBuffer msgText = new StringBuffer();
			msgText.append("Support request\nTime: " + sdf.format(new Date())
					+ "\n\n");

			// Set the host smtp address
			Properties props = new Properties();
			props.put("mail.smtp.host", SMTP_HOST_NAME);
			props.put("mail.smtp.auth", "true");
			Authenticator auth = new SMTPAuthenticator();
			Session session = Session.getDefaultInstance(props, auth);

			session.setDebug(false);

			// create a message
			Message msg = new MimeMessage(session);
			msg.setFrom(new InternetAddress(txtMail.getText()));
			msg.setRecipient(RecipientType.TO, new InternetAddress(EMAIL_TO));
			if (chkGetCopy.isSelected())
				msg.addRecipient(RecipientType.CC,
						new InternetAddress(txtMail.getText()));
			msg.setSubject(EMAIL_SUBJECT);

			// Build multipart
			Multipart multipart = new MimeMultipart();

			// aei_output.log (live from string)
			MimeBodyPart mimeBody = new MimeBodyPart();
			DataSource source = new StringDataSource(LogPrintStream
					.getInstance().getLog());
			mimeBody.setDataHandler(new DataHandler(source));
			mimeBody.setFileName("aei_output.log");
			multipart.addBodyPart(mimeBody);

			// updater_output.log
			File f = new File(Paths.getInstallerPath(), "updater_output.log");
			if (f.exists()) {
				mimeBody = new MimeBodyPart();
				source = new FileDataSource(f);
				mimeBody.setDataHandler(new DataHandler(source));
				mimeBody.setFileName("updater_output.log");
				multipart.addBodyPart(mimeBody);
			} else {
				msgText.append("updater_output.log does not exist!\n");
			}

			// Initialization.log
			f = new File(Paths.getInstallerPath(), "Initialization.log");
			if (f.exists()) {
				mimeBody = new MimeBodyPart();
				source = new FileDataSource(f);
				mimeBody.setDataHandler(new DataHandler(source));
				mimeBody.setFileName("Initialization.log");
				multipart.addBodyPart(mimeBody);
			} else {
				msgText.append("Initialization.log does not exist!\n");
			}

			// Installation.log
			f = new File(Paths.getInstallerPath(), "Installation.log");
			if (f.exists()) {
				mimeBody = new MimeBodyPart();
				source = new FileDataSource(f);
				mimeBody.setDataHandler(new DataHandler(source));
				mimeBody.setFileName("Installation.log");
				multipart.addBodyPart(mimeBody);
			} else {
				msgText.append("Installation.log does not exist!\n");
			}

			// startup.txt
			f = new File(Paths.getEditionBasePath(), "startup.txt");
			if (f.exists()) {
				mimeBody = new MimeBodyPart();
				source = new FileDataSource(f);
				mimeBody.setDataHandler(new DataHandler(source));
				mimeBody.setFileName("startup.txt");
				multipart.addBodyPart(mimeBody);
			} else {
				msgText.append("startup.txt does not exist!\n");
			}

			// debugger.txt
			f = new File(Paths.getEditionBasePath(), "debugger.txt");
			if (f.exists()) {
				mimeBody = new MimeBodyPart();
				source = new FileDataSource(f);
				mimeBody.setDataHandler(new DataHandler(source));
				mimeBody.setFileName("debugger.txt");
				multipart.addBodyPart(mimeBody);
			} else {
				msgText.append("debugger.txt does not exist!\n");
			}

			// File list (live from string)
			StringBuffer fileList = new StringBuffer();
			int baseLength = Paths.getEditionBasePath().getAbsolutePath()
					.length();
			IOFileFilter svnDirFilter = new NameFileFilter(
					new String[] { ".svn" });
			IOFileFilter notFilter = new NotFileFilter(svnDirFilter);
			Pattern packagePattern = Pattern.compile(
					".*/packages/[0-9]{5}[^/]*/.+", Pattern.CASE_INSENSITIVE);
			for (File flF : FileUtils.listFilesAndDirs(
					Paths.getEditionBasePath(), TrueFileFilter.INSTANCE,
					notFilter)) {
				String name = flF.getAbsolutePath().substring(baseLength);
				name = name.replace('\\', '/');
				if (!packagePattern.matcher(name).matches())
					fileList.append(name + "\n");
			}

			mimeBody = new MimeBodyPart();
			source = new StringDataSource(fileList.toString());
			mimeBody.setDataHandler(new DataHandler(source));
			mimeBody.setFileName("filelist.txt");
			multipart.addBodyPart(mimeBody);

			// Build text part
			msgText.append("\n\nMessage:\n" + txtMessage.getText());
			mimeBody = new MimeBodyPart();
			mimeBody.setText(msgText.toString());
			multipart.addBodyPart(mimeBody, 0);

			msg.setContent(multipart);

			Transport.send(msg);

			return true;
		} catch (AuthenticationFailedException e) {
			e.printStackTrace();
		} catch (MessagingException e) {
			e.printStackTrace();
		}
		return false;
	}
}
