/***************************************************************************
 *   Copyright (C) 2004-2006 by Pere Constans
 *   constans@molspaces.com
 *   cb2Bib version 0.6.1
 *   See LICENSE file that comes with this distribution
 ***************************************************************************/
#include "c2beditor.h"
#include "cb2bib_par.h"
#include "bibsyntaxhighlighter.h"
#include "c2bbibparser.h"
#include "c2bpostprocess.h"
#include "c2btextedit.h"
#include "c2butils.h"
#include "referencelist.h"
#include "resyntaxhighlighter.h"

#include <qaction.h>
#include <qapplication.h>
#include <qdir.h>
#include <qfiledialog.h>
#include <qfile.h>
#include <qfileinfo.h>
#include <qfont.h>
#include <qlabel.h>
#include <qmessagebox.h>
#include <qpopupmenu.h>
#include <qsettings.h>
#include <qstatusbar.h>


/*! \page c2beditor Embedded File Editor
 
The cb2Bib contains a practical editor suitable to manipulate the files related
to a cb2Bib session. Bookmarks files, regular expression files, and BibTeX are
readely available.
 
\section c2beditor_menu Right-Click Menu Functionality
 
\htmlonly
<center><table cellpadding="4" cellspacing="2" border="1" 
summary="Summary table of Right-Click Menu Functionality">
<tr> <th valign="top">Keys</th> <th valign="top">Action</th></tr>
<tr> <td valign="top">Alt+F</td> <td valign="top">Find in text</td></tr>
<tr> <td valign="top"></td> <td valign="top">Wrap text</td></tr>
<tr> <td valign="top"></td> <td valign="top">Unwrap text</td></tr>
<tr> <td valign="top"></td> <td valign="top">Selection to LaTeX</td></tr>
<tr> <td valign="top"></td> <td valign="top">Selection to Unicode</td></tr>
<tr> <td valign="top"></td> <td valign="top">Journals to Full Name</td></tr>
<tr> <td valign="top"></td> <td valign="top">Journals to Abbreviated Name</td></tr>
<tr> <td valign="top">Alt+T</td> <td valign="top">Paste current BibTeX</td></tr>
<tr> <td valign="top">Alt+P</td> <td valign="top">Save and Postprocess BibTeX file</td></tr>
</table></center>
\endhtmlonly
 
<p>&nbsp;</p>
\section references_menu Reference List Right-Click Menu Functionality
 
\htmlonly
<center><table cellpadding="4" cellspacing="2" border="1" 
summary="Summary table of Right-Click Menu Functionality">
<tr> <th valign="top">Keys</th> <th valign="top">Action</th></tr>
<tr> <td valign="top">Alt+E</td> <td valign="top">Cite Selected Entries</td></tr>
<tr> <td valign="top"></td> <td valign="top">Cite to Clipboard</td></tr>
<tr> <td valign="top"></td> <td valign="top">Open Article File</td></tr>
<tr> <td valign="top"></td> <td valign="top">Browse by DOI</td></tr>
<tr> <td valign="top"></td> <td valign="top">Web Search by Title</td></tr>
<tr> <td valign="top"></td> <td valign="top">Refresh List</td></tr>
</table></center>
\endhtmlonly
 
<p>&nbsp;</p>
\section c2beditor_qt Inherited Functionality
 
\htmlonly
<center><table cellpadding="4" cellspacing="2" border="1" 
summary="Summary table of Inherited Functionality">
<tr> <th valign="top">Keys</th> <th valign="top">Action</th></tr>
<tr> <td valign="top">Backspace</td> <td valign="top">Delete the character to the left of the cursor</td></tr>
<tr> <td valign="top">Delete</td> <td valign="top">Delete the character to the right of the cursor</td></tr>
<tr> <td valign="top">Ctrl+A</td> <td valign="top">Move the cursor to the beginning of the line</td></tr>
<tr> <td valign="top">Ctrl+B</td> <td valign="top">Move the cursor one character left</td></tr>
<tr> <td valign="top">Ctrl+C</td> <td valign="top">Copy the marked text to the clipboard (also
Ctrl+Insert under Windows)</td></tr>
<tr> <td valign="top">Ctrl+D</td> <td valign="top">Delete the character to the right of the cursor</td></tr>
<tr> <td valign="top">Ctrl+E</td> <td valign="top">Move the cursor to the end of the line</td></tr>
<tr> <td valign="top">Ctrl+F</td> <td valign="top">Move the cursor one character right</td></tr>
<tr> <td valign="top">Ctrl+H</td> <td valign="top">Delete the character to the left of the cursor</td></tr>
<tr> <td valign="top">Ctrl+K</td> <td valign="top">Delete to end of line</td></tr>
<tr> <td valign="top">Ctrl+N</td> <td valign="top">Move the cursor one line down</td></tr>
<tr> <td valign="top">Ctrl+P</td> <td valign="top">Move the cursor one line up</td></tr>
<tr> <td valign="top">Ctrl+V</td> <td valign="top">Paste the clipboard text into line edit
(also Shift+Insert under Windows)</td></tr>
<tr> <td valign="top">Ctrl+X</td> <td valign="top">Cut the marked text, copy to clipboard
(also Shift+Delete under Windows)</td></tr>
<tr> <td valign="top">Ctrl+Z</td> <td valign="top">Undo the last operation</td></tr>
<tr> <td valign="top">Ctrl+Y</td> <td valign="top">Redo the last operation</td></tr>
<tr> <td valign="top">LeftArrow</td> <td valign="top">Move the cursor one character left</td></tr>
<tr> <td valign="top">Ctrl+LeftArrow</td> <td valign="top">Move the cursor one word left</td></tr>
<tr> <td valign="top">RightArrow</td> <td valign="top">Move the cursor one character right</td></tr>
<tr> <td valign="top">Ctrl+RightArrow</td> <td valign="top">Move the cursor one word right</td></tr>
<tr> <td valign="top">UpArrow</td> <td valign="top">Move the cursor one line up</td></tr>
<tr> <td valign="top">Ctrl+UpArrow</td> <td valign="top">Move the cursor one word up</td></tr>
<tr> <td valign="top">DownArrow</td> <td valign="top">Move the cursor one line down</td></tr>
<tr> <td valign="top">Ctrl+Down Arrow</td> <td valign="top">Move the cursor one word down</td></tr>
<tr> <td valign="top">PageUp</td> <td valign="top">Move the cursor one page up</td></tr>
<tr> <td valign="top">PageDown</td> <td valign="top">Move the cursor one page down</td></tr>
<tr> <td valign="top">Home</td> <td valign="top">Move the cursor to the beginning of the line</td></tr>
<tr> <td valign="top">Ctrl+Home</td> <td valign="top">Move the cursor to the beginning of the text</td></tr>
<tr> <td valign="top">End</td> <td valign="top">Move the cursor to the end of the line</td></tr>
<tr> <td valign="top">Ctrl+End</td> <td valign="top">Move the cursor to the end of the text</td></tr>
<tr> <td valign="top">Shift+Wheel</td> <td valign="top">Scroll the page horizontally</td></tr>
<tr> <td valign="top">Ctrl+Wheel</td> <td valign="top">Zoom the text</td></tr>
</table></center>
\endhtmlonly
 
<p>&nbsp;</p>
*/


