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

#include "net/base/directory_lister.h"

#include <algorithm>
#include <utility>

#include "base/bind.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_util.h"
#include "base/i18n/file_util_icu.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/task/post_task.h"
#include "base/task_runner.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "base/threading/thread_restrictions.h"
#include "net/base/net_errors.h"

namespace net {

namespace {

bool IsDotDot(const base::FilePath& path) {
  return FILE_PATH_LITERAL("..") == path.BaseName().value();
}

// Comparator for sorting lister results. This uses the locale aware filename
// comparison function on the filenames for sorting in the user's locale.
// Static.
bool CompareAlphaDirsFirst(const DirectoryLister::DirectoryListerData& a,
                           const DirectoryLister::DirectoryListerData& b) {
  // Parent directory before all else.
  if (IsDotDot(a.info.GetName()))
    return true;
  if (IsDotDot(b.info.GetName()))
    return false;

  // Directories before regular files.
  bool a_is_directory = a.info.IsDirectory();
  bool b_is_directory = b.info.IsDirectory();
  if (a_is_directory != b_is_directory)
    return a_is_directory;

  return base::i18n::LocaleAwareCompareFilenames(a.info.GetName(),
                                                 b.info.GetName());
}

void SortData(std::vector<DirectoryLister::DirectoryListerData>* data,
              DirectoryLister::ListingType listing_type) {
  // Sort the results. See the TODO below (this sort should be removed and we
  // should do it from JS).
  if (listing_type == DirectoryLister::ALPHA_DIRS_FIRST) {
    std::sort(data->begin(), data->end(), CompareAlphaDirsFirst);
  } else if (listing_type != DirectoryLister::NO_SORT &&
             listing_type != DirectoryLister::NO_SORT_RECURSIVE) {
    NOTREACHED();
  }
}

}  // namespace

DirectoryLister::DirectoryLister(const base::FilePath& dir,
                                 DirectoryListerDelegate* delegate)
    : DirectoryLister(dir, ALPHA_DIRS_FIRST, delegate) {}

DirectoryLister::DirectoryLister(const base::FilePath& dir,
                                 ListingType type,
                                 DirectoryListerDelegate* delegate)
    : delegate_(delegate) {
  core_ = new Core(dir, type, this);
  DCHECK(delegate_);
  DCHECK(!dir.value().empty());
}

DirectoryLister::~DirectoryLister() {
  Cancel();
}

void DirectoryLister::Start() {
  base::PostTaskWithTraits(
      FROM_HERE,
      {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
      base::Bind(&Core::Start, core_));
}

void DirectoryLister::Cancel() {
  core_->CancelOnOriginSequence();
}

DirectoryLister::Core::Core(const base::FilePath& dir,
                            ListingType type,
                            DirectoryLister* lister)
    : dir_(dir),
      type_(type),
      origin_task_runner_(base::SequencedTaskRunnerHandle::Get().get()),
      lister_(lister),
      cancelled_(0) {
  DCHECK(lister_);
}

DirectoryLister::Core::~Core() = default;

void DirectoryLister::Core::CancelOnOriginSequence() {
  DCHECK(origin_task_runner_->RunsTasksInCurrentSequence());

  base::subtle::NoBarrier_Store(&cancelled_, 1);
  // Core must not call into |lister_| after cancellation, as the |lister_| may
  // have been destroyed. Setting |lister_| to NULL ensures any such access will
  // cause a crash.
  lister_ = nullptr;
}

void DirectoryLister::Core::Start() {
  std::unique_ptr<DirectoryList> directory_list(new DirectoryList());

  if (!base::DirectoryExists(dir_)) {
    origin_task_runner_->PostTask(
        FROM_HERE, base::Bind(&Core::DoneOnOriginSequence, this,
                              base::Passed(std::move(directory_list)),
                              ERR_FILE_NOT_FOUND));
    return;
  }

  int types = base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES;
  bool recursive;
  if (NO_SORT_RECURSIVE != type_) {
    types |= base::FileEnumerator::INCLUDE_DOT_DOT;
    recursive = false;
  } else {
    recursive = true;
  }
  base::FileEnumerator file_enum(dir_, recursive, types);

  base::FilePath path;
  while (!(path = file_enum.Next()).empty()) {
    // Abort on cancellation. This is purely for performance reasons.
    // Correctness guarantees are made by checks in DoneOnOriginSequence.
    if (IsCancelled())
      return;

    DirectoryListerData data;
    data.info = file_enum.GetInfo();
    data.path = path;
    data.absolute_path = base::MakeAbsoluteFilePath(path);
    directory_list->push_back(data);

    /* TODO(brettw) bug 24107: It would be nice to send incremental updates.
       We gather them all so they can be sorted, but eventually the sorting
       should be done from JS to give more flexibility in the page. When we do
       that, we can uncomment this to send incremental updates to the page.

    const int kFilesPerEvent = 8;
    if (file_data.size() < kFilesPerEvent)
      continue;

    origin_loop_->PostTask(
        FROM_HERE,
        base::Bind(&DirectoryLister::Core::SendData, file_data));
    file_data.clear();
    */
  }

  SortData(directory_list.get(), type_);

  origin_task_runner_->PostTask(
      FROM_HERE, base::Bind(&Core::DoneOnOriginSequence, this,
                            base::Passed(std::move(directory_list)), OK));
}

bool DirectoryLister::Core::IsCancelled() const {
  return !!base::subtle::NoBarrier_Load(&cancelled_);
}

void DirectoryLister::Core::DoneOnOriginSequence(
    std::unique_ptr<DirectoryList> directory_list,
    int error) const {
  DCHECK(origin_task_runner_->RunsTasksInCurrentSequence());

  // Need to check if the operation was before first callback.
  if (IsCancelled())
    return;

  for (const auto& lister_data : *directory_list) {
    lister_->OnListFile(lister_data);
    // Need to check if the operation was cancelled during the callback.
    if (IsCancelled())
      return;
  }
  lister_->OnListDone(error);
}

void DirectoryLister::OnListFile(const DirectoryListerData& data) {
  delegate_->OnListFile(data);
}

void DirectoryLister::OnListDone(int error) {
  delegate_->OnListDone(error);
}

}  // namespace net
