/***************************************************************************
                    macnotification.cpp - Notifications on Mac OS X
                             -------------------
    begin                : Thursday June 3 2010
    copyright            : (C) 2010 by Sjors Gielen
    email                : sjors@kmess.org
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include <QtGui/QApplication>
#include <QtGui/QSystemTrayIcon>
#include <QtXml/QDomDocument>
#include <QtCore/QDebug>

#include <phonon/Phonon/MediaObject>
#include <phonon/Phonon/MediaSource>
#include <phonon/Phonon/AudioOutput>

#include <KLocale>

#include "macnotification.h"

enum MacNotifyOption
{
  NoNotify = 0,
  DockNotify,
  GrowlNotify,
  SoundNotify,
};

#define MessageSound         "kmess_msg.mp3"
#define ContactOnlineSound   "kmess_logon.mp3"
#define ContactOfflineSound  "kmess_logoff.mp3"
#define ChatSound            "kmess_chat.mp3"
#define CREATE_ICON          if( icon_ == 0 ) { icon_ = new QSystemTrayIcon(); }

QSystemTrayIcon *MacNotification::icon_(0);

bool MacNotification::growlSupported()
{
  CREATE_ICON;
  return icon_->supportsMessages();
}

void MacNotification::notify( const QString &event, const QString &text,
                              NotificationManager::EventSettings settings )
{
  QString textTitle;
  int opt = NoNotify;
  QString sound;
  if( event == "status" )
  {
    textTitle = i18n("Contact changed status");
    opt = GrowlNotify;
  }
  else if( event == "new email" )
  {
    textTitle = i18n("You received a new e-mail message");
    opt = GrowlNotify | SoundNotify;
    sound = MessageSound;
  }
  else if( event == "nudge" )
  {
    textTitle = i18n("A contact nudged you!");
    opt = GrowlNotify | DockNotify | SoundNotify;
    sound = ChatSound;
  }
  else if( event == "chat start" )
  {
    textTitle = i18n("A contact started a chat with you");
    opt = GrowlNotify | DockNotify | SoundNotify;
    sound = ChatSound;
  }
  else if( event == "new message" )
  {
    textTitle = i18n("A contact messaged you");
    opt = GrowlNotify | DockNotify | SoundNotify;
    sound = ChatSound;
  }
  else if( event == "contact online" )
  {
    textTitle = i18n("A contact came online");
    opt = GrowlNotify | SoundNotify;
    sound = ContactOnlineSound;
  }
  else if( event == "contact offline" )
  {
    textTitle = i18n("A contact went offline");
    opt = GrowlNotify;
    sound = ContactOfflineSound;
  }
  else if( event == "contact status" )
  {
    textTitle = i18n("A contact changed status");
    opt = GrowlNotify;
  }
  else
  {
    textTitle = i18n("KMess notification");
    opt = GrowlNotify | DockNotify | SoundNotify;
    sound = MessageSound;
  }

  // This is one of the reasons KNotify is this annoying. It supports HTML, so
  // everybody sends HTML to it; but then suddenly you realise that it uses
  // or wants to use backends that *don't* support HTML. But it has no flags
  // to check that, and even if there would be, nobody would check them
  // anyway.
  qDebug() << "Stripping html: " << text;
  QString displayText = stripHtml( text );
  qDebug() << "Outcome: " << displayText;

  if( opt & DockNotify )
  {
    MacNotification::jumpIcon();
  }
  if( opt & SoundNotify )
  {
    MacNotification::playSound( sound );
  }
  if( opt & GrowlNotify )
  {
    MacNotification::showGrowlBalloon( textTitle, displayText );
  }
}

QString MacNotification::stripHtml( const QString &text )
{
  // Strip all HTML from the incoming text, quickly and dirty, by using
  // QDom.
  QDomDocument stripper;
  stripper.setContent( "<elem>" + text + "</elem>" );
  return stripHtml( stripper.documentElement() );
}

QString MacNotification::stripHtml( const QDomNode &e )
{
  if( e.isText() )
    return e.toText().data();

  QString data;
  for( int i = 0; i < e.childNodes().size(); ++i )
  {
    data.append( stripHtml( e.childNodes().at(i) ) );
  }
  return data;
}

void MacNotification::showGrowlBalloon( const QString &title, const QString &text )
{
  // One of the ways to display a Growl notification is by using
  // QSystemTrayIcon. We don't actually want to *display* a system tray
  // icon, therefore we show the icon, show the message, hide the icon.
  // TODO: replace this with more native code so we have more features
  CREATE_ICON;
  icon_->show();
  icon_->showMessage( title,
                      text,
                      QSystemTrayIcon::NoIcon,
                      10000 );
  icon_->hide();
}

void MacNotification::playSound( const QString &name )
{
  Phonon::MediaObject *obj = new Phonon::MediaObject();
  obj->setCurrentSource( Phonon::MediaSource("/tmp/" + name) );
  Phonon::AudioOutput *out =
      new Phonon::AudioOutput();
  Phonon::createPath(obj, out);
  obj->play();
  connect( obj, SIGNAL( finished() ), out, SLOT( deleteLater() ) );
  connect( obj, SIGNAL( finished() ), obj, SLOT( deleteLater() ) );
}

/**
 * @brief Bounce the icon in the Dock.
 *
 * This method causes the application icon to bounce in the dock.
 */
void MacNotification::jumpIcon()
{
  // A widget has to be given, but since this call works applicationwide on
  // Mac instead of on a specific widget, we give through a nullpointer.
  QApplication::alert((QWidget*)0,0);
}