c2bEditor::c2bEditor( const QString& edtype, QWidget* main,
                      QWidget* parent, const char* name, WFlags fl )
        : c2bEditorBase(parent,name,fl)
{
    EditorType = edtype;
    c2bMain = main;
    QSettings settings;
    settings.insertSearchPath( QSettings::Windows, WINDOWS_REGISTRY );
    if ( EditorType == "RegExp" )
        EFile = QDir::convertSeparators(settings.readEntry( APP_KEY + "regexpfl", APP_REGEXPF ));
    else if ( EditorType == "NetQInfo" )
        EFile = QDir::convertSeparators(settings.readEntry( APP_KEY + "netqinffl", APP_NETQIF ));
    else
        EFile = "noname";
    initEditor();
}

c2bEditor::c2bEditor( const QString& file, const QString& edtype, c2bBibParser *p, QWidget* main,
                      QWidget* parent, const char* name, WFlags fl)
        : c2bEditorBase(parent,name,fl)
{
    EditorType = edtype;
    c2bMain = main;
    EFile = file;
    bp = p;
    initEditor();
}

c2bEditor::~c2bEditor()
{
    if( RList )
        delete RList;
    delete sH;
    delete textEdit;
}


void c2bEditor::initEditor()
{
    RList = 0;
    setIcons();
    lineLabel = new QLabel( this, "lineLabel" );
    lineLabel->setText( tr(" Line: 1 Col: 1 ") );
    lineLabel->setAlignment( Qt::AlignVCenter | Qt::AlignRight );
    lineLabel->setFrameStyle( QFrame::NoFrame );
    lineLabel->setLineWidth( 1 );
    lineLabel->setFixedHeight( lineLabel->fontMetrics().height() );
    statusBar()->addWidget(lineLabel,1);
    connect( textEdit, SIGNAL( cursorPositionChanged( int, int ) ),
             this, SLOT( cursorPositionChanged( int, int ) ) );
    overwriteLabel = new QLabel( this, "overwriteLabel" );
    overwriteLabel->setText( tr(" INS ") );
    overwriteLabel->setAlignment( Qt::AlignVCenter | Qt::AlignRight );
    overwriteLabel->setFrameStyle( QFrame::NoFrame );
    overwriteLabel->setLineWidth( 1 );
    overwriteLabel->setFixedHeight( overwriteLabel->fontMetrics().height() );
    statusBar()->addWidget(overwriteLabel);
    textEdit->setOverwriteMode( FALSE );
    connect( textEdit, SIGNAL( overwriteModeChanged() ), this, SLOT( overwriteModeChanged() ) );

    connect( fileExecAction, SIGNAL( activated() ), this, SLOT( saveAndExecute() ) );
    textEdit->setFrameShape( QTextEdit::StyledPanel );
    textEdit->setFrameShadow( QTextEdit::Raised );
    QSettings settings;
    settings.insertSearchPath( QSettings::Windows, WINDOWS_REGISTRY );
    int windowWidth = settings.readNumEntry( APP_KEY + "edWindowWidth", ED_WINDOW_W );
    int windowHeight = settings.readNumEntry( APP_KEY + "edWindowHeight", ED_WINDOW_H );
    resize( windowWidth, windowHeight );
    viewToolsAction->setOn( settings.readBoolEntry( APP_KEY + "toolbar", TRUE ) );
    QFont font;
    font.setFamily( settings.readEntry( APP_KEY + "Font0", WINDOW_FF ) );
    font.setPointSize( settings.readNumEntry( APP_KEY + "FontSize0", WINDOW_FS ) );
    textEdit->setFont( font );
    textEdit->wordUnWrap();
    QString ms;

    if ( EditorType == "RegExp" )
    {
        sH = new reSyntaxHighlighter( textEdit );
        fileExecAction->setText( tr( "Restart Recognition" ) );
        fileExecAction->setAccel( tr( "Alt+R" ) );
        connect( this, SIGNAL( Execute() ), this, SIGNAL( restartEngine() ) );
        ms = tr("Close and Usue cb2Bib Configure button to choose "
                "an existing filename and location.\n");
    }
    else if ( EditorType == "NetQInfo" )
    {
        sH = new reSyntaxHighlighter( textEdit );
        fileExecAction->setText( tr( "Restart Net Query" ) );
        fileExecAction->setAccel( tr( "Alt+N" ) );
        connect( this, SIGNAL( Execute() ), this, SIGNAL( restartQuery() ) );
        ms = tr("Close and Usue cb2Bib Configure button to choose an "
                "existing filename and location.\n");
    }
    else if ( EditorType == "BibTeX" )
    {
        sH = new bibSyntaxHighlighter( textEdit );
        textEdit->setBibTeXActions();
        connect( textEdit, SIGNAL( pasteCurrentBibTeX() ), this, SLOT( pasteCurrentBibTeX() ) );
        connect( textEdit, SIGNAL( journalsToFull() ), this, SLOT( journalsToFull() ) );
        connect( textEdit, SIGNAL( journalsToAbbreviated() ), this, SLOT( journalsToAbbreviated() ) );
        connect( bp, SIGNAL( message(const QString&) ), this, SLOT( statusMessage(const QString&) ) );
        connect( c2bMain, SIGNAL( addedBibtoFile(const QString&) ), this, SLOT( reload(const QString&) ) );
        fileExecAction->setText( tr( "Save and Postprocess" ) );
        fileExecAction->setAccel( tr( "Alt+P" ) );
        connect( this, SIGNAL( Execute() ), this, SLOT( postProcess() ) );
        ms = tr("Close and Usue the File Selector button to choose an "
                "existing filename and location.\n");
        createReferenceList();
        viewReferenceListAction->setOn( settings.readBoolEntry( APP_KEY +
                                        "referencelist", TRUE ) );
        viewReferenceList( settings.readBoolEntry( APP_KEY +
                           "referencelist", TRUE ) );
    }
    else
        c2bDebug( "c2bEditor::initEditor: EditorType not specified." );

    if ( EFile.isEmpty() )
    {
        EFile = "noname";
        textEdit->wordUnWrap();
        QMessageBox::information(
            c2bMain, tr("cb2Bib Info"),
            tr( QString("No file name specified for editing.\n\n") ) +
            tr( "Choose an appropriate filename and location.\n\n" ),
            tr("&Continue") );
        return;
    }
    else
        setCaption( tr( QString("%1 - cb2Bib").arg(EFile) ) );

    load( ms );
    connect( textEdit, SIGNAL( textChanged() ), this, SLOT( isModified() ) );
    if ( EditorType == "BibTeX" )
        RList->loadList( textEdit->text() );

    // Populating File, Edit and View menus
    textEdit->findTextAction->addTo( editMenu );
    if ( EditorType == "BibTeX" )
    {
        editMenu->insertSeparator();
        textEdit->convertSelection2LaTeXAction->addTo( editMenu );
        textEdit->convertSelection2UnicodeAction->addTo( editMenu );
        editMenu->insertSeparator();
        textEdit->journalsToFullAction->addTo( editMenu );
        textEdit->journalsToAbbreviatedAction->addTo( editMenu );
        editMenu->insertSeparator();
        textEdit->pasteCurrentBibTeXAction->addTo( editMenu );
#ifndef Q_WS_WIN

        editMenu->insertSeparator();
        setLyxPipeAction->addTo( editMenu );
#endif

    }
    textEdit->wordWrapAction->addTo( viewMenu );
    textEdit->wordUnWrapAction->addTo( viewMenu );
    viewMenu->insertSeparator();
    viewCb2BibAction->addTo( viewMenu );
}

