package usda.weru.util.tree;

import java.awt.EventQueue;
import de.schlichtherle.truezip.file.TFile;
import java.awt.Cursor;
import static java.awt.Cursor.getPredefinedCursor;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.FileFilter;
import java.util.LinkedList;
import java.util.List;
import javax.swing.tree.TreeNode;
import static usda.weru.remoteDataAccess.csip.CsipInputControllerCachingSupport.PROP_CSIP_BGCATALOG_COMPLETE;
import static usda.weru.remoteDataAccess.csip.CsipInputControllerCachingSupport.PROP_CSIP_BGCATALOG_STARTING;
import usda.weru.remoteDataAccess.csip.CsipLmodUtil;
import usda.weru.soil.SoilDatabase;
import usda.weru.util.About;
import usda.weru.util.ConfigData;
import usda.weru.util.wepsFileChooser2.WepsFileTypes2;
import usda.weru.weps.RunFileData;
import usda.weru.weps.Weps;
import static usda.weru.weps.gui.ConfigPanel_n.CSIP_SOIL_POLYGONSIZE_PROP;
import static usda.weru.remoteDataAccess.csip.crlmod.CsipInputContCrLmodBgCache.PROP_CSIP_BGFILLCACHE_COMPLETE_EXTERNAL;
import static usda.weru.weps.location.chooser.SiteChooser.PROP_SELECTED_SITE;

public class WepsTreeModelSoil extends WepsTreeModel implements PropertyChangeListener, FileFilter {

    private static final long serialVersionUID = 1L;

    private List<SoilDatabase> databases;
    
    public WepsTreeNodeSoilCsip csipSoilServiceNode;
//    private WepsTreeNodeSoilMdb mdbNode; - unused variable -EL
    private WepsTreeNodeFile csipSoilCacheNode;
    private WepsTreeNodeFile sysSoilDataFile;
    private WepsTreeNodeFile locSoilDataFile;
    private WepsTreeNodeFile locSoilDataMartFile;
    private WepsTreeNodeSoilSdm nrcsSDMNode;
    
    private boolean csipSoilServiceVisible;
    private boolean nrcsSoilDataMartVisible;
    private boolean systemSoilDataVisible;
    private boolean csipSoilCacheNodeVisible;
    private boolean localSoilDataVisible;
    private boolean localSoilDataMartVisible;
    
    public String nrcsSDMLocationSite;
    
    public WepsTreeModelSoil(WepsTreeComboBox treeCombo, boolean useWaitCursor) {
        this (treeCombo, true, true, useWaitCursor);
    }
    
    public WepsTreeModelSoil(WepsTreeComboBox treeCombo, boolean includeProjectNode, boolean includeTemplateNode, boolean useWaitCursor) {
        super(treeCombo, includeProjectNode, includeTemplateNode,useWaitCursor);
        
        csipSoilCacheNodeVisible = ConfigData.getDefault().getDataParsed(ConfigData.cachedCsipSoilDir_CB).contentEquals("1");
        systemSoilDataVisible = ConfigData.getDefault().getDataParsed(ConfigData.systemSoilDataDir_CB).contentEquals("1");
        localSoilDataVisible = ConfigData.getDefault().getDataParsed(ConfigData.localSoilDataDir_CB).contentEquals("1");
        localSoilDataMartVisible = ConfigData.getDefault().getDataParsed(ConfigData.localSoilDataMartDir_CB).contentEquals("1");
        csipSoilServiceVisible = ConfigData.getDefault().getDataParsed(ConfigData.csipSoilService_CB).contentEquals("1");
        nrcsSoilDataMartVisible = ConfigData.getDefault().getDataParsed(ConfigData.nrcsSoilDataMartURL_CB).contentEquals("1");
        
        sysSoilDataFile = new WepsTreeNodeFile(new TFile(ConfigData.getDefault().getDataParsed(ConfigData.SoilDB)), this);
        locSoilDataFile = new WepsTreeNodeFile(new TFile(ConfigData.getDefault().getDataParsed(ConfigData.LocalSoilDB)), this);
        locSoilDataMartFile = new WepsTreeNodeFile(new TFile(ConfigData.getDefault().getDataParsed(ConfigData.LocalSDMDB)), this);
        nrcsSDMNode = new WepsTreeNodeSoilSdm();
        csipSoilCacheNode = new WepsTreeNodeFileSoilCache (new TFile(About.getWepsCacheDir(), CsipLmodUtil.WepsCacheDirNameSoil), this);

        csipSoilServiceNode = null;
    }
    
