PrioritizeChunks( chunkPrioritizer );
  public void SetupFilesAndChunks()  {    if ( floodFile.targetFiles.size() > 0 )    {      runtimeTargetFiles = new Hashtable( floodFile.targetFiles.size() );      Iterator targetFileIter = Arrays.asList(floodFile.targetFiles.values().toArray()).iterator();      for ( int fileIndex = 0; targetFileIter.hasNext(); ++fileIndex )      {        FloodFile.TargetFile targetFile = (FloodFile.TargetFile) targetFileIter.next();        RuntimeTargetFile runtimeTargetFile = new RuntimeTargetFile();        runtimeTargetFile.name       = targetFile.name;        runtimeTargetFile.nameOnDisk = targetFile.name;  // TODO let people override this somehow         runtimeTargetFile.targetFile = targetFile;        runtimeTargetFile.chunks     = new Vector(targetFile.chunks.size());                try        {          // Get a file handle and channel for the file on disk          runtimeTargetFile.fileObject = new File(runtimeTargetFile.nameOnDisk);          if( !runtimeTargetFile.fileObject.exists() )          {            // make any necessary dirs            String targetFileDirectoryPath = runtimeTargetFile.fileObject.getAbsolutePath();            File runtimeTargetFileDirectory = new File(targetFileDirectoryPath.substring( 0, targetFileDirectoryPath.lastIndexOf( '/' )));            runtimeTargetFileDirectory.mkdirs();          }                    runtimeTargetFile.fileHandle = new RandomAccessFile(runtimeTargetFile.fileObject, "rw");          runtimeTargetFile.fileChannel = runtimeTargetFile.fileHandle.getChannel();        }        catch (Exception e)        {          e.printStackTrace();        }        runtimeTargetFiles.put( targetFile.name, runtimeTargetFile );        // track some stats        totalBytes += targetFile.size;        int numChunks = targetFile.chunks.size();        runtimeTargetFile.chunkOffsets = new long[numChunks];        runtimeTargetFile.chunkMap = new char[numChunks];        Iterator chunkiter = targetFile.chunks.iterator();        for ( long nextOffset = 0; chunkiter.hasNext(); )        {          FloodFile.Chunk chunk = (FloodFile.Chunk) chunkiter.next();          RuntimeChunk runtimeChunk           = new RuntimeChunk();          runtimeChunk.index                  = chunk.index;          runtimeChunk.weight                 = chunk.weight;          runtimeChunk.size                   = chunk.size;          runtimeChunk.ownerRuntimeTargetFile = runtimeTargetFile;          runtimeTargetFile.chunks.add(runtimeChunk.index, runtimeChunk);                    // track the offsets          runtimeTargetFile.chunkOffsets[chunk.index] = nextOffset;          // mark it as invalid          runtimeTargetFile.chunkMap[chunk.index] = '0';          // see if the existing chunk is valid          byte[] chunkData = new byte[chunk.size];          try          {            FileLock readLock = null;            try            {              readLock = runtimeTargetFile.fileChannel.tryLock();            }            catch( Exception e)            {              e.printStackTrace();            }                        runtimeTargetFile.fileHandle.seek( nextOffset );            if ( runtimeTargetFile.fileHandle.read(chunkData) == chunk.size )            {              String existingHash = Encoder.SHA1Base64Encode( chunkData, chunk.size );              if ( existingHash.compareTo( chunk.hash ) == 0 )              {                runtimeTargetFile.chunkMap[chunk.index] = '1';                // how many bytes did we start with                bytesAtStartup += chunk.size;              }            }            // FIXME throw some error            else            {            }            readLock.release();          }          catch ( IOException e )          {            e.printStackTrace();          }          if ( runtimeTargetFile.chunkMap[chunk.index] == '0' )          {            chunksToDownload.add( runtimeChunk );          }                    nextOffset += chunk.size;        }      }    }    // how many bytes are we currently missing    bytesMissing = totalBytes - bytesAtStartup;  }