/***************************************************************************
 *   Copyright (C) 2007 by Rajko Albrecht                                  *
 *   ral@alwins-world.de                                                   *
 *                                                                         *
 *   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.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
 ***************************************************************************/

#include "diffbrowser.h"
#include "diffbrowserdata.h"
#include "tdesvnsettings.h"

#include <tdeglobalsettings.h>
#include <tdeglobal.h>
#include <kdebug.h>
#include <tdefiledialog.h>
#include <tdemessagebox.h>
#include <tdeapplication.h>
#include <tdelocale.h>

#include <tqfont.h>
#include <tqtooltip.h>
#include <tqwhatsthis.h>
#include <tqtextcodec.h>

/*!
    \fn DiffBrowser::DiffBrowser(TQWidget*parent=0,const char*name=0)
 */
DiffBrowser::DiffBrowser(TQWidget*parent,const char*name)
    : KTextBrowser( parent, name)
{
    setTextFormat(TQt::PlainText);
    setFont(TDEGlobalSettings::fixedFont());
    m_Data = new DiffBrowserData;

    setWordWrap(TQTextEdit::NoWrap);
    m_Data->m_Syntax = new DiffSyntax(this);
    TQToolTip::add(this,i18n("Ctrl-F for search, F3 or Shift-F3 for search again."));
    TQWhatsThis::add(this,i18n("<b>Display differences between files</b><p>You may search inside text with Ctrl-F.</p><p>F3 for search forward again, Shift-F3 for search backward again.</p><p>You may save the (original) output with Ctrl-S.</p>"));
    setFocus();
}

/*!
    \fn DiffBrowser::~DiffBrowser()
 */
 DiffBrowser::~DiffBrowser()
{
    delete m_Data;
}

void DiffBrowser::setText(const TQString&aText)
{
    m_Data->m_content.setRawData(aText.local8Bit(),aText.local8Bit().size());
    KTextBrowser::setText(aText);
    setCursorPosition(0,0);
}

void DiffBrowser::setText(const TQByteArray&aText)
{
    m_Data->m_content=aText;
    printContent();
    setCursorPosition(0,0);
}

void DiffBrowser::printContent()
{
    TQTextCodec * cc = TQTextCodec::codecForName(Kdesvnsettings::locale_for_diff().ascii());
    if (!cc) {
        KTextBrowser::setText(TQString::fromLocal8Bit(m_Data->m_content,m_Data->m_content.size()));
    } else {
        KTextBrowser::setText(cc->toUnicode(m_Data->m_content,m_Data->m_content.size()));
    }
}

/*!
    \fn DiffBrowser::saveDiff()
 */
void DiffBrowser::saveDiff()
{
    TQString saveTo = KFileDialog::getSaveFileName(TQString(),"text/x-diff");
    if (saveTo.isEmpty()) {
        return;
    }
    TQFile tfile(saveTo);
    if (tfile.exists()) {
        if (KMessageBox::warningYesNo(TQT_TQWIDGET(TDEApplication::activeModalWidget()),
                                     i18n("File %1 exists - overwrite?").arg(saveTo))
            !=KMessageBox::Yes) {
            return;
        }
    }
    tfile.open(IO_Truncate|IO_WriteOnly|IO_Raw);
    TQDataStream stream( &tfile );
    stream.writeRawBytes(m_Data->m_content.data(),m_Data->m_content.size());
}

void DiffBrowser::keyPressEvent(TQKeyEvent*ev)
{
    if ( ev->key() == Key_Return) {
        ev->ignore();
        return;
    }
    if (ev->key() == Key_F3) {
        if (ev->state() == ShiftButton) {
            searchagainback_slot();
        } else {
            searchagain_slot();
        }
    } else if (ev->key()==Key_F && ev->state() == ControlButton) {
        startSearch();
    } else if (ev->key()==Key_S && ev->state() == ControlButton) {
        saveDiff();
    } else {
        KTextBrowser::keyPressEvent(ev);
    }
}

