text: // Copyright (c) 2014 GitHub, Inc.
  // Use of this source code is governed by the MIT license that can be
  // found in the LICENSE file.
  
  #include "shell/browser/api/atom_api_notification.h"
  
  #include "base/guid.h"
  #include "base/strings/utf_string_conversions.h"
  #include "native_mate/constructor.h"
  #include "shell/browser/api/atom_api_menu.h"
  #include "shell/browser/atom_browser_client.h"
  #include "shell/browser/browser.h"
  #include "shell/common/gin_converters/image_converter.h"
  #include "shell/common/gin_helper/dictionary.h"
  #include "shell/common/gin_helper/object_template_builder.h"
  #include "shell/common/node_includes.h"
  #include "url/gurl.h"
  
  namespace gin {
  
  template <>
  struct Converter<electron::NotificationAction> {
    static bool FromV8(v8::Isolate* isolate,
                       v8::Local<v8::Value> val,
                       electron::NotificationAction* out) {
      gin::Dictionary dict(isolate);
      if (!ConvertFromV8(isolate, val, &dict))
        return false;
  
      if (!dict.Get("type", &(out->type))) {
        return false;
      }
      dict.Get("text", &(out->text));
      return true;
    }
  
    static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
                                     electron::NotificationAction val) {
      gin::Dictionary dict = gin::Dictionary::CreateEmpty(isolate);
      dict.Set("text", val.text);
      dict.Set("type", val.type);
      return ConvertToV8(isolate, dict);
    }
  };
  
  }  // namespace gin
  
  namespace electron {
  
  namespace api {
  
  Notification::Notification(gin::Arguments* args) {
    InitWithArgs(args);
  
    presenter_ = static_cast<AtomBrowserClient*>(AtomBrowserClient::Get())
                     ->GetNotificationPresenter();
  
    gin::Dictionary opts(nullptr);
    if (args->GetNext(&opts)) {
      opts.Get("title", &title_);
      opts.Get("subtitle", &subtitle_);
      opts.Get("body", &body_);
      has_icon_ = opts.Get("icon", &icon_);
      if (has_icon_) {
        opts.Get("icon", &icon_path_);
      }
      opts.Get("silent", &silent_);
      opts.Get("replyPlaceholder", &reply_placeholder_);
      opts.Get("urgency", &urgency_);
      opts.Get("hasReply", &has_reply_);
      opts.Get("timeoutType", &timeout_type_);
      opts.Get("actions", &actions_);
      opts.Get("sound", &sound_);
      opts.Get("closeButtonText", &close_button_text_);
    }
  }
  
  Notification::~Notification() {
    if (notification_)
      notification_->set_delegate(nullptr);
  }
  
  // static
  mate::WrappableBase* Notification::New(gin_helper::ErrorThrower thrower,
                                         gin::Arguments* args) {
    if (!Browser::Get()->is_ready()) {
      thrower.ThrowError("Cannot create Notification before app is ready");
      return nullptr;
    }
    return new Notification(args);
  }
  
  // Getters
  base::string16 Notification::GetTitle() const {
    return title_;
  }
  
  base::string16 Notification::GetSubtitle() const {
    return subtitle_;
  }
  
  base::string16 Notification::GetBody() const {
    return body_;
  }
  
  bool Notification::GetSilent() const {
    return silent_;
  }
  
  bool Notification::GetHasReply() const {
    return has_reply_;
  }
  
  base::string16 Notification::GetTimeoutType() const {
    return timeout_type_;
  }
  
  base::string16 Notification::GetReplyPlaceholder() const {
    return reply_placeholder_;
  }
  
  base::string16 Notification::GetSound() const {
    return sound_;
  }
  
  base::string16 Notification::GetUrgency() const {
    return urgency_;
  }
  
  std::vector<electron::NotificationAction> Notification::GetActions() const {
    return actions_;
  }
  
  base::string16 Notification::GetCloseButtonText() const {
    return close_button_text_;
  }
  
  // Setters
  void Notification::SetTitle(const base::string16& new_title) {
    title_ = new_title;
  }
  
  void Notification::SetSubtitle(const base::string16& new_subtitle) {
    subtitle_ = new_subtitle;
  }
  
  void Notification::SetBody(const base::string16& new_body) {
    body_ = new_body;
  }
  
  void Notification::SetSilent(bool new_silent) {
    silent_ = new_silent;
  }
  
  void Notification::SetHasReply(bool new_has_reply) {
    has_reply_ = new_has_reply;
  }
  
  void Notification::SetTimeoutType(const base::string16& new_timeout_type) {
    timeout_type_ = new_timeout_type;
  }
  
  void Notification::SetReplyPlaceholder(const base::string16& new_placeholder) {
    reply_placeholder_ = new_placeholder;
  }
  
  void Notification::SetSound(const base::string16& new_sound) {
    sound_ = new_sound;
  }
  
  void Notification::SetUrgency(const base::string16& new_urgency) {
    urgency_ = new_urgency;
  }
  
  void Notification::SetActions(
      const std::vector<electron::NotificationAction>& actions) {
    actions_ = actions;
  }
  
  void Notification::SetCloseButtonText(const base::string16& text) {
    close_button_text_ = text;
  }
  
  void Notification::NotificationAction(int index) {
    Emit("action", index);
  }
  
  void Notification::NotificationClick() {
    Emit("click");
  }
  
  void Notification::NotificationReplied(const std::string& reply) {
    Emit("reply", reply);
  }
  
  void Notification::NotificationDisplayed() {
    Emit("show");
  }
  
  void Notification::NotificationDestroyed() {}
  
  void Notification::NotificationClosed() {
    Emit("close");
  }
  
  void Notification::Close() {
    if (notification_) {
      notification_->Dismiss();
      notification_->set_delegate(nullptr);
      notification_.reset();
    }
  }
  
  // Showing notifications
  void Notification::Show() {
    Close();
    if (presenter_) {
      notification_ = presenter_->CreateNotification(this, base::GenerateGUID());
      if (notification_) {
        electron::NotificationOptions options;
        options.title = title_;
        options.subtitle = subtitle_;
        options.msg = body_;
        options.icon_url = GURL();
        options.icon = icon_.AsBitmap();
        options.silent = silent_;
        options.has_reply = has_reply_;
        options.timeout_type = timeout_type_;
        options.reply_placeholder = reply_placeholder_;
        options.actions = actions_;
        options.sound = sound_;
        options.close_button_text = close_button_text_;
        options.urgency = urgency_;
        notification_->Show(options);
      }
    }
  }
  
  bool Notification::IsSupported() {
    return !!static_cast<AtomBrowserClient*>(AtomBrowserClient::Get())
                 ->GetNotificationPresenter();
  }
  
  // static
  void Notification::BuildPrototype(v8::Isolate* isolate,
                                    v8::Local<v8::FunctionTemplate> prototype) {
    prototype->SetClassName(gin::StringToV8(isolate, "Notification"));
    gin_helper::Destroyable::MakeDestroyable(isolate, prototype);
    gin_helper::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
        .SetMethod("show", &Notification::Show)
        .SetMethod("close", &Notification::Close)
        .SetProperty("title", &Notification::GetTitle, &Notification::SetTitle)
        .SetProperty("subtitle", &Notification::GetSubtitle,
                     &Notification::SetSubtitle)
        .SetProperty("body", &Notification::GetBody, &Notification::SetBody)
        .SetProperty("silent", &Notification::GetSilent, &Notification::SetSilent)
        .SetProperty("hasReply", &Notification::GetHasReply,
                     &Notification::SetHasReply)
        .SetProperty("timeoutType", &Notification::GetTimeoutType,
                     &Notification::SetTimeoutType)
        .SetProperty("replyPlaceholder", &Notification::GetReplyPlaceholder,
                     &Notification::SetReplyPlaceholder)
        .SetProperty("urgency", &Notification::GetUrgency,
                     &Notification::SetUrgency)
        .SetProperty("sound", &Notification::GetSound, &Notification::SetSound)
        .SetProperty("actions", &Notification::GetActions,
                     &Notification::SetActions)
        .SetProperty("closeButtonText", &Notification::GetCloseButtonText,
                     &Notification::SetCloseButtonText);
  }
  
  }  // namespace api
  
  }  // namespace electron
  
  namespace {
  
  using electron::api::Notification;
  
  void Initialize(v8::Local<v8::Object> exports,
                  v8::Local<v8::Value> unused,
                  v8::Local<v8::Context> context,
                  void* priv) {
    v8::Isolate* isolate = context->GetIsolate();
    Notification::SetConstructor(isolate,
                                 base::BindRepeating(&Notification::New));
  
    gin_helper::Dictionary dict(isolate, exports);
    dict.Set("Notification", Notification::GetConstructor(isolate)
                                 ->GetFunction(context)
                                 .ToLocalChecked());
  
    dict.SetMethod("isSupported", &Notification::IsSupported);
  }
  
  }  // namespace
  
  NODE_LINKED_MODULE_CONTEXT_AWARE(atom_common_notification, Initialize)
  