/*
 * Main.java
 *
 * Created on January 2, 2007, 6:57 PM
 *
 */

package gradualbackupmanager;

import java.io.*;
import java.util.Vector;
import java.util.Random;

/**
 *
 * @author Jimmy
 */
public class Main {
    
    static final int backupSize = 700*1024*1024;
    static final int sectorSize = 512*1024;
    static final String startDir = "C:\\";
    static final String targetDir = "D:\\"; //"C:\\backup\\incback\\";
    static final String logFile = "D:\\iblog.txt"; //"C:\\backup\\incback\\iblog.txt";
    static final String errFile = "D:\\iberr.txt"; //"C:\\backup\\incback\\iberr.txt";
    
    protected Vector<File> prohibited;
    
    /** Creates a new instance of Main */
    public Main() {
        prohibited = new Vector<File>();
    }
    
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws IOException {
        Main handler = new Main();

        // Make initial structure
        File newdir = new File(targetDir);
        if (!newdir.exists())
            if (!newdir.mkdir()) {
                handler.AddToErrorFile(newdir, "could not make directory");
                return;
            }

        int result = handler.BackupRandomFiles(backupSize);
    }
    
    public int BackupRandomFiles(int size) throws IOException {
        Random randgen = new Random();
        int written = 0;
        while (size > sectorSize) {
            File target = new File(startDir);

            for (int level = 1; target.isDirectory(); level++) {
                File[] contents = target.listFiles();
                Vector<File> subdirs = new Vector<File>();

                if (contents == null) {
                    AddToErrorFile(target, "empty list files");
                    target = new File(startDir);
                    level--;
                    continue;
                }
                
                // get the collection of directories
                int filecount = 0;
                for (int ii = 0; ii < contents.length; ii++) {
                    if (contents[ii].equals(targetDir))
                        continue;
                    if (prohibited.contains(contents[ii]))
                        continue;
                    if (contents[ii].isDirectory())
                        subdirs.add(contents[ii]);
                    else if (contents[ii].isFile())
                        filecount++;
                }

                // Randomly choose one (or the current directory)
                if (subdirs.size() == 0 && filecount == 0) {
                    target = new File(startDir); // reset!
                    level--; // keep level high
                    continue;
                }
                
                int chosen = randgen.nextInt(subdirs.size() + min(filecount, level));
                if (chosen < subdirs.size())
                    target = subdirs.get(chosen);
                else {
                    Vector<File> files = new Vector<File>();

                    // get the collection of files
                    for (int ii = 0; ii < contents.length; ii++) {
                        if (contents[ii].isFile())
                            files.add(contents[ii]);
                    }

                    chosen = randgen.nextInt(files.size());
                    target = files.get(chosen);
                }
            }

            // Copy over the file
            int copysize = CopyRelativeFile(target, size);

            if (copysize > 0) {
                // Add to the index
                AddToLogFile(target);
                size -= copysize;
                written += copysize;
            } else {
                size -= sectorSize;
            }
        }
        
        return written;
    }
    
    int CopyRelativeFile(File file, int maxSize) throws IOException {
        if (file.length() > maxSize)
            return 0;
        
        String path = file.getAbsolutePath().substring(3);
        String dirs[] = path.split("\\\\");
        
        String partpath = targetDir;
        for (int ii = 0; ii < dirs.length - 1; ii++) {
            partpath += dirs[ii] + "\\";
            File newdir = new File(partpath);
            if (!newdir.exists())
                if (!newdir.mkdir()) {
                    AddToErrorFile(newdir, "could not make directory");
                    return 0;
                }
        }
        
        // copy the file over
        File dest = new File(partpath + dirs[dirs.length - 1]);
        if (dest.exists())
            return 0;   // no need!
        
        byte[] buf = new byte[1024];
        int len;
        int totallen = 0;
        
        try {
            InputStream in = new FileInputStream(file);
            OutputStream out = new FileOutputStream(dest);
        
            while ((len = in.read(buf)) > 0) {
                out.write(buf, 0, len);
                totallen += len;
            }
            in.close();
            out.close();
        } catch (FileNotFoundException e) {
            AddToErrorFile(file, e.getMessage());
            return 0;
        }
        
        return totallen;
    }
    
    void AddToLogFile(File target) throws IOException {
        OutputStream out = new FileOutputStream(logFile, true);
        String output = target.toString() + " (" + Math.round(target.length() / 1024) + "k)\n";
        out.write(output.getBytes());
        out.close();
    }
    
    void AddToErrorFile(File target, String error) throws IOException {
        OutputStream out = new FileOutputStream(errFile, true);
        String output = target.toString() + ": " + error + "\n";
        out.write(output.getBytes());
        out.close();
        
        // No more trying things with this file!
        prohibited.add(target);
    }

    int min(int a, int b) {
        if (a < b)
            return a;
        return b;
    }
}