    /**
     * PropertyChangeListeners are now added after the constructor to prevent any bugs with
     * "this" being referenced in inside of the constructor
     * 
     * Add property Change Listeners for all the check boxes in the Soil Configuration Panel
     * 
     * Additionally add a listener for changing the SDM sort method
     * 
     */
    public void configurePropertyChangeListeners() {
        
        if(Weps.getInstance() == null) {
            build(true);
            setUseWaitCursor(true);
        } else if(Weps.getInstance().getMassSoilChooserSDM()) {
            build(true);
            setUseWaitCursor(true);
        } else if(Weps.getInstance().getRunFileData() != null) {
            Weps.getInstance().getRunFileData().addPropertyChangeListener(RunFileData.StrLatLong, this);
            ConfigData.getDefault().addPropertyChangeListener(CSIP_SOIL_POLYGONSIZE_PROP, this);
            ConfigData.getDefault().addPropertyChangeListener(ConfigData.cachedCsipSoilDir_CB, this);
            ConfigData.getDefault().addPropertyChangeListener(ConfigData.systemSoilDataDir_CB, this);
            ConfigData.getDefault().addPropertyChangeListener(ConfigData.localSoilDataDir_CB, this);
            ConfigData.getDefault().addPropertyChangeListener(ConfigData.localSoilDataMartDir_CB, this);
            ConfigData.getDefault().addPropertyChangeListener(ConfigData.csipSoilService_CB, this);
            ConfigData.getDefault().addPropertyChangeListener(ConfigData.nrcsSoilDataMartURL_CB, this);
            Weps.getInstance().getLocationPanel().getSiteChooser().addPropertyChangeListener(PROP_SELECTED_SITE, this);
            ConfigData.getDefault().addPropertyChangeListener(ConfigData.SDMSoilSortMethod, this);
            ConfigData.getDefault().addPropertyChangeListener(ConfigData.SDMSoilSortOrder, this);
            build();
            setUseWaitCursor(true);
        }
    }

    @Override
    public void refresh() {
        build();
    }
    
    @Override
    public void build(boolean sweep) {
        super.build(false);
        databases = new LinkedList<>();
        nrcsSDMNode = new WepsTreeNodeSoilSdm();
        addNode(nrcsSDMNode);
//        try{
//            sdmNode.getNodeData();
//            //sdmNode.reInitialize();
//        } catch(IOException e) {
//            System.out.println("ERROR: Unable to properly initialize SSURGO Soil List.");
//        }
    }
    
