/*******************************************************************************
*                         Goggles Music Manager                                *
********************************************************************************
*           Copyright (C) 2007-2010 by Sander Jansen. All Rights Reserved      *
*                               ---                                            *
* This program is free software: you can redistribute it and/or modify         *
* it under the terms of the GNU General Public License as published by         *
* the Free Software Foundation, either version 3 of the License, or            *
* (at your option) any later version.                                          *
*                                                                              *
* This program is distributed in the hope that it will be useful,              *
* but WITHOUT ANY WARRANTY; without even the implied warranty of               *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                *
* GNU General Public License for more details.                                 *
*                                                                              *
* You should have received a copy of the GNU General Public License            *
* along with this program.  If not, see http://www.gnu.org/licenses.           *
********************************************************************************/
#ifdef HAVE_DBUS
#include "common.h"
#include "fxdbus.h"
#include "GMNotifyDaemon.h"

#define NOTIFY_NAME "org.freedesktop.Notifications"
#define NOTIFY_PATH "/org/freedesktop/Notifications"
#define NOTIFY_INTERFACE "org.freedesktop.Notifications"

FXDEFMAP(GMNotifyDaemon) GMNotifyDaemonMap[]={
  FXMAPFUNC(SEL_COMMAND,GMNotifyDaemon::ID_NOTIFY_RESULT,GMNotifyDaemon::onCmdNotify),
  FXMAPFUNC(SEL_COMMAND,GMNotifyDaemon::ID_NOTIFY_CLOSE,GMNotifyDaemon::onCmdClose)
  };

FXIMPLEMENT(GMNotifyDaemon,FXObject,GMNotifyDaemonMap,ARRAYNUMBER(GMNotifyDaemonMap));

static DBusHandlerResult dbus_notifydaemon_filter(DBusConnection *,DBusMessage * msg,void * data){
  GMNotifyDaemon * daemon = (GMNotifyDaemon*)data;
  if (dbus_message_has_path(msg,NOTIFY_PATH)){
    if (dbus_message_is_signal(msg,NOTIFY_INTERFACE,"NotificationClosed")){
      FXuint msgid=0,reason=0;
      if (dbus_message_has_signature(msg,"u")) {
        if (dbus_message_get_args(msg,NULL,DBUS_TYPE_UINT32,&msgid,DBUS_TYPE_INVALID)) {
          daemon->closed(msgid);
          }
        }
      else if (dbus_message_has_signature(msg,"uu")) {
        if (dbus_message_get_args(msg,NULL,DBUS_TYPE_UINT32,&msgid,DBUS_TYPE_UINT32,&reason,DBUS_TYPE_INVALID)) {
          daemon->closed(msgid);
          }
        }
      return DBUS_HANDLER_RESULT_HANDLED;
      }
    }
  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;

  }


GMNotifyDaemon::GMNotifyDaemon(){
  }

GMNotifyDaemon::GMNotifyDaemon(FXDBusConnection* c) : dbus(c), replace_id(0) {
  dbus_bus_add_match(c->connection(),"type='signal',path='" NOTIFY_PATH "',interface='" NOTIFY_INTERFACE "',member='NotificationClosed'",NULL);
  dbus_connection_add_filter(dbus->connection(),dbus_notifydaemon_filter,this,NULL);
  }

GMNotifyDaemon::~GMNotifyDaemon() {
  dbus_connection_remove_filter(dbus->connection(),dbus_notifydaemon_filter,this);
  }

long GMNotifyDaemon::onCmdClose(FXObject*,FXSelector,void*){
  return 1;
  }

long GMNotifyDaemon::onCmdNotify(FXObject*,FXSelector,void*ptr){
  DBusMessage * msg = (DBusMessage*)ptr;
  if (msg) {
    DBusMessageIter iter;
    dbus_message_iter_init(msg,&iter);
    dbus_message_iter_get_basic(&iter,&replace_id);
    //fxmessage("replace id = %d\n",replace_id);
    }
  return 1;
  }

void GMNotifyDaemon::close() {
  FXTRACE((70,"GMNotifyDaemon::close\n"));
  if (replace_id>0) {
    DBusMessage * msg = dbus_message_new_method_call(NOTIFY_NAME,NOTIFY_PATH,NOTIFY_INTERFACE,"CloseNotification");
    if (msg) {
      dbus_message_append_args(msg,DBUS_TYPE_UINT32,&replace_id,DBUS_TYPE_INVALID);
      dbus_message_set_no_reply(msg,true);
      dbus->sendWithReply(msg,-1,this,ID_NOTIFY_CLOSE);
      }
    }
  }

