// Copyright (c) 2013 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.

#include "p2p/server/file_watcher.h"

#include <gio/gio.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include <algorithm>

#include <base/logging.h>

using std::string;
using std::vector;

using base::FilePath;

namespace p2p {

namespace server {

class FileWatcherGLib : public FileWatcher {
 public:
  FileWatcherGLib(const FilePath& dir, const string& file_extension);
  FileWatcherGLib(const FileWatcherGLib&) = delete;
  FileWatcherGLib& operator=(const FileWatcherGLib&) = delete;

  ~FileWatcherGLib() override;

  const vector<FilePath>& files() const override;

  const FilePath& dir() const override;
  const string& file_extension() const override;

  void SetChangedCallback(FileWatcherCallback changed_callback) override;

  bool Init();

 private:
  // Looks at all files in |dir_| and sees if anything has
  // changed. Usually called from the file monitoring callback from
  // the kernel (inotify via GFileMonitor). The |changed_file|
  // parameter should be NULL unless the kernel indicates the given
  // file has changed. Updates the |files_| member.
  void ReloadDir(const FilePath* changed_file);

  // Used for handling the GFileMonitor::changed GLib signal.
  static void OnMonitorChanged(GFileMonitor* monitor,
                               GFile* file,
                               GFile* other_file,
                               GFileMonitorEvent event_type,
                               gpointer user_data);

  // The directory we monitor.
  FilePath dir_;

  // The file extension for files we are interested in, e.g. ".p2p".
  string file_extension_;

  // The callback set by the user of our callback.
  FileWatcherCallback changed_callback_;

  // The current set of files in |dir_|. Is updated by ReloadDir().
  vector<FilePath> files_;

