// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import AxiomError from 'axiom/core/error';

import FileSystemBinding from 'axiom/bindings/fs/file_system';

import Path from 'axiom/fs/path';
import DomExecuteContext from 'axiom/fs/dom_execute_context';
import DomOpenContext from 'axiom/fs/dom_open_context';

/**
 * @param {FileSystemBinding} opt_binding An optional FileSystemBinding
 * instance to bind to. If not provided, a new binding will be created.
 */
export var DomFileSystem = function(file_system, opt_binding) {
  this.binding = opt_binding || new FileSystemBinding();
  this.fileSystem = file_system;

  this.binding.bind(this, {
    stat: this.stat,
    mkdir: this.mkdir_,
    unlink: this.unlink,
    list: this.list,
    createContext: this.createContext
  });

  this.binding.ready();
};

export default DomFileSystem;

/**
 * This method is not directly reachable through the FileSystemBinding.
 *
 * @param {Path} path
 * @return {ResolveResult}
 */
DomFileSystem.prototype.resolve = function(path) {
  //TODO(grv): resolve directories and read mode bits.
  var domfs = this.fileSystem;
  return new Promise(function(resolve, reject) {
    domfs.root.getFile(path, {create: true}, resolve, reject);
  });
};

/**
 * @param {string} pathSpec
 * @return {Promise<>}
 */
DomFileSystem.prototype.stat = function(pathSpec) {
  var path = new Path(pathSpec);
  if (!path.isValid)
    return Promise.reject(new AxiomError.Invalid('path', pathSpec));

  var rv = this.resolve(path);

  return rv.entry.stat();
};

/**
 * This version of mkdir_ is attached to the FileSystemBinding to ensure that
 * the DomDirectory returned by `mkdir` doesn't leak through the binding.
 *
 * @param {string} pathSpec
 * @return {Promise<>}
 */
DomFileSystem.prototype.mkdir_ = function(pathSpec) {
  return this.mkdir(pathSpec).then(function() { return null; });
};

/**
 * @param {string} pathSpec
 * @return {Promise<>}
 */
DomFileSystem.prototype.mkdir = function(pathSpec) {
  var path = new Path(pathSpec);
  if (!path.isValid)
    return Promise.reject(new AxiomError.Invalid('path', pathSpec));

  var parentPath = path.getParentPath();
  var targetName = path.getBaseName();


  var rv = this.resolve(parentPath);

  if (!rv.entry.hasMode('d'))
    return Promise.reject(new AxiomError.TypeMismatch('dir', parentPath.spec));

  return rv.entry.mkdir(targetName);
};

/**
 * Create an alias from a path on this file system to a different path on this
 * file system.
 *
 * If the "from" path is on a different fs, we'll forward the call.  If "from"
 * is on this fs but "to" is not, the move will fail.
 *
 * The destination path must refer to a file that does not yet exist, inside a
 * directory that does.
 *
 * @param {string} pathSpecFrom
 * @param {string} pathSpecTo
 * @return {Promise<>}
 */
DomFileSystem.prototype.alias = function(pathSpecFrom, pathSpecTo) {
    return Promise.reject(new AxiomError.Invalid('path', 'not supported yet.'));
};

/**
 * Move an entry from a path on this file system to a different path on this
 * file system.
 *
 * If the "from" path is on a different fs, we'll forward the call.  If "from"
 * is on this fs but "to" is not, the move will fail.
 *
 * The destination path must refer to a file that does not yet exist, inside a
 * directory that does.
 *
 * @param {string} pathSpecFrom
 * @param {string} pathSpecTo
 * @return {Promise<>}
 */
DomFileSystem.prototype.move = function(fromPathSpec, toPathSpec) {
    return Promise.reject(new AxiomError.Invalid('path', 'not supported yet.'));
};

/**
 * @param {string} pathSpec
 * @return {Promise<>}
 */
DomFileSystem.prototype.unlink = function(pathSpec) {
    return Promise.reject(new AxiomError.Invalid('path', 'not supported yet.'));
};

/**
 * @param {string} pathSpec
 * @return {Promise<>}
 */
DomFileSystem.prototype.list = function(pathSpec) {
    return Promise.reject(new AxiomError.Invalid('path', 'not supported yet.'));
};

/**
 * @param {string} contextType ('execute' | 'open')
 * @param {string} pathSpec
 * @param {Object} arg
 */
DomFileSystem.prototype.createContext = function(contextType, pathSpec, arg) {
  var path = new Path(pathSpec);
  if (!path.isValid)
    return Promise.reject(new AxiomError.Invalid('path', pathSpec));

  var domfs = this;
  return this.resolve(path).then(function(entry) {
    var cx;
    if (contextType == 'execute') {
      cx = new DomExecuteContext(this, path, entry, arg);
    } else if (contextType == 'open') {
      cx = new DomOpenContext(domfs, path, entry, arg);
    } else {
      return Promise.reject(new AxiomError.Invalid('contextType', contextType));
    }
    return Promise.resolve(cx.binding);
  }).catch(function(e) {
     throw new AxiomError.Runtime(e.toString());
  });
};

@@ -4393,61 +4393,8 @@
 is;%0A
-  return this.resolve(path).then(function(entry) %7B%0A  
   va
@@ -4399,18 +4399,16 @@
 var cx;%0A
-  
   if (co
@@ -4429,26 +4429,24 @@
 execute') %7B%0A
-  
     cx = new
@@ -4475,32 +4475,23 @@
 s, path,
- entry,
  arg);%0A
-  
   %7D else
@@ -4524,18 +4524,16 @@
 ) %7B%0A    
- 
- 
 cx = new
@@ -4564,15 +4564,8 @@
 ath,
- entry,
  arg
@@ -4569,18 +4569,16 @@
 arg);%0A  
- 
- 
 %7D else %7B
@@ -4578,18 +4578,16 @@
  else %7B%0A
-  
     retu
@@ -4661,18 +4661,14 @@
 ));%0A
-  
   %7D%0A  
- 
- 
 retu
@@ -4703,87 +4703,7 @@
 g);%0A
-  %7D).catch(function(e) %7B%0A     throw new AxiomError.Runtime(e.toString());%0A  %7D);%0A
 %7D;%0A

make create context sync.