// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

part of file.src.backends.memory;

class _MemoryDirectory extends _MemoryFileSystemEntity implements Directory {
  static int _tempCounter = 0;

  _MemoryDirectory(MemoryFileSystem fileSystem, String path)
      : super(fileSystem, path);

  @override
  io.FileSystemEntityType get expectedType => io.FileSystemEntityType.DIRECTORY;

  @override
  Uri get uri => new Uri.directory(path);

  @override
  bool existsSync() => _backingOrNull?.stat?.type == expectedType;

  @override
  Future<Directory> create({bool recursive: false}) async {
    createSync(recursive: recursive);
    return this;
  }

  @override
  void createSync({bool recursive: false}) {
    _Node node = _createSync(
      followTailLink: true,
      visitLinks: true,
      createChild: (_DirectoryNode parent, bool isFinalSegment) {
        if (recursive || isFinalSegment) {
          return new _DirectoryNode(parent);
        }
        return null;
      },
    );
    if (node.type != expectedType) {
      // There was an existing non-directory node at this object's path
      throw common.notADirectory(path);
    }
  }

  @override
  Future<Directory> createTemp([String prefix]) async => createTempSync(prefix);

  @override
  Directory createTempSync([String prefix]) {
    prefix = (prefix ?? '') + 'rand';
    String fullPath = fileSystem.path.join(path, prefix);
    String dirname = fileSystem.path.dirname(fullPath);
    String basename = fileSystem.path.basename(fullPath);
    _DirectoryNode node = fileSystem._findNode(dirname);
    _checkExists(node, () => dirname);
    _checkIsDir(node, () => dirname);
    String name() => '$basename$_tempCounter';
    while (node.children.containsKey(name())) {
      _tempCounter++;
    }
    _DirectoryNode tempDir = new _DirectoryNode(node);
    node.children[name()] = tempDir;
    return new _MemoryDirectory(
        fileSystem, fileSystem.path.join(dirname, name()));
  }

  @override
  Future<Directory> rename(String newPath) async => renameSync(newPath);

  @override
  Directory renameSync(String newPath) => _renameSync(
        newPath,
        validateOverwriteExistingEntity: (_DirectoryNode existingNode) {
          if (existingNode.children.isNotEmpty) {
            throw common.directoryNotEmpty(newPath);
          }
        },
      );

  @override
  Directory get parent =>
      (_backingOrNull?.isRoot ?? false) ? this : super.parent;

  @override
  Directory get absolute => super.absolute;

  @override
  Stream<FileSystemEntity> list({
    bool recursive: false,
    bool followLinks: true,
  }) =>
      new Stream<FileSystemEntity>.fromIterable(listSync(
        recursive: recursive,
        followLinks: followLinks,
      ));

  @override
  List<FileSystemEntity> listSync({
    bool recursive: false,
    bool followLinks: true,
  }) {
    _DirectoryNode node = _backing;
    List<FileSystemEntity> listing = <FileSystemEntity>[];
    List<_PendingListTask> tasks = <_PendingListTask>[
      new _PendingListTask(
        node,
        path.endsWith(_separator) ? path.substring(0, path.length - 1) : path,
        new Set<_LinkNode>(),
      ),
    ];
    while (tasks.isNotEmpty) {
      _PendingListTask task = tasks.removeLast();
      task.dir.children.forEach((String name, _Node child) {
        Set<_LinkNode> breadcrumbs = new Set<_LinkNode>.from(task.breadcrumbs);
        String childPath = fileSystem.path.join(task.path, name);
        while (followLinks && _isLink(child) && breadcrumbs.add(child)) {
          _Node referent = (child as _LinkNode).referentOrNull;
          if (referent != null) {
            child = referent;
          }
        }
        if (_isDirectory(child)) {
          listing.add(new _MemoryDirectory(fileSystem, childPath));
          if (recursive) {
            tasks.add(new _PendingListTask(child, childPath, breadcrumbs));
          }
        } else if (_isLink(child)) {
          listing.add(new _MemoryLink(fileSystem, childPath));
        } else if (_isFile(child)) {
          listing.add(new _MemoryFile(fileSystem, childPath));
        }
      });
    }
    return listing;
  }

  @override
  Directory _clone(String path) => new _MemoryDirectory(fileSystem, path);

  @override
  String toString() => "MemoryDirectory: '$path'";
}

class _PendingListTask {
  final _DirectoryNode dir;
  final String path;
  final Set<_LinkNode> breadcrumbs;
  _PendingListTask(this.dir, this.path, this.breadcrumbs);
}
