/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "IOEventLoop.h"

#include <event2/event.h>
#include <fcntl.h>

#include <android-base/logging.h>

struct IOEvent {
  IOEventLoop* loop;
  event* e;
  std::function<bool()> callback;
  bool enabled;

  IOEvent(IOEventLoop* loop, const std::function<bool()>& callback)
      : loop(loop), e(nullptr), callback(callback), enabled(false) {}

  ~IOEvent() {
    if (e != nullptr) {
      event_free(e);
    }
  }
};

IOEventLoop::IOEventLoop() : ebase_(nullptr), has_error_(false) {}

IOEventLoop::~IOEventLoop() {
  events_.clear();
  if (ebase_ != nullptr) {
    event_base_free(ebase_);
  }
}

bool IOEventLoop::EnsureInit() {
  if (ebase_ == nullptr) {
    ebase_ = event_base_new();
    if (ebase_ == nullptr) {
      LOG(ERROR) << "failed to call event_base_new()";
      return false;
    }
  }
  return true;
}

void IOEventLoop::EventCallbackFn(int, short, void* arg) {
  IOEvent* e = static_cast<IOEvent*>(arg);
  if (!e->callback()) {
    e->loop->has_error_ = true;
    e->loop->ExitLoop();
  }
}

static bool MakeFdNonBlocking(int fd) {
  int flags = fcntl(fd, F_GETFL, 0);
  if (flags == -1 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
    PLOG(ERROR) << "fcntl() failed";
    return false;
  }
  return true;
}

IOEventRef IOEventLoop::AddReadEvent(int fd,
                                     const std::function<bool()>& callback) {
  if (!MakeFdNonBlocking(fd)) {
    return nullptr;
  }
  return AddEvent(fd, EV_READ | EV_PERSIST, nullptr, callback);
}

IOEventRef IOEventLoop::AddWriteEvent(int fd,
                                      const std::function<bool()>& callback) {
  if (!MakeFdNonBlocking(fd)) {
    return nullptr;
  }
  return AddEvent(fd, EV_WRITE | EV_PERSIST, nullptr, callback);
}

bool IOEventLoop::AddSignalEvent(int sig,
                                 const std::function<bool()>& callback) {
  return AddEvent(sig, EV_SIGNAL | EV_PERSIST, nullptr, callback) != nullptr;
}

bool IOEventLoop::AddSignalEvents(std::vector<int> sigs,
                                  const std::function<bool()>& callback) {
  for (auto sig : sigs) {
    if (!AddSignalEvent(sig, callback)) {
      return false;
    }
  }
  return true;
}

bool IOEventLoop::AddPeriodicEvent(timeval duration,
                                   const std::function<bool()>& callback) {
  return AddEvent(-1, EV_PERSIST, &duration, callback) != nullptr;
}

IOEventRef IOEventLoop::AddEvent(int fd_or_sig, short events, timeval* timeout,
                                 const std::function<bool()>& callback) {
  if (!EnsureInit()) {
    return nullptr;
  }
  std::unique_ptr<IOEvent> e(new IOEvent(this, callback));
  e->e = event_new(ebase_, fd_or_sig, events, EventCallbackFn, e.get());
  if (e->e == nullptr) {
    LOG(ERROR) << "event_new() failed";
    return nullptr;
  }
  if (event_add(e->e, timeout) != 0) {
    LOG(ERROR) << "event_add() failed";
    return nullptr;
  }
  e->enabled = true;
  events_.push_back(std::move(e));
  return events_.back().get();
}

bool IOEventLoop::RunLoop() {
  if (event_base_dispatch(ebase_) == -1) {
    LOG(ERROR) << "event_base_dispatch() failed";
    return false;
  }
  if (has_error_) {
    return false;
  }
  return true;
}

bool IOEventLoop::ExitLoop() {
  if (event_base_loopbreak(ebase_) == -1) {
    LOG(ERROR) << "event_base_loopbreak() failed";
    return false;
  }
  return true;
}

bool IOEventLoop::DisableEvent(IOEventRef ref) {
  if (ref->enabled) {
    if (event_del(ref->e) != 0) {
      LOG(ERROR) << "event_del() failed";
      return false;
    }
    ref->enabled = false;
  }
  return true;
}

bool IOEventLoop::EnableEvent(IOEventRef ref) {
  if (!ref->enabled) {
    if (event_add(ref->e, nullptr) != 0) {
      LOG(ERROR) << "event_add() failed";
      return false;
    }
    ref->enabled = true;
  }
  return true;
}

bool IOEventLoop::DelEvent(IOEventRef ref) {
  DisableEvent(ref);
  IOEventLoop* loop = ref->loop;
  for (auto it = loop->events_.begin(); it != loop->events_.end(); ++it) {
    if (it->get() == ref) {
      loop->events_.erase(it);
      break;
    }
  }
  return true;
}