void c2bEditor::setIcons()
{
    setIcon( QPixmap::fromMimeSource( APP_ICON_CB2BIB ) );
    QIconSet is;
    is.setPixmap( QPixmap::fromMimeSource( "filesave_22.png" ), QIconSet::Automatic );
    is.setPixmap( QPixmap::fromMimeSource( "d_filesave_22.png" ), QIconSet::Automatic ,
                  QIconSet::Disabled );
    fileSaveAction->setIconSet( is );
    is.setPixmap( QPixmap::fromMimeSource( "filesaveas_22.png" ), QIconSet::Automatic );
    is.setPixmap( QPixmap::fromMimeSource( "d_filesaveas_22.png" ), QIconSet::Automatic ,
                  QIconSet::Disabled );
    fileSaveAsAction->setIconSet( is );
}

void c2bEditor::createReferenceList()
{
    dwRList = new QDockWindow( QDockWindow::InDock, this );
    RList = new ReferenceList( textEdit, dwRList );
    dwRList->setResizeEnabled( TRUE );
    dwRList->setCloseMode( QDockWindow::Always );
    addDockWindow( dwRList, DockBottom );
    dwRList->setWidget( RList );
    dwRList->setCaption( "Reference List" );
    viewReferenceListAction->setEnabled( TRUE );
    connect( RList, SIGNAL(openFileRequested(const QString&)),this,
             SIGNAL(helpRequested(const QString&)));
    connect( RList, SIGNAL(statusMessage(const QString&)),this,
             SLOT(statusMessage(const QString&)));
    connect( viewReferenceListAction, SIGNAL( toggled(bool) ),
             this, SLOT( viewReferenceList(bool) ) );
    setLyxPipeAction = new QAction( this, "setLyxPipeAction" );
    setLyxPipeAction->setMenuText( tr( "Set active LyX pipe ..." ) );
    setLyxPipeAction->setText( tr( "Set active LyX pipe name" ) );
    connect( setLyxPipeAction, SIGNAL( activated() ), RList, SLOT( setLyxPipe() ) );
}

