/*
* Copyright 2014 Yaroslav Mytkalyk
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.docd.purefm.tasks;
import java.lang.ref.WeakReference;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.LinkedList;
import android.app.Activity;
import com.docd.purefm.R;
import com.docd.purefm.file.FileFactory;
import com.docd.purefm.operations.OperationsService;
import com.docd.purefm.settings.Settings;
import com.docd.purefm.ui.dialogs.FileExistsDialog;
import com.docd.purefm.file.GenericFile;
import com.docd.purefm.utils.ClipBoard;
import com.docd.purefm.utils.PFMFileUtils;
import com.docd.purefm.utils.StatFsCompat;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.util.Pair;
import android.widget.Toast;
public final class PasteTaskExecutor implements FileExistsDialog.FileExistsDialogListener {
@NonNull
private final WeakReference<Activity> mActivityReference;
@NonNull
private final Settings mSettings;
@NonNull
private final GenericFile mTargetFile;
@NonNull
private final LinkedList<GenericFile> mToProcess = new LinkedList<>();
@NonNull
private final HashMap<GenericFile, GenericFile> mExisting = new HashMap<>();
private FreeSpaceTask mFreeSpaceTask;
@SuppressWarnings("FieldCanBeLocal")
private Thread mStartThread;
private Pair<GenericFile, GenericFile> mCurrentPair;
public PasteTaskExecutor(@NonNull final Activity activity,
@NonNull final GenericFile targetFile) {
mActivityReference = new WeakReference<>(activity);
mSettings = Settings.getInstance(activity);
mTargetFile = targetFile;
}
public void start() {
if (mFreeSpaceTask == null) {
mFreeSpaceTask = new FreeSpaceTask(mTargetFile, mToProcess);
mFreeSpaceTask.execute();
}
}
@Override
public void onActionSkip(final boolean all) {
if (all) {
mExisting.clear();
}
next();
}
@Override
public void onActionReplace(final boolean all) {
if (mCurrentPair.second.delete()) {
mToProcess.add(mCurrentPair.first);
} else {
final Context context = mActivityReference.get();
if (context != null) {
Toast.makeText(context, context.getString(R.string.dialog_overwrite_replace_failed,
mCurrentPair.second.getAbsolutePath()), Toast.LENGTH_LONG).show();
}
}
if (all) {
mToProcess.addAll(mExisting.keySet());
mExisting.clear();
}
next();
}
@Override
public void onActionAbort() {
mExisting.clear();
mToProcess.clear();
}
private void next() {
final Activity activity = this.mActivityReference.get();
if (activity != null) {
if (mExisting.isEmpty()) {
if (mToProcess.isEmpty()) {
ClipBoard.clear();
} else {
final GenericFile[] files = new GenericFile[mToProcess.size()];
mToProcess.toArray(files);
OperationsService.paste(activity, mTargetFile, files, ClipBoard.isMove());
}
} else {
final GenericFile key = mExisting.keySet().iterator().next();
final GenericFile target = mExisting.get(key);
mCurrentPair = new Pair<>(key, target);
mExisting.remove(key);
if (!activity.isFinishing()) {
if (Looper.myLooper() == Looper.getMainLooper()) {
showExistsDialog(activity, key, target);
} else {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
showExistsDialog(activity, key, target);
}
});
}
}
}
}
}
private void showExistsDialog(@NonNull final Context context,
@NonNull final GenericFile source,
@NonNull final GenericFile target) {
new FileExistsDialog(context, source, target, this).show();
}
private static final class FreeSpaceTaskResult {
final long mFreeSpace;
final long mFilesSize;
final boolean mHasEnoughFreeSpace;
FreeSpaceTaskResult(final long freeSpace,
final long filesSize) {
this.mFreeSpace = freeSpace;
this.mFilesSize = filesSize;
mHasEnoughFreeSpace = freeSpace > mFilesSize;
}
}
private final class FreeSpaceTask extends AsyncTask<Void, Void, FreeSpaceTaskResult> {
private final GenericFile mTarget;
private final Iterable<GenericFile> mFiles;
FreeSpaceTask(@NonNull final GenericFile target,
@NonNull final Iterable<GenericFile> files) {
this.mTarget = target;
this.mFiles = files;
}
@NonNull
@Override
protected FreeSpaceTaskResult doInBackground(Void... params) {
long total = 0;
for (final GenericFile file : mFiles) {
total += file.length();
}
final StatFsCompat statFs = new StatFsCompat(PFMFileUtils.fullPath(mTarget));
return new FreeSpaceTaskResult(statFs.getAvailableBytes(), total);
}
@Override
protected void onPostExecute(@NonNull final FreeSpaceTaskResult freeSpaceTaskResult) {
if (freeSpaceTaskResult.mHasEnoughFreeSpace) {
mStartThread = new StartThread();
mStartThread.start();
} else {
final Context context = mActivityReference.get();
if (context != null) {
final String freeSpace = PFMFileUtils.byteCountToDisplaySize(
BigInteger.valueOf(freeSpaceTaskResult.mFreeSpace));
final String filesSize = PFMFileUtils.byteCountToDisplaySize(
BigInteger.valueOf(freeSpaceTaskResult.mFilesSize));
Toast.makeText(context, context.getString(R.string.not_enough_space_message,
freeSpace, filesSize), Toast.LENGTH_LONG).show();
}
}
}
}
private final class StartThread extends Thread {
@Override
public void run() {
final GenericFile[] contents = ClipBoard.getClipBoardContents();
if (contents == null) {
return;
}
for (final GenericFile file : contents) {
if (file != null && file.exists()) {
final GenericFile testTarget = FileFactory.newFile(mSettings,
mTargetFile.toFile(), file.getName());
if (testTarget.exists()) {
mExisting.put(file, testTarget);
} else {
mToProcess.add(file);
}
}
}
next();
}
}
}