package org.basex.core.cmd;

import static org.basex.core.Text.*;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import org.basex.core.Command;
import org.basex.core.Prop;
import org.basex.core.User;
import org.basex.io.IO;

/**
 * Evaluates the 'copy' command and creates a copy of a database.
 *
 * @author BaseX Team 2005-11, BSD License
 * @author Andreas Weiler
 */
public class Copy extends Command {

  /** Counter for outstanding files. */
  private int of;
  /** Counter of total files. */
  private int tf;

  /**
   * Default constructor.
   * @param db db name
   * @param newdb new db name
   */
  public Copy(final String db, final String newdb) {
    super(User.CREATE, db, newdb);
  }

  @Override
  protected boolean run() {
    final String db = args[0];
    final String newdb = args[1];

    // check if names are valid
    if(!validName(db)) return error(NAMEINVALID, db);
    if(!validName(newdb)) return error(NAMEINVALID, newdb);

    // check if new database already exists
    if(prop.dbexists(newdb)) return error(DBEXISTS, newdb);

    // try to copy database
    return !prop.dbexists(db) ? error(DBNOTFOUND, db) :
      copy(db, newdb, prop) ? info(DBCOPY, db, perf) : error(DBNOCOPY, db);
  }

  /**
   * Copies the specified database.
   * @param db database name
   * @param newdb new database name
   * @param pr database properties
   * @return success flag
   */
  private boolean copy(final String db, final String newdb, final Prop pr) {
    final File src = pr.dbpath(db);
    final File trg = pr.dbpath(newdb);

    // return false if source cannot be opened, or target cannot be created
    final String[] files = src.list();
    if(files == null || !trg.mkdir()) return false;
    tf = files.length;
    boolean ok = true;
    for(final String file : files) {
      of++;
      try {
        copy(new File(src, file), new File(trg, file));
      } catch(final IOException ex) {
        ok = false;
        break;
      }
    }
    // drop new database if error occurred
    if(!ok) DropDB.drop(newdb, pr);
    return ok;
  }

  /**
   * Copies the specified file.
   * @param src source file
   * @param trg target file
   * @throws IOException I/O exception
   */
  public static synchronized void copy(final File src, final File trg)
      throws IOException {

    final byte[] buf = new byte[IO.BLOCKSIZE];
    FileInputStream fis = null;
    FileOutputStream fos = null;
    try {
      fis = new FileInputStream(src);
      fos = new FileOutputStream(trg);
      for(int i; (i = fis.read(buf)) != -1;) fos.write(buf, 0, i);
    } finally {
      if(fis != null) try { fis.close(); } catch(final IOException ex) { }
      if(fos != null) try { fos.close(); } catch(final IOException ex) { }
    }
  }

  @Override
  protected String tit() {
    return BUTTONCOPY;
  }

  @Override
  public boolean supportsProg() {
    return true;
  }

  @Override
  protected double prog() {
    return (double) of / tf;
  }
}

@@ -265,32 +265,8 @@
 ser;
-%0Aimport org.basex.io.IO;
 %0A%0A/*
@@ -2352,48 +2352,101 @@
     
-final byte%5B%5D buf = new byte%5BIO.BLOCKSIZE
+// optimize buffer size%0A    final byte%5B%5D buf = new byte%5B(int) Math.min(src.length(), 1 %3C%3C 22)
 %5D;%0A 

use optimized buffer size for copying files