/*
 *  Copyright (C) 2001-2003, Richard J. Moore <rich@kde.org>
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library 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
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public License
 *  along with this library; see the file COPYING.LIB.  If not, write to
 *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 *  Boston, MA 02111-1307, USA.
 */

#include <qcombobox.h>
#include <qfile.h>
#include <qhbox.h>
#include <qlayout.h>
#include <qpushbutton.h>
#include <qtextedit.h>

#include <kdebug.h>
#include <kdialog.h>
#include <kglobal.h>
#include <kiconloader.h>
#include <klocale.h>
#include <kpopupmenu.h>
#include <kprocess.h>

#include <kjs/interpreter.h>
#include <kjs/ustring.h>
#include <kjs/types.h>

#include "jsbinding.h"
#include "kjsembedpart.h"

#include "jsconsolewidget.h"
#include "jsconsolewidget.moc"

//
// JScript Widget
//

namespace KJSEmbed {

class Private
{
public:
    KPopupTitle *title;
};

JSConsoleWidget::JSConsoleWidget( KJS::Interpreter *js, QWidget *parent, const char *name )
    : QFrame( parent, name ? name : "JSConsoleWidget" )
{
    d = new Private;
    setFocusPolicy( QWidget::StrongFocus );
    createView();
    this->js = js;
}

JSConsoleWidget::~JSConsoleWidget()
{
    delete d;
}

KPopupTitle *JSConsoleWidget::title() const
{
    return d->title;
}

void JSConsoleWidget::createView()
{
    d->title = new KPopupTitle( this, "Title" );
    d->title->setText( i18n("Javascript Console") );
    QPixmap px( KGlobal::iconLoader()->loadIcon("konsole", KIcon::NoGroup, KIcon::SizeSmall) );
    d->title->setIcon( px );

    log = new QTextEdit( this, "LogView" );
    log->setReadOnly( true );
    log->setUndoRedoEnabled( false );
    log->setTextFormat( Qt::RichText );
    log->setWrapPolicy( QTextEdit::Anywhere );
    log->setText( "<qt><pre>" );

    QHBox *hbox = new QHBox( this, "HBox" );
    hbox->setSpacing( KDialog::spacingHint() );

    cmd = new QComboBox( true, hbox, "CmdEdit" );
    cmd->setInsertionPolicy( QComboBox::AtTop );
    cmd->setFocus();

    go = new QPushButton( i18n("&Run"), hbox, "RunButton" );
    go->setFixedSize( go->sizeHint() );

    connect( cmd, SIGNAL( activated(int) ), go, SLOT( animateClick() ) );
    connect( go, SIGNAL( clicked() ), SLOT( execute() ) );

    //
    // Layout
    //
    QVBoxLayout *vertical = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
    vertical->addWidget( d->title );
    vertical->addWidget( log );
    vertical->addWidget( hbox );

    println( i18n("-- Enter a JS expression and press enter --") );
}

void JSConsoleWidget::execute()
{
    QString code = cmd->currentText();
    println( QString( "<b>kjs&gt; %1</b>" ).arg( code ) );
    execute( code );
}

bool JSConsoleWidget::execute( const QString &cmd )
{
    KJS::Completion jsres = js->evaluate( KJS::UString(cmd), js->globalObject() );

    KJS::UString s;
    KJS::ComplType ct = jsres.complType();
    bool res  = false;

    // Report Errors
    if ( (ct == KJS::Throw) || (ct == KJS::Break) || ct == KJS::Continue ) {
	kdDebug() << "jsconsolewidget: Error returned" << endl;

	s = jsres.value().toString( js->globalExec() );
	if ( !s.isNull() )
	    warn( s.qstring() );
	else {
	    kdDebug() << "jsconsolewidget: Null error message" << endl;
	}

	res = false;
    }
    // Handle Normal
    else if ( ct == KJS::Normal ) {
	kdDebug() << "jsconsolewidget: Normal result" << endl;
	res = true;

	// Handle Return Values
	if ( jsres.isValueCompletion() ) {
	    kdDebug() << "jsconsolewidget: Value returned" << endl;

	    KJS::Value ret = jsres.value();
	    if ( ret.type() == KJS::StringType || ret.type() == KJS::NumberType )
		s = ret.toString( js->globalExec() );
	    else if ( ret.type() == KJS::ListType ) {
		s = KJS::UString( "====list====" );
	    }
	    else {
		s = ret.toString( js->globalExec() );
		if ( s.isNull() )
		    s = KJS::UString( "====object====" );
	    }

	    if ( s.isNull() )
		println( i18n("Return Value, <Unable to display result>") );
	    else {
		QString txt = s.qstring();
		txt = txt.replace( QChar('\n'), "<br>" );
		println( txt );
	    }

	    res = true;
	}
    }

    return res;
}

void JSConsoleWidget::println( const QString &msg )
{
    log->append( msg );
    log->scrollToBottom();
}

void JSConsoleWidget::warn( const QString &msg )
{
    QString err( "<font color=\"red\"><b>%1</b></font>" );
    println( err.arg(msg) );
}

//
// Process Handling
//
bool JSConsoleWidget::run( const QString &cmd )
{
    if ( proc )
	return false;

    println( cmd );
    proc = new KShellProcess("/bin/sh");
    *proc << cmd;

    connect( proc, SIGNAL( processExited(KProcess *) ),
	     this, SLOT(childExited()) );
    connect( proc, SIGNAL( receivedStdout(KProcess *, char *, int) ),
	     this, SLOT( receivedStdOutput(KProcess *, char *, int) ) );
    connect( proc, SIGNAL( receivedStderr(KProcess *, char *, int) ),
	     this, SLOT( receivedStdError(KProcess *, char *, int) ) );

    return proc->start( KProcess::NotifyOnExit,
			KProcess::Communication( KProcess::Stdout|KProcess::Stderr ));
}


void JSConsoleWidget::childExited()
{
    QString s;
    if ( proc->normalExit() ) {
	if ( proc->exitStatus() )
	    s = i18n( "[Exited with status %1]\n" ).arg( proc->exitStatus() );
	else
	    s = i18n( "[Finished]\n" );
	println( s );
    }
    else {
        s = i18n("[Aborted]\n");
	warn( s );
    }

    delete proc;
    proc = 0;
}

void JSConsoleWidget::receivedStdOutput( KProcess *, char *buffer, int buflen )
{
    QCString buf = QCString( buffer, buflen+1 );
    println( QString(buf) );
}

void JSConsoleWidget::receivedStdError( KProcess *, char *buffer, int buflen )
{
    QCString buf = QCString( buffer, buflen+1 );
    warn( QString(buf) );
}


}; // namespace KJSEmbed

// Local Variables:
// c-basic-offset: 4
// End:
