package org.yi.happy.archive.tag;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.yi.happy.archive.RetrieveBlock;
import org.yi.happy.archive.file_system.FileSystem;
import org.yi.happy.archive.key.FullKey;

/**
 * A management process for multiple files being restored.
 */
public class RestoreManager {

    private List<RestoreFile> files;
    private final FileSystem fs;
    private final RetrieveBlock store;

    /**
     * initialize.
     * 
     * @param fs
     *            the file system to use.
     * @param store
     *            the block store to use.
     */
    public RestoreManager(FileSystem fs, RetrieveBlock store) {
        this.fs = fs;
        this.store = store;
        files = new ArrayList<RestoreFile>();
    }

    /**
     * add a file to the set of files being restored.
     * 
     * @param path
     *            the path to the file to restore.
     * @param fullKey
     *            the key to store there.
     */
    public void addFile(String path, FullKey fullKey) {
        files.add(new RestoreFile(fullKey, store, path, fs));
    }

    /**
     * do a processing step.
     * 
     * @throws IOException
     */
    public void step() throws IOException {
        for (RestoreFile f : files) {
            f.step();
        }
    }

    /**
     * get the number of blocks read and processed.
     * 
     * @return the number of blocks read and processed.
     */
    public int getProgress() {
        int progress = 0;
        for (RestoreFile f : files) {
            progress += f.getProgress();
        }
        return progress;
    }

    /**
     * get the keys for the blocks that are known to be needed.
     * 
     * @return a list of the needed blocks.
     */
    public List<FullKey> getPending() {
        List<FullKey> out = new ArrayList<FullKey>();
        Set<FullKey> seen = new HashSet<FullKey>();
        for (RestoreFile f : files) {
            for (FullKey k : f.getPending()) {
                if (seen.contains(k)) {
                    continue;
                }
                out.add(k);
                seen.add(k);
            }
        }
        return out;
    }

    /**
     * check if the restore is done.
     * 
     * @return true if the restore is done.
     */
    public boolean isDone() {
        for (RestoreFile f : files) {
            if (!f.isDone()) {
                return false;
            }
        }
        return true;
    }

}

@@ -77,91 +77,53 @@
 til.
-Array
 List;%0A
+%0A
 import 
-java.util.HashSet;%0Aimport java.util.List;%0Aimport java.util.Se
+org.yi.happy.archive.Fragmen
 t;%0A
-%0A
 impo
@@ -161,16 +161,57 @@
 eBlock;%0A
+import org.yi.happy.archive.block.Block;%0A
 import o
@@ -286,19 +286,132 @@
 ive.
-key.FullKey
+file_system.RandomOutputFile;%0Aimport org.yi.happy.archive.key.FullKey;%0Aimport org.yi.happy.archive.restore.RestoreManyEngine
 ;%0A%0A/
@@ -506,17 +506,16 @@
 nager %7B%0A
-%0A
     priv
@@ -522,31 +522,38 @@
 ate 
-List%3C
+final 
 Restore
-File%3E files
+ManyEngine engine
 ;%0A  
@@ -623,16 +623,111 @@
 store;%0A%0A
+    /**%0A     * the number of blocks read and processed.%0A     */%0A    private int progress = 0;%0A%0A
     /**%0A
@@ -1008,42 +1008,43 @@
     
-files = new ArrayList%3CRestoreFile%3E
+this.engine = new RestoreManyEngine
 ();%0A
@@ -1330,59 +1330,32 @@
     
-files.add(new RestoreFile(fullKey, store, path, fs)
+engine.add(path, fullKey
 );%0A 
@@ -1496,59 +1496,1003 @@
     
-for (RestoreFile f : files) %7B%0A            f.step();
+RandomOutputFile out = null;%0A        String path = null;%0A        try %7B%0A            engine.start();%0A            while (engine.findReady()) %7B%0A                Block block = store.retrieveBlock(engine.getKey());%0A                if (block == null) %7B%0A                    engine.skip();%0A                    continue;%0A                %7D%0A                Fragment part = engine.step(block);%0A                progress++;%0A                if (part != null) %7B%0A                    if (out != null && !path.equals(engine.getJobName())) %7B%0A                        out.close();%0A                        out = null;%0A                    %7D%0A                    if (out == null) %7B%0A                        path = engine.getJobName();%0A                        out = fs.openRandomOutputFile(path);%0A                    %7D%0A                    out.writeAt(part.getOffset(), part.getData().toByteArray());%0A                %7D%0A            %7D%0A        %7D finally %7B%0A            if (out != null) %7B%0A                out.close();%0A            %7D
 %0A   
@@ -2672,123 +2672,8 @@
 ) %7B%0A
-        int progress = 0;%0A        for (RestoreFile f : files) %7B%0A            progress += f.getProgress();%0A        %7D%0A
     
@@ -2884,378 +2884,33 @@
     
-List%3CFullKey%3E out = new ArrayList%3CFullKey%3E();%0A        Set%3CFullKey%3E seen = new HashSet%3CFullKey%3E();%0A        for (RestoreFile f : files) %7B%0A            for (FullKey k : f.getPending()) %7B%0A                if (seen.contains(k)) %7B%0A                    continue;%0A                %7D%0A                out.add(k);%0A                seen.add(k);%0A            %7D%0A        %7D%0A        return out
+return engine.getNeeded()
 ;%0A  
@@ -3061,149 +3061,37 @@
     
-for (RestoreFile f : files) %7B%0A            if (!f.isDone()) %7B%0A                return false;%0A            %7D%0A        %7D%0A        return true
+return engine.isDone()
 ;%0A    %7D%0A
 %0A%7D%0A
@@ -3087,11 +3087,10 @@
 ;%0A    %7D%0A
-%0A
 %7D%0A

Change RestoreManager to use RestoreManyEngine.