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

import java.awt.Frame;
import java.awt.event.ActionEvent;
import de.schlichtherle.truezip.file.TFile;
import de.schlichtherle.truezip.file.TFileWriter;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.ProgressMonitor;
import javax.swing.SwingUtilities;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import org.apache.log4j.Logger;
import usda.weru.soil.JdbcSoilDatabase.ComponentNode;
import usda.weru.soil.JdbcSoilDatabase.LegendNode;
import usda.weru.soil.JdbcSoilDatabase.MapUnitNode;
import usda.weru.soil.gui.MassSoilChooser_n;
import usda.weru.util.ConfigData;
import usda.weru.util.LazyLoadingTreeController;
import usda.weru.util.WepsMessage;
import usda.weru.util.WepsMessageDialog;
import usda.weru.util.WepsMessageLog;
import usda.weru.weps.RunFileData;

/**
 *
 * @author Joseph Levin
 */
public class MassSoilChooser extends MassSoilChooser_n {

    private static final long serialVersionUID = 1L;

    private static final Logger LOGGER = Logger.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();
    }

    /**
     *
     * @param parent
     * @param projectDirectory
     * @param soilFile
     * @param changes
     */
    public MassSoilChooser(Frame parent) {
        super(parent);
        LOGGER.debug("creating soil chooser");
        init();
        //change g_tree component renderer to new checkbox componenet renderer thingy.
        //setRootFile(soilFile);
        updateNumbers();
    }

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

    private void init() {
        setModal(true);
        c_model = new MassSoilTreeModel();
        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 = ConfigData.getDefault().getData(ConfigData.LocalSoilDB);
        if(!destinationDirectory.endsWith(TFile.separator)) destinationDirectory += TFile.separator;
        destinationDirectoryField.setText(destinationDirectory);
    }

    /**
     * @param args the command line arguments
     */
    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(new Runnable() {
            @Override
            public void run() {
                sc.setVisible(true);
            }
        });

    }

    private void loadSelectedNodes() 
    {
        Thread task = new Thread("Soil Downloader")
        {
            int failures = 0;
            int files = 0;
            JdbcSoilDatabase database;
            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."); }
                final ProgressMonitor progress = new ProgressMonitor(MassSoilChooser.this, 
                        "Downloading Soil Records", "", 0, c_model.selected.size());
                progress.setMillisToDecideToPopup(0);
                progress.setMillisToPopup(0);
                int finished = 0;
                for(DefaultMutableTreeNode node : c_model.selected)
                {
                    if(canceled || progress.isCanceled()) break;
                    progress.setProgress(finished++);
                    if(node instanceof LegendNode)
                    {
                        database = ((LegendNode) node).getDatabase();
                        downloadLegend((LegendNode) node, destinationDirectory, progress);
                    }
                    else if(node instanceof MapUnitNode)
                    {
                        database = ((MapUnitNode) node).getDatabase();
                        downloadMapUnit((MapUnitNode) node, destinationDirectory, progress);
                    }
                    else if(node instanceof ComponentNode)
                    {
                        database = ((ComponentNode) node).getDatabase();
                        downloadComponent((ComponentNode) node, destinationDirectory, progress);
                    }
                }
                progress.close();
                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);
                }
                g_cancelButton.setEnabled(false);
            }
            
            private void downloadLegend(LegendNode node, String directory, ProgressMonitor progress)
            {
                if(canceled || progress.isCanceled()) return;
                try
                {
                    String legendName = (String) node.getUserObject();
                    directory += legendName + "/";
                    TFile legendDir = new TFile(directory);
                    if(!legendDir.exists()) legendDir.mkdir();
                    if(node.getChildrenLoaded())
                    {
                        MapUnitNode child = (MapUnitNode) node.getFirstChild();
                        while(child != null)
                        {
                            if(canceled || progress.isCanceled()) return;
                            downloadMapUnit(child, directory, progress);
                            child = (MapUnitNode) child.getNextSibling();
                        }
                    }
                    else
                    {
                        for(MutableTreeNode temp : node.createChildren())
                        {
                            if(canceled || progress.isCanceled()) return;
                            downloadMapUnit((MapUnitNode) temp, directory, progress);
                        }
                    }
                }
                catch(ClassCastException cce)
                {
                    LOGGER.error("Bad structure passed in.  A Legend node does not"
                            + "contain exclusively map unit nodes.");
                }
            }

            private void downloadMapUnit(MapUnitNode node, String directory, ProgressMonitor progress)
            {
                if(canceled || progress.isCanceled()) return;
                try
                {
                    String muName = (String) node.getUserObject();
                    directory += muName + "/";
                    TFile muDir = new TFile(directory);
                    if(!muDir.exists()) muDir.mkdir();
                    if(node.getChildrenLoaded())
                    {
                        ComponentNode child = (ComponentNode) node.getFirstChild();
                        while(child != null)
                        {
                            if(canceled || progress.isCanceled()) return;
                            downloadComponent(child, directory, progress);
                            child = (ComponentNode) child.getNextSibling();
                        }
                    }
                    else
                    {
                        for(MutableTreeNode temp : node.createChildren())
                        {
                            if(canceled || progress.isCanceled()) return;
                            downloadComponent((ComponentNode) temp, directory, progress);
                        }
                    }
                }
                catch(ClassCastException cce)
                {
                    LOGGER.error("Bad structure passed in.  A Legend node does not"
                            + "contain exclusively map unit nodes.");
                }
            }

            private void downloadComponent(ComponentNode node, String directory, ProgressMonitor progress)
            {
                if(canceled || progress.isCanceled()) return;
                String fileName = (String) node.getUserObject();
                String fileString = directory + fileName + ".ifc";
                TFile file = new TFile(fileString);
                System.out.println(file.getAbsolutePath());
                final ProgressMonitor progress2 = new ProgressMonitor(MassSoilChooser.this, 
                        "Downloading " + fileName, "", 0, 100);
                progress2.setMillisToDecideToPopup(0);
                progress2.setMillisToPopup(0);
                try
                {
                    files ++;
                    IFC soil = database.getIfcFromKnownNode(node, progress2);
                    if(soil != null)
                    {  
                        WepsMessageLog log = soil.getLog();
                        if (log.getCount(WepsMessage.MessageSeverity.ERROR) == 0) 
                        {
                            System.out.println("Writing");
                            soil.writeNewIfc(directory, null);
                        }
                        else 
                        { //We have errors to report
                            failures ++;
                            if (!NASIS.getEstimateNullValues() && log.getCount(
                                    WepsMessage.MessageSeverity.ERROR) > 0) 
                            {
                                System.out.println("Printing error");
                                if(errorsink != null)
                                {
                                    errorsink.println(fileName);
                                    List<WepsMessage> mess = log.getMessages(WepsMessage.MessageSeverity.ERROR);
                                    for(WepsMessage wm : mess)
                                    {
                                        errorsink.println(wm.getMessage());
                                    }
                                    errorsink.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
                                }
                            } 
                            else 
                            {
                                System.out.println("Printing error");
                                if(errorsink != null)
                                {
                                    errorsink.println(fileName);
                                    List<WepsMessage> mess = log.getMessages(WepsMessage.MessageSeverity.ERROR, WepsMessage.MessageSeverity.WARNING);
                                    for(WepsMessage wm : mess)
                                    {
                                        errorsink.println(wm.getMessage());
                                    }
                                    errorsink.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
                                }
                            }
                        }
                    }
                }
                catch(OrganicSoilException ose)
                {
                    failures ++;
                    System.out.println("OSE");
                    //the soil being loaded
                    if(errorsink != null)
                    {
                        String message = ose.getMessage();
                        errorsink.println(fileName);
                        errorsink.println("Soil Selection " 
                                + fileName + " is organic.  All organic soils will be "
                                + "replaced in the interface with this file: \n"
                                + ConfigData.getDefault().getData(ConfigData.SoilOrganicFile)
                                + "\nas specified in the Configuration Panel.");
                        errorsink.println(message != null ? message : "");
                        errorsink.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
                    }
                }
                catch(ArithmeticException exc)
                {
                    failures ++;
                    if(errorsink != null)
                    {
                        errorsink.println(fileName);
                        errorsink.println("Soil Selection " 
                                + fileName + " failed unexpectedly while waiting for the edt "
                                + "to return from the organic soil prompt.");
                        errorsink.println("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
                    }
                    LOGGER.error("Unexpected error while waiting for the edt "
                            + "to return from the organic soil prompt.", exc);
                }
                progress2.close();
            }
        };
        task.start();
    }

    /**
     *
     * @param evt
     */
    @Override
    protected void cancelButtonActionPerformed(ActionEvent evt) 
    {
        canceled = true;
//        setVisible(false);
    }

    /**
     *
     * @param evt
     */
    @Override
    protected void downloadButtonAction(ActionEvent evt) 
    {
        canceled = false;
        downloadButton.setEnabled(false);
        g_cancelButton.setEnabled(true);
        loadSelectedNodes();
    }

    /**
     *
     * @param evt
     */
    @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 = destinationDirectoryField.getText();
    }


    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;
            Object obj = node.getUserObject();          
            TreePath tp = new TreePath(node.getPath());
            boolean isChecked = c_model.pathSelected(tp);
            check.setSelected(isChecked);
            check.setText(obj.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());
            MassSoilChooser.this.repaint();
        }
    }
}
