/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package usda.weru.util;

import de.schlichtherle.io.File;
import java.awt.Cursor;
import java.awt.EventQueue;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.LinkedList;
import java.util.List;
import javax.swing.DefaultListModel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import org.apache.log4j.Logger;
import org.mantisbt.connect.MCException;
import org.mantisbt.connect.axis.MCSession;
import org.mantisbt.connect.model.CustomFieldValue;
import org.mantisbt.connect.model.IProject;
import org.mantisbt.connect.model.IssueAttachment;
import org.mantisbt.connect.model.MCAttribute;
import org.mantisbt.connect.ui.DefaultSubmitter;
import usda.weru.weps.RunFileData;
import usda.weru.weps.Weps;

/**
 *
 * @author wjr
 */
public class Mantis extends usda.weru.util.gui.Mantis_n {
    private static final org.apache.log4j.Logger LOGGER = org.apache.log4j.Logger.getLogger(Mantis.class);
    private String url = "";
    private String user = "";
    private String password = "";
    private String category = "";
    private String project = "triage";
    private RunFileData c_rfd;
    DefaultListModel DLM_files = new DefaultListModel();
    private Thread c_sendingThread;

    public Mantis(RunFileData rfd, String url, String email, String user, String password, String category, String[] fileList) {
            this(rfd, url, email, user, password, category, "triage", fileList);
    }

    public Mantis(RunFileData rfd, String url, String email, String user, String password, String category,String project, String[] fileList) {
        super();
        c_rfd = rfd != null ? rfd : Weps.getInstance().rfd;
        this.url = url;
        this.user = user;
        this.password = password;
        this.category = category;
        this.project = project;
        JTF_email.setText(email);
        try {
//            String defFile = About.getLog().getCanOrAbsPath();
            Util.logMemoryUsage();
            ConfigData.getDefault().logConfiguration();
            
            try {
                java.io.File tmpFile = File.createTempFile(About.getLog().getName(), ".txt");
                File defFile = new File(tmpFile.getCanonicalPath());
                defFile.copyFrom(About.getLog());
                DLM_files.addElement(defFile.getCanOrAbsPath());
            } catch (IOException ex) {
                Logger.getLogger(Mantis.class).error("IOException", ex);
            }
            if(fileList != null){
                for(String fileName : fileList){
                    DLM_files.add(0, fileName);
                }
            }
        } catch (NullPointerException npe) {
            DLM_files.addElement("c:/weps.svn/weps1.install/stdout.txt");
            DLM_files.addElement("c:/weps.svn/weps1.install/stderr.txt");
            DLM_files.addElement("c:/weps.svn/weps1.install/projects/lastproj.txt");
        }
        JL_files.setModel(DLM_files);
    }

    private boolean sendMessage() {
        MCSession session = null;
        try {            
                setProgressBarString("Connecting...");
                Thread.yield();
                session = new MCSession(new URL(url), user, Util.decrypt(password, "4raf9AxU"));
                IProject proj = session.getProject(project != null ? project : "triage");
                return addIssue(session, proj.getId(), category != null ? category : "");            
        }
        catch (MalformedURLException ex) {
            JOptionPane.showMessageDialog(rootPane, "Manti URL is malformed:\n" + (url != null ? url : "NULL") + "\nCheck your mantis settings.", "Malformed URL Error", JOptionPane.ERROR_MESSAGE);
            Logger.getLogger(Mantis.class).warn("malformed url" + url, ex);
            return false;
        }
        catch (MCException ex) {
            JOptionPane.showMessageDialog(rootPane, "Unable to connect to the mantis web service.\nCheck your internet and mantis settings and try again.", "Mantis Connection Error", JOptionPane.ERROR_MESSAGE);
            Logger.getLogger(Mantis.class).warn(null, ex);
            return false;
        }
    }