  // The GLib abstraction used to interface with the kernel's inotify
  // subsystem.
  GFileMonitor* monitor_;
};

const FilePath& FileWatcherGLib::dir() const {
  return dir_;
}

const string& FileWatcherGLib::file_extension() const {
  return file_extension_;
}

void FileWatcherGLib::OnMonitorChanged(GFileMonitor* monitor,
                                       GFile* file,
                                       GFile* other_file,
                                       GFileMonitorEvent event_type,
                                       gpointer user_data) {
  FileWatcherGLib* file_watcher = reinterpret_cast<FileWatcherGLib*>(user_data);

  // Ignore hints
  if (event_type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT)
    return;

  // Ignore files not matching the extension
  gchar* file_name = g_file_get_path(file);
  if (!g_str_has_suffix(file_name, file_watcher->file_extension_.c_str())) {
    g_free(file_name);
    return;
  }

  VLOG(2) << "OnMonitorChanged, event_type=" << event_type
          << " file=" << file_name;
  FilePath path(file_name);
  file_watcher->ReloadDir(&path);
  g_free(file_name);
}

FileWatcherGLib::FileWatcherGLib(const FilePath& dir,
                                 const string& file_extension)
    : dir_(dir), file_extension_(file_extension) {}

bool FileWatcherGLib::Init() {
  GFile* file;
  GError* error = NULL;

  file = g_file_new_for_path(dir_.value().c_str());
  monitor_ = g_file_monitor_directory(file, G_FILE_MONITOR_NONE,
                                      NULL, /* GCancellable */
                                      &error);
  if (monitor_ == NULL) {
    LOG(ERROR) << "Error monitoring directory " << dir_.value() << ": "
               << error->message << "(" << error->code << ", "
               << g_quark_to_string(error->domain) << ")";
    g_clear_error(&error);
    return false;
  } else {
    g_signal_connect(monitor_, "changed", G_CALLBACK(OnMonitorChanged), this);
  }

  ReloadDir(NULL);

  g_clear_object(&file);
  return true;
}

FileWatcherGLib::~FileWatcherGLib() {
  if (monitor_ != NULL) {
    g_signal_handlers_disconnect_by_func(monitor_, (gpointer)OnMonitorChanged,
                                         this);
    g_file_monitor_cancel(monitor_);
    g_clear_object(&monitor_);
  }
}

void FileWatcherGLib::SetChangedCallback(FileWatcherCallback changed_callback) {
  changed_callback_ = changed_callback;
}

static void diff_sorted_vectors(
    const vector<FilePath>::iterator& a_first,
    const vector<FilePath>::iterator& a_last,
    const vector<FilePath>::iterator& b_first,
    const vector<FilePath>::iterator& b_last,
    vector<FilePath>* added,        // in b, not in a
    vector<FilePath>* removed,      // in a, not in b
    vector<FilePath>* unchanged) {  // in both a and b
  vector<FilePath>::const_iterator ai = a_first;
  vector<FilePath>::const_iterator bi = b_first;

  while (ai != a_last && bi != b_last) {
    int order = ai->value().compare(bi->value());
    if (order < 0) {
      // *ai > *bi
      removed->push_back(*ai);
      ++ai;
    } else if (order > 0) {
      // *ai < *bi
      added->push_back(*bi);
      ++bi;
    } else {
      // *ai == *bi
      unchanged->push_back(*bi);
      ++ai;
      ++bi;
    }
  }

  while (ai != a_last) {
    removed->push_back(*ai);
    ++ai;
  }

  while (bi != b_last) {
    added->push_back(*bi);
    ++bi;
  }
}

void FileWatcherGLib::ReloadDir(const FilePath* changed_file) {
  GDir* dir;
  GError* error = NULL;
  const char* name;
  vector<FilePath> new_files;

  VLOG(2) << "in ReloadDir(), dir=" << dir_.value() << "file="
          << (changed_file != NULL ? changed_file->value() : "(none)");

  dir = g_dir_open(dir_.value().c_str(), 0, &error);
  if (dir == NULL) {
    LOG(ERROR) << "Error opening directory " << dir_.value() << ": "
               << error->message << "(" << error->code << ", "
               << g_quark_to_string(error->domain) << ")";
    return;
  }

  while ((name = g_dir_read_name(dir)) != NULL) {
    if (file_extension_.length() > 0 &&
        g_str_has_suffix(name, file_extension_.c_str())) {
      new_files.push_back(dir_.Append(name));
    }
  }
  g_dir_close(dir);

  vector<FilePath> added;
  vector<FilePath> removed;
  vector<FilePath> unchanged;
  std::sort(new_files.begin(), new_files.end());
  // TODO(zeuthen): actually unnecessary to sort files_
  std::sort(files_.begin(), files_.end());
  diff_sorted_vectors(files_.begin(), files_.end(), new_files.begin(),
                      new_files.end(), &added, &removed, &unchanged);
  files_ = new_files;

  if (!changed_callback_.is_null()) {
    for (auto const& i : removed) {
      VLOG(2) << "Emitting kFileRemoved for file " << i.value();
      changed_callback_.Run(i, FileWatcher::EventType::kFileRemoved);
    }
    for (auto const& i : unchanged) {
      if (changed_file != NULL && *changed_file == i) {
        VLOG(2) << "Emitting kFileChanged for file " << i.value();
        changed_callback_.Run(i, FileWatcher::EventType::kFileChanged);
      }
    }
    for (auto const& i : added) {
      VLOG(2) << "Emitting kFileAdded for file " << i.value();
      changed_callback_.Run(i, FileWatcher::EventType::kFileAdded);
    }
  }
}

const vector<FilePath>& FileWatcherGLib::files() const {
  return files_;
}

// -----------------------------------------------------------------------------

FileWatcher* FileWatcher::Construct(const FilePath& dir,
                                    const string& file_extension) {
  FileWatcherGLib* instance = new FileWatcherGLib(dir, file_extension);
  if (!instance->Init()) {
    delete instance;
    return NULL;
  }
  return instance;
}

}  // namespace server

}  // namespace p2p
