
package usda.weru.soil;

import de.schlichtherle.truezip.file.TFile;
import de.schlichtherle.truezip.file.TFileWriter;

import java.awt.event.ActionEvent;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Paths;
import java.util.List;

import javax.swing.JCheckBox;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.ProgressMonitor;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; 

import usda.weru.remoteDataAccess.remoteFiles.dbFile.soil.SoilFile;
import usda.weru.soil.gui.MassSoilChooser_n;
import usda.weru.util.ConfigData;
import usda.weru.util.Util;
import usda.weru.util.WepsMessage;
import usda.weru.util.WepsMessageLog;
import usda.weru.util.tree.LazyLoadingTreeController;
import usda.weru.util.tree.WepsTreeNodeRemote;
import usda.weru.weps.Weps;

/**
 * MassSoilChooser.java
 *
 * Created on April 18, 2007, 9:58 AM
 * 
 * @author Joseph Levin
 */
public class MassSoilChooser extends MassSoilChooser_n {

    private static final long serialVersionUID = 1L;

    private static final Logger LOGGER = LogManager.getLogger(MassSoilChooser.class);
    private MassSoilTreeModel c_model;
    private String destinationDirectory = "unitialized";
    private boolean canceled = false;

    /** Creates a new instance of MassSoilChooser */
    public MassSoilChooser() {
        init();
        updateNumbers();
    }

    private void init() {
        c_model = new MassSoilTreeModel(null);
        Weps.getInstance().setMassSoilChooserSDM(true);
        c_model.configurePropertyChangeListeners();

        g_tree.setCellRenderer(new TreeCheckRenderer());
        g_tree.setModel(c_model);
        g_tree.addMouseListener(new Clicker());
        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");
        destinationDirectory = Util.parse(ConfigData.getDefault().getData(ConfigData.LocalSDMDB));
        if (!destinationDirectory.endsWith(TFile.separator)) {
            destinationDirectory += TFile.separator;
        }
        destinationDirectoryField.setText(destinationDirectory);
    }

    public static void main(String args[]) {
        ConfigData.getDefault().load(new TFile("./cfg/weps.cfg"), new TFile("/home/jonathanhornbaker/.weps/devWS_1.1.0/weps.cfg"));
        final MassSoilChooser sc = new MassSoilChooser();
        java.awt.EventQueue.invokeLater(() -> {
            sc.setVisible(true);
        });

    }

    private void loadSelectedNodes() {
        Thread task;
        task = new Thread("Soil Downloader") {
            int failures = 0;
            int files = 0;
            PrintWriter errorsink;

            @Override
            public void run() {
                try {
                    (new TFile(destinationDirectory + "errors.txt")).rm();
                } catch (IOException ioe) {

                }

                try {
                    errorsink = new PrintWriter(new TFileWriter(new TFile(destinationDirectory + "errors.txt")));
                } catch (FileNotFoundException fnfe) {
                    LOGGER.error("errors.txt file not found.");
                }

                totalProgress.setMinimum(0);
                totalProgress.setMaximum(c_model.selected.size());
                int finished = 0;

                for (DefaultMutableTreeNode node : c_model.selected) {
                    if (canceled) {
                        break;
                    }

                    totalProgress.setValue(finished++);
                    SoilFile value;

                    try {
                        value = (SoilFile) node.getUserObject();
                    } catch (ClassCastException cce) {
                        return;
                    }

                    totalProgress.setString(value.getName());
                    downloadNodeAndChildren(node, destinationDirectory);
                    totalProgress.setString("");
                }

                errorsink.close();
                errorsink = null;

                if (failures > 0) {
                    JOptionPane.showMessageDialog(MassSoilChooser.this, failures + " files failed to download."
                            + "\nTo see detailed messages, open the errors.txt file in the "
                            + destinationDirectory + " directory.", "Download Failures", JOptionPane.WARNING_MESSAGE);
                }
                totalProgress.setValue(0);
                totalProgress.setString("Completed");
                c_model.selected.clear();
                MassSoilChooser.this.repaint();
            }

            private void downloadNodeAndChildren(DefaultMutableTreeNode nonCastNode, String directory) {
                if (canceled) {
                    return;
                }

                try {
                    WepsTreeNodeRemote node = (WepsTreeNodeRemote) nonCastNode;

                    if (node.isLeaf()) {
                        if (JCB_printFullPath.isSelected()) {
                            String fullPath = node.getTreeNodePath();
                            String[] path = fullPath.split("/");
                            for (int index = 1; index < path.length; index++) {
                                directory += path[index] + TFile.separator;
                                TFile holdDir = new TFile(directory);

                                if (!holdDir.exists()) {
                                    holdDir.mkdir();
                                }
                            }
                        }
                        componentProgress.setString(node.toString());
                        node.getRemoteFileObj().setDestinationPath(Paths.get(directory));
                        try {
                            node.getNodeData(new ProgressBarWrapper());
                        } catch (IOException ex) {
                            // MEH check w Jonathan.
                        }

                        WepsMessageLog log = node.getNodeDataLog();
                        if (log.getCount() > 1) {
                            if (log.getCount(WepsMessage.MessageSeverity.ERROR) > 0) {
                                failures++;
                                System.out.println("Printing error");

                                if (errorsink != null) {
                                    errorsink.println(node.toString());
                                    List<WepsMessage> mess = log.getMessages(WepsMessage.MessageSeverity.ERROR);

                                    mess.forEach(wm -> {
                                        errorsink.println(wm.getMessage());
                                    });

                                    errorsink.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
                                }
                            }
                        }
                        componentProgress.setString("Completed");
                        componentProgress.setValue(0);
                    } else {
                        if (!JCB_printFullPath.isSelected()) {
                            directory += node.toString() + TFile.separator;
                            TFile holdDir = new TFile(directory);

                            if (!holdDir.exists()) {
                                holdDir.mkdir();
                            }
                        }

                        for (Object childObj : node.loadChildren()) {
                            WepsTreeNodeRemote child = (WepsTreeNodeRemote) childObj;
                            downloadNodeAndChildren(child, directory);
                        }
                    }
                } catch (ClassCastException cce) {
                    LOGGER.error("Bad structure passed in.  A Legend node does not"
                            + "contain exclusively map unit nodes.");
                }
            }
        };
        task.start();
    }
    
