// 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 <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include <gio/gio.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);

  virtual ~FileWatcherGLib();

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

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

  virtual void SetChangedCallback(FileWatcherCallback changed_callback);

  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_;

  DISALLOW_COPY_AND_ASSIGN(FileWatcherGLib);
};

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_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