void DiffBrowser::startSearch()
{
    if( !m_Data->srchdialog ) {
        m_Data->srchdialog = new KEdFind( this, "searchdialog", false);
        connect(m_Data->srchdialog,TQT_SIGNAL(search()),this,TQT_SLOT(search_slot()));
        connect(m_Data->srchdialog,TQT_SIGNAL(done()),this,TQT_SLOT(searchdone_slot()));
    }
    TQString _st = m_Data->srchdialog->getText();
    m_Data->srchdialog->setText(_st.isEmpty() ? m_Data->pattern : _st);
    m_Data->srchdialog->show();
    m_Data->srchdialog->result();
}

/*!
    \fn DiffBrowser::search_slot()
 */
void DiffBrowser::search_slot()
{
    if( !m_Data->srchdialog ) {
        return;
    }
    TQString to_find_string = m_Data->srchdialog->getText();
    doSearch(to_find_string,m_Data->srchdialog->case_sensitive(),m_Data->srchdialog->get_direction());
}

void DiffBrowser::doSearch(const TQString&to_find_string,bool case_sensitive,bool back)
{
    if( !m_Data->srchdialog ) {
        return;
    }
    int line, col;
    getCursorPosition(&line,&col);
    if (m_Data->last_search != DiffBrowserData::NONE && !back) {
        col = col+1;
    }
    while (1) {
        bool result = find(to_find_string,case_sensitive,false,
                        (!back),&line,&col);

        if (result) {
            m_Data->last_search = back?DiffBrowserData::BACKWARD:DiffBrowserData::FORWARD;
            m_Data->pattern=to_find_string;
            break;
        }
        TQWidget * _parent = m_Data->srchdialog->isVisible()?m_Data->srchdialog:parentWidget();
        if (!m_Data->srchdialog->get_direction()) {
            // forward
            int query = KMessageBox::questionYesNo(
                    _parent,
                    i18n("End of document reached.\n"\
                            "Continue from the beginning?"),
                            i18n("Find"),KStdGuiItem::cont(),i18n("Stop"));
            if (query == KMessageBox::Yes){
                line = 0;
                col = 0;
                m_Data->last_search = DiffBrowserData::FORWARD;
            } else {
                break;
            }
        } else {
            int query = KMessageBox::questionYesNo(
                    _parent,
                    i18n("Beginning of document reached.\n"\
                            "Continue from the end?"),
                            i18n("Find"),KStdGuiItem::cont(),i18n("Stop"));
            if (query == KMessageBox::Yes){
                line = lines()-1;
                TQString string = text(line);
                col  = string.length();
                if (col>0) {
                    --col;
                }
                m_Data->last_search = DiffBrowserData::BACKWARD;
            } else {
                break;
            }
        }
    }
}

/*!
    \fn DiffBrowser::searchdone_slot()
 */
void DiffBrowser::searchdone_slot()
{
    if (!m_Data->srchdialog)
        return;

    m_Data->srchdialog->hide();
    setFocus();
    m_Data->last_finished_search = m_Data->last_search;
    m_Data->last_search = DiffBrowserData::NONE;
    m_Data->cs = m_Data->srchdialog->case_sensitive();
}

void DiffBrowser::searchagain_slot()
{
    doSearchAgain(false);
}

void DiffBrowser::searchagainback_slot()
{
    doSearchAgain(true);
}

void DiffBrowser::doSearchAgain(bool back)
{
    if (!m_Data->srchdialog || m_Data->pattern.isEmpty()) {
        startSearch();
    } else {
        m_Data->last_search = m_Data->last_finished_search;
        doSearch(m_Data->pattern,m_Data->cs,back);
        m_Data->last_finished_search = m_Data->last_search;
        m_Data->last_search = DiffBrowserData::NONE;
    }
}

void DiffBrowser::slotTextCodecChanged(const TQString&codec)
{
    if (Kdesvnsettings::locale_for_diff()!=codec) {
        Kdesvnsettings::setLocale_for_diff(codec);
        printContent();
        Kdesvnsettings::self()->writeConfig();
    }
}

#include "diffbrowser.h.moc"
