/* ****************************************************************************
  This file is part of KBabel

  Copyright (C) 2002	by Stanislav Visnovsky
                            <visnovsky@kde.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.

  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, write to the Free Software
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

**************************************************************************** */
#include "context.h"
#include "klisteditor.h"

#include <qcombobox.h>
#include <qfileinfo.h>
#include <qframe.h>
#include <qhbox.h>
#include <qlabel.h>
#include <qlayout.h>
#include <qlineedit.h>
#include <qlistbox.h>
#include <qpushbutton.h>
#include <qregexp.h>
#include <qvgroupbox.h>

#include <kconfig.h>
#include <kdebug.h>
#include <kdialog.h>
#include <klocale.h>
#include <kmessagebox.h>

#include <klibloader.h>
#include <ktrader.h>
#include <ktexteditor/document.h>
#include <ktexteditor/editinterface.h>
#include <ktexteditor/selectioninterface.h>
#include <ktexteditor/viewcursorinterface.h>

QString Defaults::SourceContextSettings::codeRoot() { return QString(""); }

QStringList Defaults::SourceContextSettings::sourcePaths()
{
    QStringList result;
    result.append("@PACKAGEDIR@/@PACKAGE@/@COMMENTPATH@");
    result.append("@CODEROOT@/@PACKAGEDIR@/@PACKAGE@/@COMMENTPATH@");
    return result;
}

/*****************************************************************************/

SourceContext::SourceContext(QWidget *parent): QWidget(parent)
    , _part(0)
    , _view(0)
    , _referenceCombo(0)
    , _layout(0)
{
    _referenceList.clear();
    _referenceCombo = new QComboBox( this );
    connect( _referenceCombo, SIGNAL(activated(int)), this, SLOT(updateToSelected(int)));
    
    _layout= new QVBoxLayout(this);
    _layout->addWidget(_referenceCombo);
}

void SourceContext::setSettings(const SourceContextSettings& settings)
{
    _settings = settings;
}

void SourceContext::saveSettings(KConfig *config)
{
    KConfigGroupSaver saver(config,"SourceContext");
    
    config->writeEntry("CodeRoot", _settings.codeRoot);
    config->writeEntry("Paths", _settings.sourcePaths);
}

void SourceContext::restoreSettings(KConfig *config)
{
    KConfigGroupSaver saver(config,"SourceContext");
    
    _settings.codeRoot=config->readEntry("CodeRoot", Defaults::SourceContextSettings::codeRoot());
    if( config->hasKey("Paths") )
	_settings.sourcePaths=config->readListEntry("Paths");
    else
	_settings.sourcePaths=Defaults::SourceContextSettings::sourcePaths();
}

void SourceContext::setContext(const QString& packageDir, const QString& packageName, const QString& gettextComment)
{
    if( !_part && !loadPart() ) return;
    _referenceCombo->clear();
    _referenceList.clear();
    _referenceList = resolvePath(packageDir,packageName,gettextComment);
    
    for( QValueList<ContextInfo>::Iterator it=_referenceList.begin(); it!=_referenceList.end() ; it++)
	_referenceCombo->insertItem((*it).path);
    _referenceCombo->setEnabled( !_referenceList.isEmpty() );
    
    if( _referenceList.isEmpty() )
    {
	(dynamic_cast<KTextEditor::EditInterface *>(_part))->setText(i18n("Corresponding source file not found"));
	_part->setReadWrite(false);
	_part->setModified(false);
    } 
    else 
    {
	_referenceCombo->setCurrentItem(0);
	updateToSelected(0);
    }
}

void SourceContext::updateToSelected(int index)
{
    if( !_part ) return;
    ContextInfo ci = *(_referenceList.at(index));
    if( _part->url() != KURL(ci.path) )
    {
	_part->openURL( KURL(ci.path) );
    }
    _part->setReadWrite(true);
    (dynamic_cast<KTextEditor::ViewCursorInterface *>(_view))->setCursorPosition(ci.line,0);
    (dynamic_cast<KTextEditor::SelectionInterface *>(_part))->setSelection(ci.line-1,0,ci.line,0);
}