void c2bEditor::closeEvent( QCloseEvent *ce )
{
    if ( c2bEditorClose() )
        ce->accept();
}

bool c2bEditor::c2bEditorClose()
{
    if ( fileSaveAction->isEnabled() )
    {
        switch( QMessageBox::information( this, tr("cb2Bib Info"),
                                          tr("The file has been modified.\n"
                                             "Do you want to save the changes?"),
                                          "&Save", "&Discard", "&Cancel",
                                          0,      // Enter == button 0
                                          2 ) )
        { // Escape == button 2
        case 0: // Save clicked or Alt+S pressed or Enter pressed.
            fileSave();
            break;
        case 1: // Discard clicked or Alt+D pressed
            // don't save but exit
            break;
        case 2: // Cancel clicked or Escape pressed
            return FALSE;
        }
    }
    emit aboutToQuit();
    QSettings settings;
    settings.insertSearchPath( QSettings::Windows, WINDOWS_REGISTRY );
    settings.writeEntry( APP_KEY + "edWindowWidth", width() );
    settings.writeEntry( APP_KEY + "edWindowHeight", height() );
    settings.writeEntry( APP_KEY + "toolbar", !toolBar->isHidden() );
    if ( viewReferenceListAction->isEnabled() )
        settings.writeEntry( APP_KEY + "referencelist", !dwRList->isHidden() );
    return TRUE;
}

