package usda.weru.util;

import de.schlichtherle.truezip.file.TFile;
import java.awt.Cursor;
import java.awt.EventQueue;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.DecimalFormat;
import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; 
import usda.weru.util.wepsFileChooser2.WepsFileChooser2;
import usda.weru.util.wepsFileChooser2.WepsFileTypes2;
import usda.weru.weps.RunFileData;
import usda.weru.weps.Weps;
import usda.weru.util.mantis.WepsMantis;
import usda.weru.util.mantis.WepsMantisData;

/**
 *
 * @author wjr
 */
public class Mantis extends usda.weru.util.gui.Mantis_n {

    private static final long serialVersionUID = 1L;

    private static final Logger LOGGER = LogManager.getLogger(Mantis.class);
    private String maxSize = "10";
    private RunFileData c_rfd;
    private String addDirectoryButton = "0";
    DefaultListModel<String> DLM_files = new DefaultListModel<>();
    private Thread c_sendingThread;
    
    WepsMantis wepsMantis;

    
    public Mantis() {
        this (null);
    }
    
    public Mantis(String[] fileList) {
        this (Weps.getInstance().rfd, 
              fileList,
              ConfigData.getDefault().getDataParsed(ConfigData.AddDirectoryButton)
              );
        
    }
    
    public Mantis(RunFileData rfd, 
                           String[] fileList, 
                           String addDirectoryButton) {
        super(addDirectoryButton);
                    
        c_rfd = rfd;
        JTF_email.setText(ConfigData.getDefault().getDataParsed(ConfigData.MantisEmail));
        maxSize = ConfigData.getDefault().getDataParsed(ConfigData.MantisMaxSize);
        
        
        
        wepsMantis = new WepsMantis(this, ConfigData.getDefault().getDataParsed(ConfigData.MantisURL));

        try {
            Util.logMemoryUsage();
            ConfigData.getDefault().logConfiguration();

            try {
                java.io.File tmpFile = TFile.createTempFile(About.getLog().getName(), ".txt");
                TFile defFile = new TFile(tmpFile.getCanonicalPath());
                TFile.cp(About.getLog(), defFile);//old:defFile.copyFrom(About.getLog());

                if (defFile.exists()) {
                    // check that this file exists, else inform the user
                    DLM_files.addElement(defFile.getCanOrAbsPath());
                } else {
                    JOptionPane.showMessageDialog(null, 
                            "The log file:\n"
                            + defFile 
                            + "\ncould not be found and will not be included\n" 
                            + "in the bug report."
                            , "FILE NOT FOUND", JOptionPane.ERROR_MESSAGE);
                }

                if (new TFile(About.getUserConfig()).exists()) {
                    // check that this file exists, else inform the user
                    DLM_files.addElement(About.getUserConfig().getCanOrAbsPath());
                } else {
                    JOptionPane.showMessageDialog(null, 
                            "The file:\n"
                            + About.getUserConfig() 
                            + "\ncould not be found and will not be included\n" 
                            + "in the bug report."
                            , "FILE NOT FOUND", JOptionPane.ERROR_MESSAGE);
                }
            } catch (IOException ex) {
                LogManager.getLogger(Mantis.class).error("IOException", ex);
            }
            
            if (fileList != null) {
                for (String fileName : fileList) {
                    if(fileName == null) continue;
                    TFile file = new TFile(fileName);
                    if(!file.exists()) continue;
                    DLM_files.add(0, fileName);
                }
            }
        } catch (NullPointerException npe) {
        }
        JL_files.setModel(DLM_files);
    }
    
    private void addMessageData () {
        
        WepsMantisData mantisData = new WepsMantisData();
        
        // user info
        mantisData.user = ConfigData.getDefault().getData(ConfigData.UserFullName);
        mantisData.usrEmail  = JTF_email.getText();
        
        // fill in issue details
        mantisData.project = ConfigData.getDefault().getDataParsed(ConfigData.MantisProject);
        mantisData.subject = JTF_subject.getText();
        mantisData.description = (JTA_description.getText() == null || JTA_description.getText().trim().length() == 0) ? 
                                "Weps field bug report" : JTA_description.getText();
        mantisData.notify = JXB_notify.isSelected();
        
        // get system info
        mantisData.javaVer = About.getJava();
        mantisData.os = About.getOS();
        mantisData.osVer = About.getOSVersion();
        mantisData.platform = About.getPlatform();
        mantisData.buildNum = About.getBuildNumber() + " ";
        mantisData.category = "Weps GUI";
        // easier to not use this parameter
        // if used, the appropriate version must be manually entered
        // into the Mantis system each time a new version is released.
        // The Mantis API uses version to connect to Mantis
        // If the version is not found in our Mantis db, the connection fails.
        // mantisData.version = About.getVersion();
        
        // add the version here for reference
        // adding it here does not matter for API
        mantisData.description = "Weps GUI version:. "+About.getVersion()+"\n"
                                 +mantisData.description;
        // Not sure this will always be the cfg dir though, but currently no cfg params for it
        //mantisData.cfgDir = (new java.io.File("cfg").exists()) ? "cfg" : null;
        
        mantisData.attachFiles = DLM_files;
        wepsMantis.setMantisData(mantisData);
    }