    private boolean addIssue(MCSession session, long projectID, String category) {
        org.mantisbt.connect.model.IIssue issue = null;
        try {
            issue = session.newIssue(projectID);
        } catch (MCException ex) {
            Logger.getLogger(Mantis.class).error(null, ex);
        }

        if(issue == null){
            LOGGER.error("Unable to create Mantis issue.");
            return false;
        }
        

        // fill in issue details
        issue.setCategory(category);
        issue.setSummary(JTF_subject.getText());
        String desc = JTA_description.getText();
        desc = (desc == null || desc.trim().length() == 0) ? "no description" : desc;
        issue.setDescription(desc);

        // get system info
        issue.setAdditionalInformation(About.getJava());
        issue.setOs(About.getOS());
        issue.setOsBuild(About.getOSVersion());
        issue.setPlatform(About.getPlatform());
        issue.setVersion(About.getVersion());
        issue.setBuild(About.getBuildNumber() + " ");

        // attach file(s)
        setProgressBarString("Preparing attachments...");
        Thread.yield();
        List<java.io.File> tempFiles = new LinkedList<java.io.File>();
        IssueAttachment[] iaa = new IssueAttachment[DLM_files.getSize()];
        for (int idx = 0; idx < DLM_files.getSize(); idx++) {
            if(Thread.interrupted()){
                return false;
            }
            IssueAttachment ia = new IssueAttachment();
//            File sendFile = new File((String) lm.getElementAt(idx));
            String fileName = (String) DLM_files.getElementAt(idx);
            java.io.File sendFile;
            if(fileName.toLowerCase().endsWith(".log")){
                 sendFile = new java.io.File(fileName);
            }
            else if (fileName.toLowerCase().endsWith(".zip")){
                //already zipped.
                sendFile = new java.io.File(fileName);
            }
            else{
                //store all the zip files we create
                 sendFile = Util.makeZipFile(fileName);
                 tempFiles.add(sendFile);
            }
            
            try {
                ia.setFilename(sendFile.getCanonicalPath());
            } catch (IOException ex) {
                Logger.getLogger(Mantis.class).error( null, ex);
            }
            ia.setContentType(org.mantisbt.connect.Utilities.getMimeType(sendFile));
            iaa[idx] = ia;
        }
        issue.setAttachments(iaa);

        // add return email
        setProgressBarString("Preparing message...");
        Thread.yield();
        CustomFieldValue[] cfvs = new CustomFieldValue[3];
        MCAttribute name = new MCAttribute(3, "name");
        cfvs[0] = new CustomFieldValue(name, ConfigData.getDefault().getData(ConfigData.UserFullName));

        MCAttribute email = new MCAttribute(1, "email");
        cfvs[1] = new CustomFieldValue(email, JTF_email.getText());

        MCAttribute notification = new MCAttribute(2, "Notification");
        cfvs[2] = new CustomFieldValue(notification, JXB_notify.isSelected() ? "Released" : "0");
        issue.setCustomFields(cfvs);

        if(Thread.interrupted()){
            return false;
        }
        DefaultSubmitter ds = new DefaultSubmitter(false);
        try {
            setProgressBarString("Sending...");
            JB_cancel.setEnabled(false);
            Thread.yield();
            long id = ds.submitIssue(session, issue);
            return true;
//            ds.submitAttachment(session, id, iaa[0]);
        } catch (MCException ex) {
            JOptionPane.showMessageDialog(rootPane, "Unable to connect to the mantis web service.\nCheck your internet and mantis settings and try again.", "Mantis Connection Error", JOptionPane.ERROR_MESSAGE);
            Logger.getLogger(Mantis.class).error("Error submitting mantis message.", ex);
        }
        finally{
            JB_cancel.setEnabled(true);
            for (java.io.File file : tempFiles){
                boolean deleted = file.delete();
                if(!deleted){
                    Logger.getLogger(Mantis.class).warn("Unable to delete temporary file: \"" + file.getAbsolutePath() + "\".  Will attempt to delete on exit." );
                    file.deleteOnExit();
                }
            }
        }

        return false;
    }

    // form handlers
    private void cancelAction() {
        if (c_sendingThread != null){
            c_sendingThread.interrupt();
            setProgressBarString("Canceling...");
            setSendingStatus(false);
        }
        else{
            dispose();
        }
    }

    private void sendAction() {
        setSendingStatus(true);
        c_sendingThread = new Thread("Sending Mantis Message"){

            @Override
            public void run() {
                try{
                    boolean sent = sendMessage();
                    if(sent){
                        setSendingStatus(false);
                        JOptionPane.showMessageDialog(Mantis.this, "Message Sent", "Mantis", JOptionPane.INFORMATION_MESSAGE);
                        dispose();                        
                    }
                }                
                finally{
                    c_sendingThread = null;
                    setSendingStatus(false);                    
                }
            }
        };

        c_sendingThread.start();

        
    }

    private void setProgressBarString(final String text){
        if(!EventQueue.isDispatchThread()){
            LOGGER.trace("Rerouting to EDT.");
            EventQueue.invokeLater(new Runnable() {

                @Override
                public void run() {
                    setProgressBarString(text);
                }
            });
            return;
        }

        progressBar.setString(text);
    }

    private void setSendingStatus(final boolean sending){
        if(!EventQueue.isDispatchThread()){
            LOGGER.trace("Rerouting to EDT.");
            EventQueue.invokeLater(new Runnable() {

                @Override
                public void run() {
                    setSendingStatus(sending);
                }
            });
            return;
        }

        progressBar.setIndeterminate(sending);
        progressBar.setStringPainted(sending);
        JB_send.setEnabled(!sending);
        JTA_description.setEnabled(!sending);
        if(sending){
            setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
            JB_cancel.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
            JB_cancel.setText("Cancel");
        }
        else{
            setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
            JB_cancel.setText("Close");
        }

    }