void c2bEditor::isModified()
{
    fileSaveAction->setEnabled( TRUE );
}

void c2bEditor::fileExit()
{
    qApp->closeAllWindows();
}

void c2bEditor::fileSave()
{
    QFile file( EFile );
    if ( ! file.open( IO_WriteOnly ) )
    {
        QMessageBox::warning( this, tr("cb2Bib Info"),
            tr( QString("Unable to open file %1 for writing."
                        "\nError: '%2'\n\n\n").
                arg(EFile).arg(file.errorString()) ),
            tr("&Continue") );
        return;
    }
    QTextStream stream( &file );
    stream << textEdit->text();
    fileSaveAction->setEnabled( FALSE );
    textEdit->setModified( FALSE );
}

void c2bEditor::fileSaveAs()
{
    QString fileName = QFileDialog::getSaveFileName(EFile, "*", this);
    if (fileName.isEmpty())
        return;
    if (QFile::exists(fileName))
    {
        int ret = QMessageBox::information(this, "cb2Bib Editor Info", tr("File %1 already exists.\n"
                                           "Do you want to overwrite it?")
                                           .arg(QDir::convertSeparators(fileName)),
                                           QMessageBox::Yes | QMessageBox::Default,
                                           QMessageBox::No | QMessageBox::Escape);
        if (ret == QMessageBox::No)
            return;
    }
    EFile = fileName;
    fileSave();
    setCaption( tr( QString("%1 - cb2Bib").arg(EFile) ) );
}

void c2bEditor::saveAndExecute()
{
    if ( fileSaveAction->isEnabled() )
        fileSave();
    emit Execute();
}

void c2bEditor::load( const QString& ms )
{
    QFile file( EFile );
    if ( ! file.open( IO_ReadOnly ) )
    {
        QMessageBox::information(
            c2bMain, tr("cb2Bib Info"),
            tr( QString("Unable to open file %1 for reading.\nError: '%2'\n\n").
                arg(EFile).arg(file.errorString()) ) + QString( ms +
                        "Alternatively, edit and save under the current name.\n\n"),
            tr("&Continue") );
    }
    else
    {
        QTextStream stream( &file );
        textEdit->setText( stream.read() );
    }
    fileSaveAction->setEnabled( FALSE );
    textEdit->setModified( FALSE );
}

