import storage from 'src/database/storage';
import Folder from './folder';
import idMap from './idmap';

/* Error Messages */
const ERROR_EMPTY_STRING = 'Attempting to rename file with an empty string';
const ERROR_SAME_FILE_NAME = 'Another file in the current folder has the same name';
const ERROR_MOVING_TO_SAME_FOLDER = 'Attempting to move to current folder';
const ERROR_MOVING_TO_INVALID_FOLDER = 'Attempting to move to an invalid folder';
const ERROR_NOT_FILE_INSTANCE = '"this" is not an instance of "File"';
const ERROR_CONTAIN_ILLEGAL_CHARACTERS = 'New file name contains illegal character(s)';

/* Constant */
const ILLEGAL_CHARACTERS = /^[`~!@#$%^&*()-_=+\\|[\]{};:'",<.>/?]+$/;

/**
* File Object
*
* @param {Number} fileID
* @param {String} fileName
* @param {String} filePath
*/
export default function File(fileID, fileName, filePath, parentFolder) {
  this.id = fileID;
  this.name = fileName;
  this.path = filePath;
  this.parentFolder = parentFolder;
}

/* Private Functions */
/**
 * Check if destination folder is current folder this file resides in
 *
 * @param {Folder} destFolder
 * @return {Boolean}
 */
function isCurrentFolder(destFolder) {
  if (!(this instanceof File)) {
    throw new Error(ERROR_NOT_FILE_INSTANCE);
  }
  return destFolder.id === this.parentFolder.id;
}

/**
 * Check if destination folder is null
 *
 * @param {Folder} destFolder
 * @return {Boolean}
 */
function isInvalidFolder(destFolder) {
  return Folder.getFolder(destFolder.id) == null;
}

/**
 * Check if new filename is the same as another filename
 *
 * @param {String} newFileName
 * @return {Boolean}
 */
function hasSameFileName(newFileName) {
  if (!(this instanceof File)) {
    throw new Error(ERROR_NOT_FILE_INSTANCE);
  }
  const currParentFolder = this.parentFolder;
  let currFile;
  let sameFileName = false;
  for (let index = 0; index < currParentFolder.childFileList.length; index += 1) {
    currFile = currParentFolder.childFileList[index];
    /* eslint no-continue:0 */
    if (newFileName === this.name) {
      continue;
    }
    if (newFileName === currFile.name) {
      sameFileName = true;
      break;
    }
  }
  return sameFileName;
}

/**
 * Remove file from the database
 *
 * @return {Promise}
 */
File.prototype.remove = function remove() {
  return storage.deleteFile(this.id)
    .then(() => {
      idMap.removeFileFromMap(this.id);
      const parentFolder = this.parentFolder;
      const index = parentFolder.childFileList.indexOf(this);
      parentFolder.childFileList.splice(index, 1);
    })
    .catch((error) => {
      throw error;
    });
};

/**
 * Save data into file
 *
 * @param {String} data
 * @return {}
 */
File.prototype.save = function save(data) {
  return storage.saveFile(this.id, data);
};

/**
 * Load data from file
 *
 * @param {}
 * @return {String} data loaded from file
 */
File.prototype.load = function load() {
  return storage.loadFile(this.id);
};

/**
 * Move file to a specified folder
 *
 * @param {Folder} destFolder
 * @return {Promise}
 */
File.prototype.move = function move(destFolder) {
  return new Promise((resolve, reject) => {
    if (isCurrentFolder.call(this, destFolder)) {
      reject(ERROR_MOVING_TO_SAME_FOLDER);
    }

    if (isInvalidFolder(destFolder)) {
      reject(ERROR_MOVING_TO_INVALID_FOLDER);
    }

    resolve();
  })
  .then(() => storage.moveFile(this.id, destFolder.id))
  .then(() => {
    destFolder.childFileList.push(this);
    const index = this.parentFolder.childFileList.indexOf(this);
    this.parentFolder.childFileList.splice(index, 1);
    this.parentFolder = destFolder;
  });
};

/**
 * Rename file
 *
 * @param {String} newFileName
 * @return {Promise}
 */
File.prototype.rename = function rename(newFileName) {
  if (!(this instanceof Folder)) {
    throw new Error(ERROR_NOT_FILE_INSTANCE);
  }

  newFileName = newFileName.trim();
  if (!newFileName) {
    return new Promise((resolve, reject) => reject(ERROR_EMPTY_STRING));
  } else if (this.name === newFileName) {
    return new Promise((resolve, reject) => resolve());
  } else if (newFileName.match(ILLEGAL_CHARACTERS)) {
    return new Promise((resolve, reject) => reject(ERROR_CONTAIN_ILLEGAL_CHARACTERS));
  } else if (hasSameFileName.call(this, newFileName)) {
    return new Promise((resolve, reject) => reject(ERROR_SAME_FILE_NAME));
  } else {
    return storage.renameFile(this.id, newFileName)
    .then(() => {
      const oldFileName = this.name;
      this.name = newFileName;
      this.path = this.path.replace(oldFileName, newFileName);
    });
  }
};

@@ -3600,24 +3600,430 @@
 ;%0A  %7D);%0A%7D;%0A%0A
+/**%0A * Make a copy of a file in the current Folder%0A *%0A * @return %7BPromise%7D%0A */%0AFile.prototype.copy = function copy() %7B%0A  return storage.copyFile(this.id)%0A  .then((dbCopiedFile) =%3E %7B%0A    const copiedFile = new File(dbCopiedFile.file_id, dbCopiedFile.file_name, dbCopiedFile.file_path, this);%0A    this.parentFolder.childFileList.push(copiedFile);%0A    idMap.addFileToMap(copiedFile.id, copiedFile);%0A  %7D);%0A%7D;%0A%0A
 /**%0A * Renam

Add copy function