    protected void formWindowClosePerformed(ActionEvent evt) {
        canceled = true;
    }
    
    @Override
    protected void ExitButtonActionPerformed(ActionEvent evt) {
        canceled = true;
        this.dispose();
    }

    @Override
    protected void CancelAllButtonActionPerformed(java.awt.event.ActionEvent evt) {
        canceled = true;
    }
    

    @Override
    protected void downloadButtonAction(ActionEvent evt) {
        TFile dst = new TFile(destinationDirectory);
        if(!dst.exists()) {
            JOptionPane.showMessageDialog(this, "Invalid Destination Directory."
                    + "\nPlease create directory before downloading soil files.",
                    "InvlaidDirectory", JOptionPane.ERROR_MESSAGE);
            return;
        }
        canceled = false;
        downloadButton.setEnabled(false);
        exitButton.setEnabled(true);
        loadSelectedNodes();
    }

    @Override
    protected void indexActionPerformed(java.awt.event.ActionEvent evt) {
        //setRootFile(c_rootFile);
    }
    
    private void updateNumbers() {
        legendsNum.setText(Integer.toString(c_model.getNumLegend()));
        mapUnitsNum.setText(Integer.toString(c_model.getNumMapUnit()));
        componentsNum.setText(Integer.toString(c_model.getNumComponent()));
    }
    
    @Override
    protected void destinationDirectoryFieldUpdate() {
        destinationDirectory = Util.parse(destinationDirectoryField.getText());
    }

    @Override
    protected void clearSelection() {
        c_model.selected.clear();
        MassSoilChooser.this.repaint();
        clearSelectionButton.setEnabled(false);
        downloadButton.setEnabled(c_model.downloadReady());
            
    }

    private class TreeCheckRenderer extends JPanel implements TreeCellRenderer {

        public static final long serialVersionUID = 943789267L;

        private JCheckBox check;

        public TreeCheckRenderer() {
            super();
            this.setLayout(new BorderLayout());
            check = new JCheckBox();
            this.add(check, BorderLayout.CENTER);
            this.setOpaque(false);
        }

        @Override
        public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
            DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
            TreePath tp = new TreePath(node.getPath());
            boolean isChecked = c_model.pathSelected(tp);
            check.setSelected(isChecked);
            String temp = "fail";
            try {
                temp = ((WepsTreeNodeRemote) node).getTreeNodeName();
            } catch (ClassCastException cce) {
            }
            check.setText(node.toString());
            this.setOpaque(true);
            return this;
        }

    }
 
    private class Clicker extends MouseAdapter {
        @Override
        public void mouseClicked(MouseEvent evt) {
            TreePath tp = g_tree.getPathForLocation(evt.getX(), evt.getY());
            if(tp == null) return;
            c_model.selectPath(tp);
            updateNumbers();
            downloadButton.setEnabled(c_model.downloadReady());
            clearSelectionButton.setEnabled(!c_model.selected.isEmpty());
            MassSoilChooser.this.repaint();
        }
    }
    
    private class ProgressBarWrapper extends ProgressMonitor {
        public ProgressBarWrapper() { 
            this(null, null, null, 0, 0); 
        }
        
        public ProgressBarWrapper(Component parentComponent, Object message, String note, int min, int max) {
            super(parentComponent, message, note, min, max);
            this.close();
        }
        
        @Override
        public void setProgress(int input) { 
            componentProgress.setValue(input); 
        }
    }
}