    private boolean sendMessage() {
        addMessageData();
        return wepsMantis.sendMessage();
    }


    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);
    }
    
    
    // form handlers
    private void cancelAction() {
        if (c_sendingThread != null) {
            c_sendingThread.interrupt();
            setProgressBarString("Canceling...");
            setSendingStatus(false);
        } else {
            dispose();
        }
    }

    private void sendAction() {
        //require an email address
        String email = JTF_email.getText();
        if (!Util.isValidEmail(email)) {
            JOptionPane.showMessageDialog(this, "A valid email address is required.",
                    "Email Required", JOptionPane.ERROR_MESSAGE);
            JTF_email.selectAll();
            JTF_email.requestFocusInWindow();
            return;
        }

        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();

    }


    protected 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() {
        WepsFileChooser2 wfc = new WepsFileChooser2(WepsFileTypes2.Run, ".", WepsFileChooser2.Action.Open);
        wfc.disableNewFolder(wfc);
        String path = c_rfd != null ? c_rfd.getData(RunFileData.RunsLocation) : null;
        if (path != null && path.length() > 0) {
            wfc.setCurrentDirectory(path);
        }
        if (wfc.showDialog(this) == WepsFileChooser2.APPROVE_OPTION) {
            try {
                // //System.out.println("Selecting a project directory location");
                DLM_files.addElement(wfc.getSelectedFile().getCanonicalPath());
            } catch (IOException ex) {
                LOGGER.error(ex);
            }
        }
    }

    private void addFile() {
        WepsFileChooser2 wfc = new WepsFileChooser2(WepsFileTypes2.File, ".", WepsFileChooser2.Action.Open);
        wfc.disableNewFolder(wfc);
        String path = ConfigData.getDefault().getDataParsed(ConfigData.CurrentProj);
        if (path != null && path.length() > 0) {
            wfc.setCurrentDirectory(path);
        }
        System.out.println("Path: " + path);
        if (wfc.showDialog(this) == WepsFileChooser2.APPROVE_OPTION) {
            try {
                // //System.out.println("Selecting a project directory location");
                System.out.println("Selected File: " + wfc.getSelectedFile());
                DLM_files.add(1, wfc.getSelectedFile().getCanonicalPath());
            } catch (IOException ex) {
                LOGGER.error(ex);
            }
        }
    }
    
    //add a directory
    //need to make it allow a directory as an attachment 10MB maximum
    private void addDirectory(){
	    DecimalFormat df = new DecimalFormat("#.###");
        WepsFileChooser2 wfc = new WepsFileChooser2(WepsFileTypes2.Dir, ".", WepsFileChooser2.Action.Open);
        String path = ConfigData.getDefault().getDataParsed(ConfigData.ProjDir);
        if (path != null && path.length() > 0) {
            wfc.setCurrentDirectory(path);
        }
        if (wfc.showDialog(this) == WepsFileChooser2.APPROVE_OPTION ) {
            try {
                long size = getAllFiles(wfc.getSelectedFile(),0);
                //System.out.println("Selected File: " + wfc.getSelectedFile());
                if(wfc.getSelectedFile().getCanonicalPath().endsWith("Documents")){
                    JFrame frame = new JFrame();
                    JOptionPane.showMessageDialog(frame,"Directory must be smaller than "+maxSize+"MB", "Warning",JOptionPane.WARNING_MESSAGE);
                }
                    
                else if(size < (Float.parseFloat(maxSize)*1000000.0)){
                    DLM_files.addElement(wfc.getSelectedFile().getCanonicalPath());
                }
                else{
                    //create popup telling user their directory is too large
                    JFrame frame = new JFrame();
                    JOptionPane.showMessageDialog(frame, "Directory size "+df.format(size/1000000.0)+"MB too large, must be less than "+maxSize+"MB", "Warning", JOptionPane.WARNING_MESSAGE);
                }

            } catch (IOException ex) {
                LOGGER.error(ex);
            }
        }
    }

    private long getAllFiles(File dir, long totsize) {
		File[] files = dir.listFiles();
                if(files!=null){
		for (File file : files) {
			if (file.isDirectory()) {
				totsize += getAllFiles(file, 0);
			} 
                        else {
                                totsize += file.length();
                               
			}
			}
                }
        return totsize;
    }
    

    private void addProject() {
        WepsFileChooser2 wfc = new WepsFileChooser2(WepsFileTypes2.Project, ".", WepsFileChooser2.Action.Open);
        wfc.disableNewFolder(wfc);
        String path = ConfigData.getDefault().getDataParsed(ConfigData.ProjDir);
        if (path != null && path.length() > 0) {
            wfc.setCurrentDirectory(path);
            
        }
        if (wfc.showDialog(this) == WepsFileChooser2.APPROVE_OPTION) {
            try {
                // //System.out.println("Selecting a project directory location");
                DLM_files.addElement(wfc.getSelectedFile().getCanonicalPath());
            } catch (IOException ex) {
                LOGGER.error(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();
        } else if (src == JB_addDirectory){
            addDirectory();
        }
        
    }

    @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 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) {

        final Mantis mantis = new Mantis(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);
                }

            });
        }
    }
}
