/*
 * Copyright (c) 2016 Ngewi Fet <ngewif@gmail.com>
 *
 * 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 org.gnucash.android.util;

import android.util.Log;

import org.gnucash.android.db.MigrationHelper;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;

/**
 * Moves all files from one directory  into another.
 * The destination directory is assumed to already exist
 */
public class RecursiveMoveFiles implements Runnable {
    File mSource;
    File mDestination;

    /**
     * Constructor, specify origin and target directories
     * @param src Source directory/file. If directory, all files within it will be moved
     * @param dst Destination directory/file. If directory, it should already exist
     */
    public RecursiveMoveFiles(File src, File dst){
        mSource = src;
        mDestination = dst;
    }

    /**
     * Copy file from one location to another.
     * Does not support copying of directories
     * @param src Source file
     * @param dst Destination of the file
     * @return {@code true} if the file was successfully copied, {@code false} otherwise
     * @throws IOException
     */
    private boolean copy(File src, File dst) throws IOException {
        FileChannel inChannel = new FileInputStream(src).getChannel();
        FileChannel outChannel = new FileOutputStream(dst).getChannel();
        try {
            long bytesCopied = inChannel.transferTo(0, inChannel.size(), outChannel);
            return bytesCopied >= src.length();
        } finally {
            if (inChannel != null)
                inChannel.close();
            outChannel.close();
        }
    }

    /**
     * Recursively copy files from one location to another and deletes the origin files after copy.
     * If the source file is a directory, all of the files in it will be moved.
     * This method will create the destination directory if the {@code src} is also a directory
     * @param src origin file
     * @param dst destination file or directory
     * @return number of files copied (excluding parent directory)
     */
    private int recursiveMove(File src, File dst){
        int copyCount = 0;
        if (src.isDirectory() && src.listFiles() != null){
            dst.mkdirs(); //we assume it works everytime. Great, right?
            for (File file : src.listFiles()) {
                File target = new File(dst, file.getName());
                 copyCount += recursiveMove(file, target);
            }
            src.delete();
        } else {
            try {
                if(copy(src, dst))
                    src.delete();
            } catch (IOException e) {
                Log.d(MigrationHelper.LOG_TAG, "Error moving file: " + src.getAbsolutePath());
            }
        }
        Log.d("RecursiveMoveFiles", String.format("Moved %d files from %s to %s", copyCount, src.getPath(), dst.getPath()));
        return copyCount;
    }

    @Override
    public void run() {
        recursiveMove(mSource, mDestination);
    }
}