    @Override
    public void build() {
        super.build();
        
        // build gets called multiple times.
        // If this is not first, then re-use
        if (csipSoilServiceNode == null) {
            csipSoilServiceNode = new WepsTreeNodeSoilCsip();
        
            csipSoilServiceNode.getBackgroundPropertyChangeObject()
                        .addPropertyChangeListener(PROP_CSIP_BGCATALOG_STARTING, this);
            csipSoilServiceNode.getBackgroundPropertyChangeObject()
                        .addPropertyChangeListener(PROP_CSIP_BGCATALOG_COMPLETE, this);

            // set the listener on the csipSoilNode, and when done, 
            // then the csipSoilCacheNode will get updated in propertyChange() 
            csipSoilServiceNode.getBackgroundPropertyChangeObject()
                        .addPropertyChangeListener(PROP_CSIP_BGFILLCACHE_COMPLETE_EXTERNAL, this);
        } else {
            csipSoilServiceNode.refreshChildren();
        }
        
        if(nrcsSDMNode == null) {
            nrcsSDMNode = new WepsTreeNodeSoilSdm();
        }
        
        if(ConfigData.checkParmValue(ConfigData.csipSoilService_CB,"1")) {
            addNode(csipSoilServiceNode);
        }
        
        if(ConfigData.checkParmValue(ConfigData.nrcsSoilDataMartURL_CB,"1")){
            addNode(nrcsSDMNode);  
        }
    
        if(ConfigData.checkParmValue(ConfigData.systemSoilDataDir_CB,"1")) {
            addNode(sysSoilDataFile, "System Soil Data");
        }
        
        if(ConfigData.checkParmValue(ConfigData.localSoilDataDir_CB,"1")) {
            addNode(locSoilDataFile, "Local Soil Data");
        }
        
        if(ConfigData.checkParmValue(ConfigData.localSoilDataMartDir_CB,"1")) {
            addNode(locSoilDataMartFile, "Local SoilDataMart Soils");
        }
                
        if (ConfigData.checkParmValue(ConfigData.cachedCsipSoilDir_CB,"1")) {
            addNode(csipSoilCacheNode, "Cached CSIP Soils");
        }
       
        databases = new LinkedList<>();
        
//        if (includeTemplateNode && !isNRCSMode) {
//            addTemplateNode(new TFile(ConfigData.getDefault().getDataParsed(ConfigData.SoilDB)));
//        }
//        
//        if (!isNRCSMode) {
//            TFile file = new TFile (ConfigData.getDefault().getDataParsed(ConfigData.SoilDB),"WEPS_baseline.mdb");
//            if (file.exists()) {
//                mdbNode = new WepsTreeNodeSoilMdb(file);
//            addNode(mdbNode);
//            }
//        }
    }
    
    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        super.propertyChange(evt);
        synchronized (this) {
            String propertyName = evt.getPropertyName();
            boolean newVisible;

            switch(propertyName) {
                case PROP_CSIP_BGCATALOG_STARTING:
                    isLoading = true;
                    if(treeCombo != null) {
                        cursorSave = treeCombo.getCursor();
                        
                        if(cursorSave.equals(getPredefinedCursor(Cursor.WAIT_CURSOR))) {
                            //If set to WAIT somewhere else, restore to default
                            cursorSave = getPredefinedCursor(Cursor.DEFAULT_CURSOR);
                        } else {
                            treeCombo.setCursor(getPredefinedCursor(Cursor.WAIT_CURSOR));
                        }
                    }
                    
                    csipSoilServiceNode.removeAllChildren();
                    csipSoilServiceNode.setTemporarilyClosed(true);
                    nodeStructureChanged(csipSoilServiceNode);
                    
                    if(csipSoilCacheNodeVisible) {
                        nodeStructureChanged(csipSoilCacheNode);
                    }
                                        
                    break;
                    
                case PROP_CSIP_BGCATALOG_COMPLETE:
                    boolean inCache = (evt.getNewValue() instanceof Boolean) ? ((Boolean)evt.getNewValue()) : false;
                    if(inCache) {
                        csipSoilServiceNode.setTemporarilyClosed(false);
                        
                        if(treeCombo != null && cursorSave != null) {
                            treeCombo.setCursor(cursorSave);
                        }
                    }
                    
                    csipSoilServiceNode.refreshChildren();
                    nodeStructureChanged(csipSoilServiceNode);           
                    isLoading = false;
                    
                    break;
                    
                case PROP_CSIP_BGFILLCACHE_COMPLETE_EXTERNAL:
                    csipSoilServiceNode.setTemporarilyClosed(false);
                    csipSoilServiceNode.refreshChildren();
                    nodeStructureChanged(csipSoilServiceNode);
                    
                    if(csipSoilCacheNodeVisible) {
                        csipSoilCacheNode.refreshChildren();
                        nodeStructureChanged(csipSoilCacheNode);
                    }
                    
                    isLoading = false;
                    
                    if(treeCombo != null && cursorSave != null) {
                        treeCombo.setCursor(cursorSave);
                    }
                                        
                    break;
                
                case ConfigData.csipSoilService_CB:
                    newVisible = ConfigData.getDefault().getDataParsed(ConfigData.csipSoilService_CB).contentEquals("1");
                    if(newVisible != csipSoilServiceVisible) {
                        csipSoilServiceVisible = newVisible;
                        
                        if(csipSoilServiceVisible) {
                            build();
                        } else {
                            removeNode(csipSoilServiceNode);
                            csipSoilServiceNode.removeAllChildren(); //Done to refresh the csipsoilservice node after changing checkbox
                        }
                    }
                    
                    break;
                
                case ConfigData.SDMSoilSortOrder:
                case ConfigData.SDMSoilSortMethod:
                    
                    if(nrcsSoilDataMartVisible) {
                        nrcsSDMNode = null;
                        build();
                    }
                    
                    break;
                    
                case PROP_SELECTED_SITE:
                    String selection = Weps.getInstance().getSelectedFromSiteChooser().toString();
                    
                    if(selection != null) {
                        if(nrcsSDMLocationSite == null) {
                            nrcsSDMLocationSite = selection;
                        } else {
                            if(!selection.equals(nrcsSDMLocationSite)) {
                                nrcsSDMLocationSite = selection;
                                if(nrcsSoilDataMartVisible) {
                                    removeNode(nrcsSDMNode);
                                    nrcsSDMNode = null;
                                    build();
                                }
                            }
                        }
                    }
                                        
                    break;
                
                case ConfigData.nrcsSoilDataMartURL_CB:
                    newVisible = ConfigData.getDefault().getDataParsed(ConfigData.nrcsSoilDataMartURL_CB).contentEquals("1");
                    if(newVisible != nrcsSoilDataMartVisible) {
                        nrcsSoilDataMartVisible = newVisible;
                        
                        if(nrcsSoilDataMartVisible) {
                            build();
                        } else {
                            removeNode(nrcsSDMNode);
                            nrcsSDMNode = null;
                        }
                    }
                    
                    break;
                    
                case ConfigData.systemSoilDataDir_CB:
                    newVisible = ConfigData.getDefault().getDataParsed(ConfigData.systemSoilDataDir_CB).contentEquals("1");
                    if(newVisible != systemSoilDataVisible) {
                        systemSoilDataVisible = newVisible;
                        
                        if(systemSoilDataVisible) {
                            build();
                        } else {
                            removeNode(sysSoilDataFile);
                        }
                    }
                    
                    break;
                    
                case ConfigData.localSoilDataDir_CB:
                    newVisible = ConfigData.getDefault().getDataParsed(ConfigData.localSoilDataDir_CB).contentEquals("1");
                    if(newVisible != localSoilDataVisible) {
                        localSoilDataVisible = newVisible;
                        
                        if(localSoilDataVisible) {
                            build();
                        } else {
                            removeNode(locSoilDataFile);
                        }
                    }
                    
                    break;  
                    
                case ConfigData.localSoilDataMartDir_CB:
                    newVisible = ConfigData.getDefault().getDataParsed(ConfigData.localSoilDataMartDir_CB).contentEquals("1");
                    if(newVisible != localSoilDataMartVisible) {
                        localSoilDataMartVisible = newVisible;
                        
                        if(localSoilDataMartVisible) {
                            build();
                        } else {
                            removeNode(locSoilDataMartFile);
                        }
                    }
                    
                    break;
                    
                case ConfigData.cachedCsipSoilDir_CB:
                    newVisible = ConfigData.getDefault().getDataParsed(ConfigData.cachedCsipSoilDir_CB).contentEquals("1");
                    if(newVisible != csipSoilCacheNodeVisible) {
                        csipSoilCacheNodeVisible = newVisible;
                        
                        if(csipSoilCacheNodeVisible) {
                            build();
                        } else {
                            removeNode(csipSoilCacheNode);
                        }
                    }
                    
                    break;
            }
        }
    }
    
    @Override
    public void nodeStructureChanged(final TreeNode node) {
        try {
            super.nodeStructureChanged(node);
        } catch (Exception e) {
            EventQueue.invokeLater(() -> {
                //use the super so if the second time there is still an exception then the user will be alerted.
                WepsTreeModelSoil.super.nodeStructureChanged(node);
            });
        }
    }

    public List<SoilDatabase> getDatabases() {
        return databases;
    }

    @Override
    public boolean accept(java.io.File file) {
        return ( file.isDirectory() || file.getName().toLowerCase().trim().endsWith(WepsFileTypes2.Soil.getExtension()) );
    }
}
