/*
 * SoilChooser.java
 *
 * Created on April 18, 2007, 9:58 AM
 *
 */
package usda.weru.soil;

import usda.weru.util.tree.WepsTreeModelSoil;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeSupport;
import de.schlichtherle.truezip.file.TFile;
import java.awt.EventQueue;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.ProgressMonitor;
import javax.swing.SwingUtilities;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; 
import org.openide.util.Exceptions;
import usda.weru.soil.gui.SoilChooser_n;
import usda.weru.util.ConfigData;
import usda.weru.util.tree.LazyLoadingTreeController;
import usda.weru.util.WepsMessage;
import usda.weru.util.WepsMessageDialog;
import usda.weru.util.WepsMessageLog;
import usda.weru.util.tree.WepsTreeNodeSoil;
import usda.weru.util.wepsFileChooser2.WepsFileChooser2;
import usda.weru.weps.RunFileData;

/**
 *
 * @author Joseph Levin
 */
public class SoilChooser extends SoilChooser_n {

    private static final long serialVersionUID = 1L;

    private static final Logger LOGGER = LogManager.getLogger(SoilChooser.class);
    private TFile c_projectDirectory;
    private WepsTreeModelSoil c_model;
    private PropertyChangeSupport c_changes;
    private Soil c_soil;
    private boolean useTempFile;
    private TFile soilFile;
    public static String PropSoilChooserNewFile = "property_SoilChooserNewFile";


    public SoilChooser() {
        init();
    }

    public SoilChooser(Frame parent, TFile projectDirectory, TFile soilFile, PropertyChangeSupport changes) {
        super(parent);
        LOGGER.debug("creating soil chooser");
        init();
        c_projectDirectory = projectDirectory;
        //setRootFile(soilFile);
        c_changes = changes;
        if (parent instanceof Soil) {
            c_soil = (Soil) parent;
        }
    }

    public void setUseTempFile(boolean temp) {
        this.useTempFile = true;
    }

    @Override
    protected void formWindow_closed(java.awt.event.WindowEvent evt) {
    }

    private void init() {
        setModal(true);
        c_model = new WepsTreeModelSoil(null, true);
        c_model.configurePropertyChangeListeners();
        g_tree.setModel(c_model);
        new LazyLoadingTreeController(g_tree);
        g_tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
        g_tree.expandPath(c_model.getPathToTemplates());
        g_tree.setRootVisible(false);
        setTitle("Select Soil");
    }

    /**
     * Makes the soil data mart folder the currently selected folder.
     * 
     * NOTE:  any change to the folders in the soil chooser will probably make this
     * need to change values.
     */
    public void setSelected()
    {
        g_tree.setSelectionRow(5);
    }
    
    public void setProjectDirectory(TFile dir) {
        c_projectDirectory = dir;
    }

    public void setChanges(PropertyChangeSupport changes) {
        c_changes = changes;
    }

