package jdrivesync.gdrive;
import com.google.api.services.drive.model.File;
import jdrivesync.cli.Options;
import jdrivesync.exception.JDriveSyncException;
import jdrivesync.logging.LoggerFactory;
import jdrivesync.model.SyncDirectory;
import jdrivesync.model.SyncFile;
import jdrivesync.model.SyncItem;
import jdrivesync.walker.Walker;
import jdrivesync.walker.WalkerVisitor;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;
public class GoogleDriveWalker implements Walker {
private static final Logger LOGGER = LoggerFactory.getLogger();
private final Options options;
private final GoogleDriveAdapter googleDriveAdapter;
public GoogleDriveWalker(Options options, GoogleDriveAdapter googleDriveAdapter) {
this.options = options;
this.googleDriveAdapter = googleDriveAdapter;
}
@Override
public void walk(WalkerVisitor walkerVisitor) {
File remoteRootFile = googleDriveAdapter.getFile("root");
remoteRootFile = getRemoteRootDir(remoteRootFile);
java.io.File localRootFile = options.getLocalRootDir().get();
SyncDirectory rootDirectory = new SyncDirectory(Optional.of(localRootFile), Optional.of(remoteRootFile), "/", Optional.empty());
walkInternal(rootDirectory, googleDriveAdapter, walkerVisitor);
}
private File getRemoteRootDir(File remoteRootFile) {
File currentRemoteDir = remoteRootFile;
if (options.getRemoteRootDir().isPresent()) {
String remoteRootDir = options.getRemoteRootDir().get();
String[] pathParts = remoteRootDir.split("/");
for (String pathPart : pathParts) {
if (pathPart.length() == 0) {
continue;
}
File foundRemoteDir = null;
List<File> remoteChildren = googleDriveAdapter.listChildren(currentRemoteDir.getId());
for (File remoteChild : remoteChildren) {
if (remoteChild.getTitle().equals(pathPart)) {
if (googleDriveAdapter.isDirectory(remoteChild)) {
foundRemoteDir = remoteChild;
} else {
throw new JDriveSyncException(JDriveSyncException.Reason.InvalidRemoteRootDirectory, "The remote root directory path '" + remoteRootDir + "' contains a file: '" + pathPart + "'.");
}
}
}
if (foundRemoteDir == null) {
throw new JDriveSyncException(JDriveSyncException.Reason.InvalidRemoteRootDirectory, "The remote path '" + remoteRootDir + "' does not exist.");
} else {
currentRemoteDir = foundRemoteDir;
}
}
}
return currentRemoteDir;
}
private void walkInternal(SyncDirectory syncDirectory, GoogleDriveAdapter googleDriveAdapter, WalkerVisitor visitor) {
if (syncDirectory.getRemoteFile().isPresent()) {
File remoteFile = syncDirectory.getRemoteFile().get();
List<File> remoteChildren = googleDriveAdapter.listChildren(remoteFile.getId());
for (File file : remoteChildren) {
if (!googleDriveAdapter.isGoogleAppsDocument(file) && googleDriveAdapter.fileNameValid(file)) {
String relativePath = toRelativePath(file, syncDirectory);
if (googleDriveAdapter.isDirectory(file)) {
if (!fileShouldBeIgnored(relativePath, true, file)) {
SyncDirectory subSyncDirectory = new SyncDirectory(Optional.empty(), Optional.of(file), relativePath, Optional.of(syncDirectory));
syncDirectory.addChild(subSyncDirectory);
}
} else {
if (!fileShouldBeIgnored(relativePath, false, file)) {
SyncFile syncFile = new SyncFile(Optional.empty(), Optional.of(file), relativePath, Optional.of(syncDirectory));
syncDirectory.addChild(syncFile);
}
}
}
}
WalkerVisitor.WalkerVisitorResult result = visitor.visitDirectory(syncDirectory);
if (result == WalkerVisitor.WalkerVisitorResult.Continue) {
Iterator<SyncItem> childrenIterator = syncDirectory.getChildrenIterator();
while (childrenIterator.hasNext()) {
SyncItem syncItem = childrenIterator.next();
if (syncItem instanceof SyncDirectory) {
SyncDirectory subSyncDir = (SyncDirectory) syncItem;
walkInternal(subSyncDir, googleDriveAdapter, visitor);
}
childrenIterator.remove(); //free memory
}
}
} else {
LOGGER.log(Level.FINE, "Skipping directory '" + syncDirectory.getPath() + "' because remote file is not set.");
}
}
private String toRelativePath(File file, SyncDirectory syncDirectory) {
if (syncDirectory.isRootDirectory()) {
return "/" + file.getTitle();
} else {
String parentPath = syncDirectory.getPath();
return parentPath + "/" + file.getTitle();
}
}
private boolean fileShouldBeIgnored(String name, boolean isDirectory, File file) {
boolean matches = options.getIgnoreFiles().matches(name, isDirectory);
if (matches && LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, "Ignoring file '" + name + "' because the name matches the ignore list.");
}
if (!matches && options.getMaxFileSize().isPresent()) {
if (!googleDriveAdapter.isDirectory(file)) {
Long fileSize = file.getFileSize();
Long maxFileSize = options.getMaxFileSize().get();
if (maxFileSize.compareTo(fileSize) < 0) {
matches = true;
LOGGER.log(Level.FINE, "Ignoring '" + name + "' because file is bigger than maxFileSize (file: " + fileSize + ", maxFileSize: " + maxFileSize + ").");
}
}
}
return matches;
}
}