/* ====================================================================
 * Copyright (c) 2003-2007, Martin Hauner
 *                          http://subcommander.tigris.org
 *
 * Subcommander is licensed as described in the file doc/COPYING, which
 * you should have received as part of this distribution.
 * ====================================================================
 */

// sc
#include "config.h"
#include "ErrorDialog.h" 
#include "MessageBox.h"
#include "Utility.h"
#include "util/Exception.h"
#include "util/ExceptionStack.h"
#include "util/ErrorCodes.h"

// qt
#include <QtGui/QLayout>
#include <QtGui/QLabel>
#include <QtGui/QPushButton>
#include <QtGui/QTextEdit>
#include <QtGui/QGroupBox>
#include <QtGui/QLineEdit>

// sys
#ifdef _WIN32
#include <mapi.h>
#endif // _WIN32


ErrorDialog::ErrorDialog( const sc::Exception& e, QWidget *parent )
: super( parent )
{
  const sc::ExceptionStack* est = dynamic_cast<const sc::ExceptionStack*>(&e);
  if( est )
  {
    setup(e.getError(),est->getStack());
  }
  else
  {
    Stackframes frames;
    setup(e.getError(),frames);
  }
}

ErrorDialog::ErrorDialog( const sc::Error* err, const Stackframes& stack, QWidget* parent )
: super( parent )
{
  setup(err,stack);
}

void ErrorDialog::setup( const sc::Error* err, const Stackframes& stack )
{
  setModal(true); // qt4
  setWindowTitle( _q("%1:exception").arg(getAppName()) );

  QString error = QString(err->getMessage());

  // extract dump file name
  const sc::Error* nested = err->getNested();
  if( nested && nested->getCode() == sc::ErrDump )
  {
    _dump = QString(nested->getMessage());
  }

  QVBoxLayout *vbl = new QVBoxLayout(this);
  vbl->setMargin(5);
  vbl->setSpacing(10);
  {
    QLabel *l = new QLabel(this);
    vbl->addWidget(l,0);
    l->setMargin(2);
    l->setText( 
      "<qt><font size=3><b>" +
      _q("sorry, %1 has a problem... :-(").arg(getLongAppName())+ 
      "</b></font></qt>" );
    l->setAlignment( Qt::AlignCenter );

    QGroupBox*   gb  = new QGroupBox(this);
    QVBoxLayout* gbl = new QVBoxLayout(gb);
    gbl->setContentsMargins(0,0,0,0);
    gb->setTitle( _q("crash details: ") );
    gb->setFlat(true);
    vbl->addWidget(gb);

    QLabel *l2 = new QLabel(this);
    vbl->addWidget(l2,0);
    l2->setMargin(2);
    l2->setText(error);
    l2->setAlignment( Qt::AlignCenter );
    //l2->setPaletteBackgroundColor( QColor(255,120,120) ); // qt4
    //l2->setBackgroundRole( QPalette::Window );

    QString textl3;
    textl3 +=
      _q("Please send this crash information and the crash dump\n"
      "(%1)\n"
      "to crash@subcommander.tigris.org.\n\n").arg(_dump);
    textl3 += 
      _q("Just press 'Send' to open your email client with a prepared email.");
    textl3 +=
      _q("\nIf this doesn't work please send the information manually.\nThank you.");

    QLabel *l3 = new QLabel(this);
    vbl->addWidget(l3,0);
    l3->setMargin(2);
    l3->setText(textl3);
    l3->setAlignment( Qt::AlignCenter );

    QGroupBox* gb2 = new QGroupBox(this); // qt4, layout needed?
    gb2->setTitle( _q("Send:") );
    gb2->setFlat(true);
    vbl->addWidget(gb2);

    _text = new QTextEdit(this);
    vbl->addWidget(_text,3);
    //te->setReadOnly(true);
    _text->setLineWidth(1);
    _text->setContentsMargins(1,1,1,1); // qt4
    _text->setWordWrapMode(QTextOption::NoWrap);
    _text->setFrameStyle( QFrame::Box | QFrame::Sunken );
    _text->setMinimumWidth(460);
    _text->setMinimumHeight(200);
    //te->setPaper( backgroundColor() );

    QString text;
    text += _q("email:\n");
    text += _q("crash@subcommander.tigris.org");
    text += _q("\n\nCrash Dump:\n");
    text += _dump;
    text += "\n\n";
    text += _q("Hi,\n\n%1 crashed when I ...\n\n").arg(getLongAppName());
    text += _q("<If you are able to reproduce the crash please describe how. Thank you!>" );
    text += "\n\n\n";
    text += "\n\n";
    text += _q("*** crash information: ***");
    text += "\n\n" + getAppName() + ":exception - " + error + "\n\n";

    for( Stackframes::const_iterator it = stack.begin(); it != stack.end(); it++ )
    {
      const Stackframe& f = *it;

      if(!f._error)
      {
        // address
        QString addr;
        text += "0x" +addr.setNum(f._addr,16).rightJustified(16,'0'); // qt4
        //+":0x" + addr.setNum(f._addrSeg).rightJustify(4,'0');

        if(f._symbol)
        {
          text += " : " +QString(f._symbolName);
        }
        else
        {
          text += " : " +QString("unknown");
        }

        if(f._module)
        {
          text += " " + QString(f._moduleName);
        }
        else
        {
          text += " " + QString("unknown");
        }

        text += "\n  ";

        if(f._line)
        {
          text += addr.setNum(f._lineNr);
          text += " + 0x" + addr.setNum(f._lineDisp,16) + " (";
          text += QString(f._fileName) + ")";
          text += "\n  ";
        }
        //else
        //{
        //text += QString("0")+ " (";
        //text += QString("unknown") + ")";
        //}

      }

      text += "\n";
    }

    _text->setText( text );

    QHBoxLayout* hu = new QHBoxLayout;
    vbl->addLayout(hu);
    {
      // eats extra space, so the buttons keep their size
      hu->addStretch(1); 

      QPushButton* send = new QPushButton(this);
      send->setText( _q("S&end") );
#ifdef _WIN32
      send->setDefault(true);
#else
      send->setDefault(false);
#endif // _WIN32
      hu->addWidget(send);

      connect( send, SIGNAL(clicked()), SLOT(send()) );

      QPushButton* cancel = new QPushButton(this);
      cancel->setText( _q("&Cancel") );
      hu->addWidget(cancel);

      connect( cancel, SIGNAL(clicked()), SLOT(reject()) );
    }
  }
}