QValueList<ContextInfo> SourceContext::resolvePath(const QString& packageDir, const QString& packageName, const QString& gettextComment)
{
    QStringList prefixes;
    for( QStringList::Iterator it = _settings.sourcePaths.begin() ; it!=_settings.sourcePaths.end() ; it++)
    {
	QString pref = (*it);
        pref.replace( "@PACKAGEDIR@", packageDir);
        pref.replace( "@PACKAGE@", packageName);
	pref.replace( "@CODEROOT@", _settings.codeRoot);
	prefixes.append(pref);
    }

    QStringList references;
    QStringList lines = QStringList::split("\n", gettextComment);
    for( QStringList::Iterator it = lines.begin() ; it!=lines.end() ; it++)
    {
	QString curLine = (*it);
	if( curLine.startsWith("#:") ) curLine = curLine.mid(2);
	curLine = curLine.stripWhiteSpace();
	
	QStringList refs=QStringList::split(" ",curLine);
	
	for( QStringList::Iterator it=refs.begin(); it!=refs.end(); it++)
	{
	     references.push_back( *it );
	}
    }
    
    QValueList<ContextInfo> results;
    QRegExp re(":\\d+");
    
    for( QStringList::Iterator it = references.begin() ; it!=references.end() ; it++)
    {
	QString curRef = (*it);
	curRef.findRev(re);
	if( re.pos(0)+re.cap(0).length() == curRef.length() )
	{
	    QString lineNum = re.cap(0).mid(1);
	    QString fileName = curRef.mid( 0, curRef.length()-re.matchedLength() );
	    for( QStringList::Iterator it1 = prefixes.begin(); it1!=prefixes.end() ; it1++ )
	    {
		QString path = (*it1);
		path.replace( "@COMMENTPATH@", fileName);
		QFileInfo url(path);
		if( url.exists())
		{
		    ContextInfo ref;
		    ref.path = url.absFilePath();
		    ref.line = lineNum.toInt();
		    results.append(ref);
		}
	    }
	}
    }
    
    return results;
}

bool SourceContext::loadPart()
{
    KTrader::OfferList offers = KTrader::self()->query( "KTextEditor/Document" );
    if( offers.count() < 1 )
    {
	KMessageBox::error(this,i18n("KBabel cannot start a text editor component.\n"
	"Please check your KDE installation."));
	_part=0;
	_view=0;
	return false;
    }
    KService::Ptr service = *offers.begin();
    KLibFactory *factory = KLibLoader::self()->factory( service->library().latin1() );
    if( !factory )
    {
	KMessageBox::error(this,i18n("KBabel cannot start a text editor component.\n"
	"Please check your KDE installation."));
	_part=0;
	_view=0;
	return false;
    }
    _part = static_cast<KTextEditor::Document *>( factory->create( this, 0, "KTextEditor::Document" ) );

    if( !_part )
    {
	KMessageBox::error(this,i18n("KBabel cannot start a text editor component.\n"
	"Please check your KDE installation."));
	_part=0;
	_view=0;
	return false;
    }
    _view = _part->createView( this, 0 );
    _layout->addWidget(static_cast<QWidget *>(_view), 1);
    static_cast<QWidget *>(_view)->show();

    return true;
}

/*****************************************************************************/

SourceContextPreferences::SourceContextPreferences(QWidget* parent): QWidget(parent)
{
    QWidget* page = this;
    QVBoxLayout* layout=new QVBoxLayout(page);
    layout->setSpacing(KDialog::spacingHint());
    layout->setMargin(KDialog::marginHint());
    
    QHBox* box = new QHBox(page);
    box->setSpacing(KDialog::spacingHint());
    QLabel* tempLabel=new QLabel(i18n("&Base folder for source code:"),box);
    _coderootEdit = new QLineEdit(box);
    tempLabel->setBuddy(_coderootEdit);
    layout->addWidget(box);
    
    _pathsEditor = new KListEditor(page);
    _pathsEditor->setTitle(i18n("Path Patterns"));
    layout->addWidget(_pathsEditor);
    
    _pathsEditor->installEventFilter(this);
				    
    setMinimumSize(sizeHint());
    
    defaults();
}

SourceContextPreferences::~SourceContextPreferences()
{
}

void SourceContextPreferences::mergeSettings(SourceContextSettings& settings) const
{
    settings.codeRoot=_coderootEdit->text();
    settings.sourcePaths=_pathsEditor->list();
}

void SourceContextPreferences::setSettings(const SourceContextSettings& settings)
{
    _coderootEdit->setText( settings.codeRoot );
    _pathsEditor->setList(settings.sourcePaths);
}

void SourceContextPreferences::defaults()
{
    _coderootEdit->setText( Defaults::SourceContextSettings::codeRoot() );
    _pathsEditor->setList( Defaults::SourceContextSettings::sourcePaths() );
}

bool SourceContextPreferences::eventFilter( QObject *, QEvent *e )
{
    if( e->type() == QEvent::KeyPress )
    {
        QKeyEvent *ke = dynamic_cast<QKeyEvent*>(e);
        if( ke->key() == Key_Return || ke->key() == Key_Enter )
            return true;
    }
    return false;
}

#include "context.moc"