    public static void main(String args[]) {
        WepsFileChooser2 jfc = new WepsFileChooser2("");
        jfc.setMultiSelectionEnabled(false);
        jfc.setFileSelectionMode(WepsFileChooser2.SelectionType.DIRECTORIES_ONLY);
        final SoilChooser sc = new SoilChooser();
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                sc.setVisible(true);
            }
        });
        int result = jfc.showDialog(sc);
        if (result == WepsFileChooser2.APPROVE_OPTION) {
            //sc.setRootFile(file);
            sc.setProjectDirectory(new TFile("."));
        }

    }

    private boolean isSoil(Object o) {
        if (o instanceof WepsTreeNodeSoil) {
            return true;
        } else if (o instanceof TreeNode) {
            TreeNode node = (TreeNode) o;
            if(c_model.getDatabases() == null) {
                System.err.println("ERROR: c_model database is null.");
                return false;
            }
            for (SoilDatabase database : c_model.getDatabases()) {
                if (database.isSoil(node)) {
                    System.out.println("This is a soil.");
                    return true;
                } else {
                    System.out.println("this is not a soil.");
                }
            }
        }
        return false;
    }

    @Override
    protected void treeValueChanged(TreeSelectionEvent evt) {
        Object o = evt.getPath().getLastPathComponent();
        g_selectButton.setEnabled(isSoil(o));
    }

    @Override
    protected void treeMouseClicked(java.awt.event.MouseEvent evt) {
        if (evt.getClickCount() == 2) {
            loadSelectedNode();
        }
    }

    public TFile getSoilFile() {
        if(soilFile != null) {
            return soilFile;
        } else {
            System.err.println("ERROR: No valid soil file was chosen.");
            return null;
        }
    }
    
    private void loadSelectedNode() {
        TreePath selectedPath = g_tree.getSelectionPath();
        if (selectedPath == null) {
            return;
        }
        Object o = selectedPath.getLastPathComponent();
        // MEH
        if (o instanceof WepsTreeNodeSoil) {
            WepsTreeNodeSoil soilNode = (WepsTreeNodeSoil)o;
            //System.err.println("soilNode level: " + soilNode.getLevel());
            if(soilNode.getLevel() == 1) {
                soilNode.loadChildren();
                return;
            }
            PropertyChangeSupport changes = c_changes;
            Thread task = new Thread("Selected Node Loader") {
                @Override
                public void run() {
                    setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.WAIT_CURSOR));
                    try {
                        ((WepsTreeNodeSoil)o).setDefaultDest(
                                    new File(ConfigData.getDefault().getDataParsed(ConfigData.SWEEPWorkDir)).toPath());
                        soilFile = ((WepsTreeNodeSoil)o).getNodeData();
                    } catch (IOException ex) {
                        Exceptions.printStackTrace(ex);
                    } finally {
                        changes.firePropertyChange(PropSoilChooserNewFile, null, soilFile);
                        setCursor(java.awt.Cursor.getDefaultCursor());
                        setVisible(false);
                    }

                }
            };
            task.start();
        } else if (o instanceof TreeNode) {
            final TreeNode node = (TreeNode) o;
            for (final SoilDatabase database : c_model.getDatabases()) {
                if (database.isSoil(node)) {
                    //Thread off the loading of the soil ifc with a progress monitor.
                    final ProgressMonitor progress = new ProgressMonitor(this, "Loading Soil Record", "", 0, 100);
                    progress.setMillisToDecideToPopup(0);
                    progress.setMillisToPopup(0);
                    Thread task = new Thread("Selected Node Loader") {
                        @Override
                        public void run() {
                            setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.WAIT_CURSOR));
                            try {
                                IFC ifc = database.getIfcFromNode(node, progress);
                                if (ifc != null) {
                                    //WepsMessageLog log = new WepsMessageLog();
                                    WepsMessageLog log = ifc.getLog();

                                    if (log.getCount(WepsMessage.MessageSeverity.ERROR) == 0) {
                                        if (c_soil != null) {
//                                            c_soil.ifcptr = ifc;
                                            c_soil.ifcptr.adjustIfc();
                                            c_soil.initializeGui(c_soil.ifcptr.getFileName());
                                            c_soil.setMenuEnable("Save", true);
                                            c_soil.setMenuEnable("Save As", true);
                                            c_soil.setMenuEnable("print", true);
                                        } else {
                                            // sends double errors to IFC file extracted from NASIS
                                            // ifc.sendErrorsToInternalVariable();
                                            if (useTempFile) {
                                                TFile temp = new TFile(TFile.createTempFile("soilchooser", ".ifc"));
                                                ifc.writeNewIfc(temp.getAbsolutePath(), c_changes);
                                                temp.deleteOnExit();
                                            } else {
                                                ifc.writeNewIfc(c_projectDirectory.getAbsolutePath(), c_changes);
                                            }
                                            c_changes.firePropertyChange(RunFileData.SoilRockFragments, null, "0.0");
                                            c_changes.firePropertyChange(RunFileData.AverageSlope, null, "-1");
                                        }
                                        //Ask the swing thread to hide the form
                                        SwingUtilities.invokeLater(new Runnable() {
                                            @Override
                                            public void run() {
                                                progress.close();
                                                //setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
                                                setVisible(false);
                                            }
                                        });
                                    } else { //We have errors to report
                                        if (!NASIS.getEstimateNullValues() && log.getCount(WepsMessage.MessageSeverity.ERROR) > 0) {
                                            WepsMessageDialog.showMessageList(null,
                                                    "Soil Record", c_projectDirectory.getAbsolutePath(),
                                                    log.getMessages(WepsMessage.MessageSeverity.ERROR));
                                        } else {
                                            WepsMessageDialog.showMessageList(null, "Soil Record",
                                                    c_projectDirectory.getAbsolutePath(),
                                                    log.getMessages(WepsMessage.MessageSeverity.ERROR,
                                                            WepsMessage.MessageSeverity.WARNING));
                                        }

                                    }
                                }
                            } catch (OrganicSoilException ose) {
                                //the soil being loaded
                                String message = ose.getMessage();
                                final JOptionPane pane = new JOptionPane(
                                        "The selected soil is not supported by the WEPS science model."
                                        + "  The high organic content may cause unexpected results."
                                        + (message != null ? "\n" + message + "\n" : "\n")
                                        + "Do you want to use the supplied organic soil substitute?\n"
                                        + "Note that selecting \"No\" will revert the soil to the previously selected record.",
                                        JOptionPane.WARNING_MESSAGE, JOptionPane.YES_NO_OPTION) {

                                            private static final long serialVersionUID = 1L;

                                            @Override
                                            public int getMaxCharactersPerLineCount() {
                                                return 80;
                                            }

                                        };

                                final JDialog dialog = pane.createDialog(SoilChooser.this, "Organic Soil");
                                try {
                                    EventQueue.invokeAndWait(new Runnable() {

                                        @Override
                                        public void run() {
                                            dialog.setVisible(true);
                                            int result = pane.getValue() != null
                                                    ? Integer.valueOf(pane.getValue().toString()) : JOptionPane.CANCEL_OPTION;
                                            if (result == JOptionPane.YES_OPTION) {
                                                //use the organic soil, close soil chooser
                                                c_changes.firePropertyChange(RunFileData.SoilFile, null,
                                                        ConfigData.getDefault().getDataParsed(ConfigData.SoilOrganicFile));
                                                SoilChooser.this.setVisible(false);

                                            } else {
                                                //do nothing, the SoilChooser remains open
                                            }
                                        }

                                    });
                                } catch (InterruptedException | InvocationTargetException e) {
                                    LOGGER.error("Unexpected error while waiting for the edt "
                                            + "to return from the organic soil prompt.", e);
                                }
                            } catch (IOException | ArithmeticException e) {
                                //some error loading the soil record.
                                progress.close();
                                JOptionPane.showMessageDialog(SoilChooser.this, "Unknown error while loading a soil record.",
                                        "Loading Error", JOptionPane.ERROR_MESSAGE);

                            } finally {
                                progress.close();
                                setCursor(java.awt.Cursor.getDefaultCursor());
                            }

                        }
                    };
                    task.start();

                    //This database was able to provide the soil,                     
                    break;
                }
            }
        }
    }

    @Override
    protected void cancelButtonActionPerformed(ActionEvent evt) {
        setVisible(false);
    }

    @Override
    protected void selectButtonActionPerformed(ActionEvent evt) {
        loadSelectedNode();
    }

    @Override
    protected void indexActionPerformed(java.awt.event.ActionEvent evt) {
        //setRootFile(c_rootFile);
    }
}
