package usda.weru.remoteDataAccess.csip.crlmod;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import usda.weru.remoteDataAccess.RdaHierarchicalItem;
import usda.weru.remoteDataAccess.csip.CsipInputControllerCachingSupport;
import usda.weru.remoteDataAccess.csip.CsipLmodUtil;
import usda.weru.remoteDataAccess.csip.CsipLmodUtil.lmodType;
import usda.weru.remoteDataAccess.exceptions.RdaConnectException;
import usda.weru.remoteDataAccess.RdaBgCacheContIf;
import usda.weru.remoteDataAccess.csip.CsipHierarchicalItem;
import usda.weru.remoteDataAccess.csip.CsipInputControllerBgCacheIf;
import usda.weru.remoteDataAccess.csip.CsipInputControllerCacheLoader;
import static usda.weru.remoteDataAccess.csip.CsipInputControllerCachingSupport.PROP_CSIP_BGCATALOG_COMPLETE;
import static usda.weru.remoteDataAccess.RdaInputControllerCacheLoader.PROP_CSIP_BGFILLCACHE_COMPLETE_INTERNAL;

/**
 *
 * @author mhaas
 */
public class CsipInputContCrLmodBgCache extends CsipInputContCrLmod 
                                        implements RdaBgCacheContIf, CsipInputControllerBgCacheIf, PropertyChangeListener  {
    
    protected CsipInputControllerCachingSupport cachesupport;
    protected CsipInputControllerCacheLoader cacheloader;
    
    public static final String PROP_CSIP_BGFILLCACHE_COMPLETE_EXTERNAL = "PropCsipBgFillCacheCompleteExternal";
    
    public CsipInputContCrLmodBgCache (lmodType ifType) {
        this (ifType, false);
    }
    
    public CsipInputContCrLmodBgCache (lmodType ifType, boolean fromSubClass) {
        super(ifType, fromSubClass);

        cachesupport = new CsipInputControllerCachingSupport(this);
        if (ifType == lmodType.lmodCropResidue) {
            // make residues a subdir of crops
            cachesupport.setBaseCacheDir(new File (new File (cachesupport.getBaseCacheDir(), CsipLmodUtil.getCrLmodName(lmodType.lmodCrop)), 
                                                   CsipLmodUtil.getCrLmodName(lmodType.lmodCropResidue)) );            
        } else {
            cachesupport.setBaseCacheDir(new File (cachesupport.getBaseCacheDir(), CsipLmodUtil.getCrLmodName(ifType)) );
        }
        
        if (ifType == lmodType.lmodOperation) {
            cacheloader = new CsipInputContCrlmodOpCacheLoader (this, cachesupport);
        } else {
            cacheloader = new CsipInputControllerCacheLoader (this, cachesupport);
        }
        //cacheloader = new CsipInputControllerCacheLoader (this, cachesupport);
        changes.addPropertyChangeListener(PROP_CSIP_BGCATALOG_COMPLETE,this);
    }
    
    @Override
    public void setInterfaceName (String interfaceName) {
        super.setInterfaceName(interfaceName);
        cachesupport.setCacheSupportInterfaceName(interfaceName);
        cacheloader.setInterfaceName();
    }
    
    @Override
    public File getFile(RdaHierarchicalItem item) throws RdaConnectException {
        return cachesupport.getFileCaching(item, csipIf);
    }
    
    @Override
    public boolean cacheWriteCatalog (ArrayList<String> catalog) throws IOException {
        return cachesupport.cacheWriteCatalog(catalog);
    }
    
    @Override
    public ArrayList<String> cacheReadCatalog () throws IOException {
        return cachesupport.cacheReadCatalog();
    }
    
    @Override
    public void clearCacheDir () {
        cachesupport.clearBaseCacheDir();
    }
    
    @Override
    public void doBackgroundGetCatalog () {
        downloading = true;
        filesChanged = true;
        if (inputDataTree == null) {
            RdaHierarchicalItem item = new CsipHierarchicalItem(interfaceName, this);
            inputDataTree = item;
        }
        cachesupport.doBackgroundGetCatalog(inputDataTree, csipIf, changes);
    }
    
    @Override
    public void resetBackgroundTask() {
//        backgroundTask = null;
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        if (evt.getPropertyName().contentEquals(PROP_CSIP_BGCATALOG_COMPLETE)) {
            downloading = false;
            boolean b = (boolean)evt.getNewValue();
            if (!(boolean)evt.getNewValue()) {
                if (!doCatalogOnly) {
                    doFillCache ();
                }
            } else {
                Logger.getLogger(this.getClass().getName()).log(Level.INFO, 
                    "Background cache files previously loaded: " + interfaceName);
                // If it was in cache, then the fill is complete implicitly.
                // So fire a propchange to signal this.
                changes.firePropertyChange(PROP_CSIP_BGFILLCACHE_COMPLETE_EXTERNAL, false, this);
            }
        } else if (evt.getPropertyName().contentEquals(PROP_CSIP_BGFILLCACHE_COMPLETE_INTERNAL)) {
            changes.firePropertyChange(PROP_CSIP_BGFILLCACHE_COMPLETE_EXTERNAL, false, this);
        }
    }
    
    // only call this one
    @Override
    public void doFillCache () {
        // need a new independent controller object:
        //   1. it uses different destination, which is part of the controller's data
        //      This object's dest is not the same as the cacheing dir.
        //   2. avoid threading conflicts when using the CsipInterface's CSIP client object.
        //
        if (doCacheBackgroundLoad) {
            // do this at most once
            doCacheBackgroundLoad = false;  
            CsipInputContCrLmodBgCache tempController = new CsipInputContCrLmodBgCache(ifType);
            try {
                tempController.init(inputDataTree);
            } catch (RdaConnectException ex) {
            }
            tempController.setInterfaceName(interfaceName);
            tempController.getChangeObj().addPropertyChangeListener(PROP_CSIP_BGFILLCACHE_COMPLETE_INTERNAL,this);
            tempController.doFillCacheInternal();
        }
    }
    
    // this one only for use from above
    @Override
    public void doFillCacheInternal() {
        cacheloader.cacheFilesInBackground(inputDataTree);
    }

    @Override
    public boolean checkBackgroundGetCatalog() {
        return downloading;
    }

    @Override
    public boolean checkNewFiles() {
        return filesChanged;
    }

    @Override
    public void clearNewFiles() {
        filesChanged = false;
    }

    @Override
    public void resetCatalog() {
        resetBackgroundTask();
        inputDataTree = null;
    }
    
    @Override
    public void addPropertyChangeListener(String propertyName, PropertyChangeListener l) {
        changes.addPropertyChangeListener(propertyName, l);
    }
    
    @Override
    public boolean cacheFilesValid () {
        return cacheloader.checkCacheFilesValid(doCatalogOnly); 
    }
    
}