    private void addRun() {
        WepsFileChooser wfc = new WepsFileChooser(WepsFileChooser.RUN, ".",WepsFileChooser.OPEN);
        wfc.disableNewFolder(wfc);
        String path = c_rfd != null ? c_rfd.getData(RunFileData.RunsLocation) : null;
        if (path != null && path.length() > 0){
            wfc.setCurrentDirectory(new File(path));
        }
        if (wfc.showDialog(this) == WepsFileChooser.APPROVE_OPTION) {
            try {
                // //System.out.println("Selecting a project directory location");
                DLM_files.addElement(wfc.getSelectedFile().getCanonicalPath());
            } catch (IOException ex) {
                Logger.getLogger(Mantis.class).error( null, ex);
            }
        }
    }

    private void addFile() {
        WepsFileChooser wfc = new WepsFileChooser(WepsFileChooser.FILE, ".",WepsFileChooser.OPEN);
        wfc.disableNewFolder(wfc);
        String path = ConfigData.getDefault().getDataParsed(ConfigData.CurrentProj);
        if (path != null && path.length() > 0){
            wfc.setCurrentDirectory(new File(path));
        }
        if (wfc.showDialog(this) == WepsFileChooser.APPROVE_OPTION) {
            try {
                // //System.out.println("Selecting a project directory location");
                DLM_files.addElement(wfc.getSelectedFile().getCanonicalPath());
            } catch (IOException ex) {
                Logger.getLogger(Mantis.class).error( null, ex);
            }
        }
    }

    private void addProject() {
        WepsFileChooser wfc = new WepsFileChooser(WepsFileChooser.PROJECT, ".",WepsFileChooser.OPEN);
        wfc.disableNewFolder(wfc);
        String path = ConfigData.getDefault().getDataParsed(ConfigData.ProjDir);
        if (path != null && path.length() > 0){
            wfc.setCurrentDirectory(new File(path));
        }
        if (wfc.showDialog(this) == WepsFileChooser.APPROVE_OPTION) {
            try {
                // //System.out.println("Selecting a project directory location");
                DLM_files.addElement(wfc.getSelectedFile().getCanonicalPath());
            } catch (IOException ex) {
                Logger.getLogger(Mantis.class).error( null, ex);
            }
        }
    }

    private void deleteItem() {
        int idx = JL_files.getSelectedIndex();
        if (idx < 0) {
            JOptionPane.showMessageDialog(this, "Nothing selected");
        } else {
            DLM_files.remove(idx);
        }
    }

    @Override
    protected void globalActionPerformed(java.awt.event.ActionEvent evt) {
        Object src = evt.getSource();
        if (src == JB_cancel) {
            cancelAction();
        } else if (src == JB_send) {
            sendAction();
        } else if (src == JB_addRun) {
            addRun();
        } else if (src == JB_addFile) {
            addFile();
        } else if (src == JB_addProject) {
            addProject();
        } else if (src == JB_delete) {
            deleteItem();
        }
    }

    @Override
    protected void globalFocusGained(java.awt.event.FocusEvent evt) {
        Object src = evt.getComponent();
        if (src instanceof JTextField) {
            JTextField jtf = (JTextField) src;
            jtf.setSelectionStart(0);
            jtf.setSelectionEnd(1000);
        }
    }

    public static void main(String[] args) {
        
        Mantis cvm = new Mantis(null, "http://weru.ksu.edu/mantis/api/soap/mantisconnect.php",
                "nobody@nowhere.com",
                "test",
                "password",
                "data",
                null);
        cvm.setVisible(true);

   }

   public static void error(String subject, Throwable error, String... attachments){
       StringWriter buffer = new StringWriter();
       error.printStackTrace(new PrintWriter(buffer));
       Mantis.message(subject, error.getMessage() + "\n" + buffer.toString(), attachments);
   }

   public static void message(String subject, String body, String... attachments){
        ConfigData config = ConfigData.getDefault();
        String mantisURL = config.getDataParsed(ConfigData.MantisURL);
        String mantisEmail = config.getDataParsed(ConfigData.MantisEmail);
        String mantisUser = config.getDataParsed(ConfigData.MantisUser);
        String mantisPassword = config.getDataParsed(ConfigData.MantisPassword);
        String mantisProject = config.getDataParsed(ConfigData.MantisProject);

        final Mantis mantis = new Mantis(null, mantisURL, mantisEmail, mantisUser, mantisPassword, "default", mantisProject, attachments);
        mantis.JTF_subject.setText(subject);
        mantis.JTA_description.setText(body);

        if(SwingUtilities.isEventDispatchThread()){
            mantis.setVisible(true);
        }
        else{
            SwingUtilities.invokeLater(new Runnable(){

                @Override
                public void run() {
                    mantis.setVisible(true);
                }

            });
        }
    }
}