void c2bEditor::reload( const QString& f )
{
    // This function must be called ONLY in BibTeX mode
    // Pointers are undefined otherwise
    if ( EditorType != "BibTeX" || EFile != f )
        return;

    if ( fileSaveAction->isEnabled() )
    {
        switch(
            QMessageBox::information( this, tr("cb2Bib Info"),
                                      tr("The file is modified on disk by adding a reference.\n"
                                         "Do you want to save the Editor changes? "
                                         "(Last reference will be lost.)"),
                                      "&Save", "&Discard and Reload", "&Cancel",
                                      0,      // Enter == button 0
                                      2 ) )
        { // Escape == button 2
        case 0: // Save clicked or Alt+S pressed or Enter pressed.
            fileSave();
            break;
        case 1: // Discard clicked or Alt+D pressed
            // don't save but exit
            break;
        case 2: // Cancel clicked or Escape pressed
            return;
        }
    }
    load();
    RList->refreshList();
    textEdit->scrollToBottom();
}

void c2bEditor::pasteCurrentBibTeX()
{
    textEdit->insert( bp->makeBib( FALSE ) );
}

void c2bEditor::journalsToFull()
{
    QString text = bp->setJournalsToFull( textEdit->text() );
    textEdit->setText( text );
}

void c2bEditor::journalsToAbbreviated()
{
    QString text = bp->setJournalsToAbbreviated( textEdit->text() );
    textEdit->setText( text );
}

void c2bEditor::postProcess()
{
    c2bPostProcess* ppBib = new c2bPostProcess( EFile, this );
    connect( ppBib, SIGNAL(helpRequested(const QString&)),this,
             SIGNAL(helpRequested(const QString&)));
    connect( ppBib, SIGNAL(openFileRequested(const QString&)),this,
             SIGNAL(helpRequested(const QString&)));
    ppBib->show();
}

void c2bEditor::helpEditorHelp()
{
    emit helpRequested( "http://www.molspaces.com/d_cb2bib-c2beditor.php" );
}

void c2bEditor::viewTools( bool stat )
{
    if ( stat )
        toolBar->show();
    else
        toolBar->hide();
}

void c2bEditor::viewReferenceList( bool stat )
{
    if ( stat )
        dwRList->show();
    else
        dwRList->hide();
}

void c2bEditor::viewCb2Bib()
{
    c2bMain->showNormal();
    c2bMain->raise();
    c2bMain->setActiveWindow();
}

void c2bEditor::statusMessage( const QString& ms )
{
    statusBar()->message( ms, MESSAGE_TIME );
}

void c2bEditor::cursorPositionChanged( int row, int col )
{
    lineLabel->setText( tr( " Line: %1 Col: %2 " ).arg( row + 1 ).arg( col + 1 ) );
}

void c2bEditor::overwriteModeChanged()
{
    if( textEdit->isOverwriteMode() )
        overwriteLabel->setText( tr(" OVR ") );
    else
        overwriteLabel->setText( tr(" INS ") );
}

const QString c2bEditor::editFileName()
{
    return ( EFile );
}

void c2bEditor::newSetting()
{
    // Custum, font related setttings from main cb2Bib setup
    QSettings settings;
    settings.insertSearchPath( QSettings::Windows, WINDOWS_REGISTRY );
    QFont font;
    font.setFamily( settings.readEntry( APP_KEY + "Font0", WINDOW_FF ) );
    font.setPointSize( settings.readNumEntry( APP_KEY + "FontSize0", WINDOW_FS ) );
    textEdit->setFont( font );
    if ( EditorType == "RegExp" || EditorType == "NetQInfo" )
        ((reSyntaxHighlighter*)sH)->reloadColors();
    else if ( EditorType == "BibTeX" )
        ((bibSyntaxHighlighter*)sH)->reloadColors();
}
