package ucar.nc2.ncml;

import java.io.IOException;
import java.util.List;
import ucar.nc2.NetcdfFile;
import ucar.nc2.dataset.NetcdfDataset;
import ucar.nc2.util.CancelTask;

/**
 *
 * @author cwardgar
 */
public class AggregationUtil {
    public static NetcdfDataset union(List<NetcdfFile> ncFiles) throws IOException {
        NetcdfDataset aggDataset = new NetcdfDataset();

        AggregationUnionOpenDataset union = new AggregationUnionOpenDataset(aggDataset);
        for (NetcdfFile ncFile : ncFiles) {
            union.addOpenNcFile(ncFile);
        }

        union.finish(null);
        aggDataset.setAggregation(union);           // Makes sure that ncFiles get closed when aggDataset gets closed.
        aggDataset.finish();
        // No enhancement done here!
        
        return aggDataset;
    }
    
    public static NetcdfDataset joinExisting(String aggDimName, List<NetcdfFile> ncFiles) throws IOException {
        NetcdfDataset aggDataset = new NetcdfDataset();
        
        AggregationExistingOpenDataset joinExisting = new AggregationExistingOpenDataset(aggDataset, aggDimName);
        for (NetcdfFile ncFile : ncFiles) {
            joinExisting.addOpenNcFile(ncFile);
        }
        
        joinExisting.finish(null);
        aggDataset.setAggregation(joinExisting);    // Makes sure that ncFiles get closed when aggDataset gets closed.
        aggDataset.finish();
        // No enhancement done here!
        
        return aggDataset;
    }
    
    
    public static class AggregationUnionOpenDataset extends AggregationUnion {
        public AggregationUnionOpenDataset(NetcdfDataset unionDataset) {
            super(unionDataset, null, null);
        }

        public void addOpenNcFile(NetcdfFile openNcFile) {
            addDataset(new UnionOpenDataset(openNcFile));
        }

        @Override protected void closeDatasets() throws IOException {
            for (Dataset dataset : getDatasets()) {
                UnionOpenDataset eod = (UnionOpenDataset) dataset;
                eod.openNcFile.close();
            }
        }


        public class UnionOpenDataset extends Aggregation.Dataset {
            private NetcdfFile openNcFile;

            public UnionOpenDataset(NetcdfFile openNcFile) {
                super(openNcFile.getLocation());
                this.cacheLocation = location;  // Silences a warning in Aggregation.makeDataset().
                this.openNcFile = openNcFile;
            }

            @Override public NetcdfFile acquireFile(CancelTask cancelTask) throws IOException {
                return openNcFile;
            }

            @Override protected void close(NetcdfFile ncfile) throws IOException {
                // DON'T ACTUALLY CLOSE ncfile HERE!
                // We're going to let it stay open until the user invokes Aggregation.close() (which, in turn, calls
                // AggregationUnionOpenDataset.closeDatasets()).
            }
        }
    }

    
    public static class AggregationExistingOpenDataset extends AggregationExisting {
        public AggregationExistingOpenDataset(NetcdfDataset joinExistingDataset, String aggDimName) {
            super(joinExistingDataset, aggDimName, null);
        }
        
        public void addOpenNcFile(NetcdfFile openNcFile) {
            addDataset(new ExistingOpenDataset(openNcFile));
        }

        @Override protected void closeDatasets() throws IOException {
            for (Dataset dataset : getDatasets()) {
                ExistingOpenDataset eod = (ExistingOpenDataset) dataset;
                eod.openNcFile.close();
            }
        }


        // The class being extended is *package private*. That's the reason that AggregationUtil must be in
        // ucar.nc2.ncml in the first place.
        public class ExistingOpenDataset extends AggregationOuterDimension.DatasetOuterDimension {
            private NetcdfFile openNcFile;
            
            public ExistingOpenDataset(NetcdfFile openNcFile) {
                super(openNcFile.getLocation());
                this.cacheLocation = location;  // Silences a warning in Aggregation.makeDataset().
                this.openNcFile = openNcFile;
            }

            @Override public NetcdfFile acquireFile(CancelTask cancelTask) throws IOException {
                return openNcFile;
            }

            @Override protected void close(NetcdfFile ncfile) throws IOException {
                // DON'T ACTUALLY CLOSE ncfile HERE!
                // We're going to let it stay open until the user invokes Aggregation.close() (which, in turn, calls
                // AggregationExistingOpenDataset.closeDatasets()).
            }
        }
    }
}