void GMNotifyDaemon::closed(FXuint id) {
  if (replace_id==id) {
    FXTRACE((70,"GMNotifyDaemon::closed\n"));
    replace_id=0;
    }
  }


void GMNotifyDaemon::notify(const FXchar * application,
                            const FXchar * icon,
                            const FXchar * summary,
                            const FXchar * body,
                            FXint timeout,
                            FXImage      * image) {

  FXint iw,ih,is,ibps,ichannels,isize;
  dbus_bool_t ialpha;
  const FXchar * idata=NULL;
  const FXchar * appicon = "";

  if (image==NULL && icon)
    appicon=icon;

  DBusMessage * msg = dbus_message_new_method_call(NOTIFY_NAME,NOTIFY_PATH,NOTIFY_INTERFACE,"Notify");
  if (msg) {
    DBusMessageIter iter;
    DBusMessageIter array;
    DBusMessageIter dict;
    DBusMessageIter value;
    DBusMessageIter variant;
    DBusMessageIter data;

    dbus_message_iter_init_append(msg,&iter);
      dbus_message_iter_append_basic(&iter,DBUS_TYPE_STRING,&application);
      dbus_message_iter_append_basic(&iter,DBUS_TYPE_UINT32,&replace_id);
      dbus_message_iter_append_basic(&iter,DBUS_TYPE_STRING,&appicon);
      dbus_message_iter_append_basic(&iter,DBUS_TYPE_STRING,&summary);
      dbus_message_iter_append_basic(&iter,DBUS_TYPE_STRING,&body);
      dbus_message_iter_open_container(&iter,DBUS_TYPE_ARRAY,DBUS_TYPE_STRING_AS_STRING,&array);
      dbus_message_iter_close_container(&iter,&array);
      dbus_message_iter_open_container(&iter,DBUS_TYPE_ARRAY,"{sv}",&array);
      if (image && image->getData()) {
        const FXchar * icon_data="icon_data"; /// spec 0.9 says "image_data". some use "icon_data" though..
        idata     = (const FXchar*)image->getData();
        ialpha    = true;
        iw        = image->getWidth();
        ih        = image->getHeight();
        is        = iw*4;
        ibps      = 8;
        ichannels = 4;
        isize     = iw*ih*4;

        dbus_message_iter_open_container(&array,DBUS_TYPE_DICT_ENTRY,0,&dict);
          dbus_message_iter_append_basic(&dict,DBUS_TYPE_STRING,&icon_data);
          dbus_message_iter_open_container(&dict,DBUS_TYPE_VARIANT,"(iiibiiay)",&variant);
            dbus_message_iter_open_container(&variant,DBUS_TYPE_STRUCT,NULL,&value);
              dbus_message_iter_append_basic(&value,DBUS_TYPE_INT32,&iw);
              dbus_message_iter_append_basic(&value,DBUS_TYPE_INT32,&ih);
              dbus_message_iter_append_basic(&value,DBUS_TYPE_INT32,&is);
              dbus_message_iter_append_basic(&value,DBUS_TYPE_BOOLEAN,&ialpha);
              dbus_message_iter_append_basic(&value,DBUS_TYPE_INT32,&ibps);
              dbus_message_iter_append_basic(&value,DBUS_TYPE_INT32,&ichannels);
              dbus_message_iter_open_container(&value,DBUS_TYPE_ARRAY,DBUS_TYPE_BYTE_AS_STRING,&data);
                dbus_message_iter_append_fixed_array(&data,DBUS_TYPE_BYTE,&idata,isize);
              dbus_message_iter_close_container(&value,&data);
            dbus_message_iter_close_container(&variant,&value);
          dbus_message_iter_close_container(&dict,&variant);
        dbus_message_iter_close_container(&array,&dict);
        }
      dbus_message_iter_close_container(&iter,&array);
      dbus_message_iter_append_basic(&iter,DBUS_TYPE_INT32,&timeout);
    dbus->sendWithReply(msg,-1,this,ID_NOTIFY_RESULT);
    }
  }
#endif