ErrorDialog::~ErrorDialog()
{
}

static const char* copyString( const QString& s )
{
  QByteArray qs = s.toLocal8Bit();
  char* result = (char*)calloc( qs.length()+1, 1 );
  strncpy( result, (const char*)qs, qs.length() );
  return result;
}

void ErrorDialog::send()
{
#if _WIN32
  typedef ULONG (FAR PASCAL *MAPISendMail)(
    LHANDLE lhSession,ULONG ulUIParam,lpMapiMessage lpMessage,FLAGS flFlags,ULONG ulReserved);

  HMODULE hMapi = LoadLibrary( "MAPI32.dll" );
  if( hMapi )
  {
    MAPISendMail MapiSendMail = (MAPISendMail)GetProcAddress( hMapi, "MAPISendMail" );
    if( MapiSendMail )
    {
      MapiFileDesc attachment =
      { 
        0,                                             // reserved
        0,                                             // data file
        (ULONG)-1,                                     // position
        (LPSTR)copyString(_dump),                      // full path
        NULL,                                          // display name
        NULL                                           // file details
      };


      QString target(_q("crash@subcommander.tigris.org"));

      MapiRecipDesc recipient =
      {
        0,                                             // reserved
        MAPI_TO,                                       // recipient class
        NULL,                                          // name
        (LPSTR)copyString(target),                     // address
        0,                                             // entry id size
        NULL                                           // entry id
      };


      MapiMessage message =
      {
        0,                                             // reserved
        (LPSTR)copyString(_q("crash..!")),             // subject
        (LPSTR)copyString(_text->toPlainText()),       // message
        NULL,                                          // message type
        NULL,                                          // date
        NULL,                                          // conversation ID
        0L,                                            // flags
        NULL,                                          // originator
        1,                                             // recipient count
        &recipient,                                    // recipents
        1,                                             // attachment count
        &attachment                                    // attachments
      };

      ULONG res = MapiSendMail( 0L, 0L, &message, MAPI_DIALOG, 0L );
    }

    FreeLibrary(hMapi);
  }
#endif // _WIN32
}
