/*
* This file is part of NucleusFramework for Bukkit, licensed under the MIT License (MIT).
*
* Copyright (c) JCThePants (www.jcwhatever.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.jcwhatever.nucleus.regions;
import com.jcwhatever.nucleus.regions.file.IRegionFileFactory;
import com.jcwhatever.nucleus.regions.file.IRegionFileLoader.LoadSpeed;
import com.jcwhatever.nucleus.regions.file.basic.BasicFileFactory;
import com.jcwhatever.nucleus.storage.IDataNode;
import com.jcwhatever.nucleus.utils.PreCon;
import com.jcwhatever.nucleus.utils.observer.future.FutureSubscriber;
import com.jcwhatever.nucleus.utils.observer.future.IFuture;
import com.jcwhatever.nucleus.utils.observer.future.IFuture.FutureStatus;
import org.bukkit.plugin.Plugin;
import javax.annotation.Nullable;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
/**
* An abstract implementation of a restorable region
* with multiple named saved snapshots.
*
* <p>The default snapshot name is "default".</p>
*/
public abstract class MultiSnapshotRegion extends RestorableRegion {
private final SnapshotFileFactory _fileFactory = new SnapshotFileFactory();
/**
* Constructor.
*
* @param plugin The owning plugin.
* @param name The name of the region.
*/
public MultiSnapshotRegion(Plugin plugin, String name) {
super(plugin, name);
}
/**
* Constructor.
*
* @param plugin The owning plugin.
* @param name The name of the region.
* @param dataNode The regions data node.
*/
public MultiSnapshotRegion(Plugin plugin, String name, IDataNode dataNode) {
super(plugin, name, dataNode);
}
@Override
public SnapshotFileFactory getFileFactory() {
if (_fileFactory.fileFactory == null)
_fileFactory.fileFactory = new BasicFileFactory();
return _fileFactory;
}
@Override
public void setFileFactory(IRegionFileFactory fileFactory) {
PreCon.notNull(fileFactory);
_fileFactory.fileFactory = fileFactory;
}
/**
* Get the name of the current snapshot.
*
* <p>The default snapshot name is "default".</p>
*/
public String getCurrentSnapshot() {
return getFileFactory().snapshotName;
}
/**
* Set the current snapshot name.
*
* @param snapshotName The snapshot name.
*/
public void setCurrentSnapshot(String snapshotName) {
PreCon.notNullOrEmpty(snapshotName);
getFileFactory().snapshotName = snapshotName;
}
/**
* Get the names of stored snapshots.
*
* <p>Snapshot names are retrieved by file name, therefore this
* only returns names of snapshots that have been saved.</p>
*
* @throws IOException
*/
public Set<String> getSnapshotNames() throws IOException {
return getSnapshotNames(new HashSet<String>(15));
}
/**
* Get the names of stored snapshots.
*
* <p>Snapshot names are retrieved by file name, therefore this
* only returns names of snapshots that have been saved.</p>
*
* @throws IOException
*/
public <T extends Collection<String>> T getSnapshotNames(T output) throws IOException {
File folder = _fileFactory.getRegionDirectory(this);
File[] files = folder.listFiles();
if (files == null)
return output;
for (File file : files) {
if (!file.isDirectory())
continue;
output.add(file.getName());
}
return output;
}
/**
* Determine if the specified snapshot can be restored.
*
* @param snapshotName The name of the snapshot.
*/
public boolean canRestore(String snapshotName) {
String current = getFileFactory().snapshotName;
getFileFactory().snapshotName = snapshotName;
boolean canRestore = getFileFormat().getLoader(this, _fileFactory).canRead();
getFileFactory().snapshotName = current;
return canRestore;
}
/**
* Restore the specified snapshot.
*
* @param loadSpeed The speed of the restore.
* @param snapshotName The name of the snapshot.
*
* @throws IOException
*/
public IFuture restoreData(LoadSpeed loadSpeed, final String snapshotName) throws IOException {
final String currentSnapshot = getFileFactory().snapshotName;
getFileFactory().snapshotName = snapshotName;
return super.restoreData(loadSpeed)
.onSuccess(new FutureSubscriber() {
@Override
public void on(FutureStatus status, @Nullable CharSequence message) {
getFileFactory().snapshotName = currentSnapshot;
}
});
}
/**
* Save the regions current state to the specified snapshot.
*
* @param snapshotName The name of the snapshot.
*
* @throws IOException
*/
public IFuture saveData(String snapshotName) throws IOException {
final String currentSnapshot = getFileFactory().snapshotName;
getFileFactory().snapshotName = snapshotName;
return super.saveData().onStatus(new FutureSubscriber() {
@Override
public void on(FutureStatus status, @Nullable CharSequence message) {
getFileFactory().snapshotName = currentSnapshot;
}
});
}
/**
* Delete the specified snapshots data.
*
* @param snapshotName The name of the snapshot.
*
* @throws IOException
*/
public void deleteData(String snapshotName) throws IOException {
PreCon.notNull(snapshotName);
final String currentSnapshot = getFileFactory().snapshotName;
getFileFactory().snapshotName = snapshotName;
super.deleteData();
getFileFactory().snapshotName = currentSnapshot;
}
public static class SnapshotFileFactory implements IRegionFileFactory {
String snapshotName = "default";
IRegionFileFactory fileFactory;
private SnapshotFileFactory() {}
@Override
public String getFilename(IRegion region) {
return fileFactory.getFilename(region);
}
@Override
public File getDirectory(IRegion region) throws IOException {
File regionFolder = getRegionDirectory(region);
File snapshotFolder = new File(regionFolder, snapshotName);
if (!snapshotFolder.exists() && !snapshotFolder.mkdirs()) {
throw new IOException("Failed to create snapshot folder.");
}
return snapshotFolder;
}
public File getRegionDirectory(IRegion region) throws IOException {
return fileFactory.getDirectory(region);
}
public String getSnapshotName() {
return snapshotName;
}
public IRegionFileFactory getInnerFactory() {
return fileFactory;
}
}
}