/***************************************************************************
 *   Copyright (C) 2003-2005 by liuspider                                  *
 *   liuspider@users.sourceforge.net                                       *
 *                                                                         *
 *   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.                                   *
 ***************************************************************************/
#define USE_SCIM_KDE_SETTINGS
#include "inputwindow.h"

#include "scimlookuptable.h"
#include "scimlineedit.h"
#include "scimdragableframe.h"
#include "src/skimglobalactions.h"

#include <qlineedit.h>
#include "scimstringlistitem.h"
#include <kdebug.h>
#include <kiconloader.h>

#define TOP_LEVEL_WFLAGS \
   Qt::WStyle_Customize|Qt::WStyle_NoBorder|Qt::WStyle_StaysOnTop|Qt::WX11BypassWM|Qt::WStyle_Tool

inputWindow::inputWindow( SkimPluginManager* is, QWidget* parent, const char* name, WFlags fl )
    : ScimDragableFrame( parent, parent, name, fl )
{
    setKeepVisible( TRUE );
    allModules = is;
    InputServer = allModules->getInputServer();

    setFrameStyle( QFrame::NoFrame );

    ScreenRect = QApplication::desktop()->screenGeometry();
    if ( !name )
      setName( "inputWindow" );
    setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ) );
    inputWindowLayout = new QVBoxLayout( this, 0, 1, "inputWindowLayout");
    inputWindowLayout->setResizeMode( QLayout::FreeResize );

    PreEditText = new ScimLineEdit( this, "PreEditText" );
    PreEditText->setFrameStyle( QFrame::StyledPanel | QFrame::Raised );
    PreEditText->hide();
    PreEditText->setBackgroundOrigin( QLineEdit::AncestorOrigin );
    PreEditText->setMouseTracking( FALSE );
    PreEditText->setAcceptDrops( FALSE );
    inputWindowLayout->addWidget( PreEditText );

    AuxText = new ScimStringListItem(this);
    AuxText->setFrameStyle( QFrame::StyledPanel | QFrame::Raised );
    inputWindowLayout->addWidget( AuxText );
    AuxText->hide();

    LookupLbl = new ScimLookupTable( this, inputWindowLayout, "LookupLbl",
      ScimKdeSettings::lookupTable_IsVertical());
    LookupLbl->setEnableMouse(ScimKdeSettings::enableMouse_IW());
    LookupLbl->setEnableHighlight(ScimKdeSettings::highlight_Candidate());
    LookupLbl->setFrameStyle( QFrame::StyledPanel | QFrame::Raised );

    inputWindowLayout->addWidget( LookupLbl );

    languageChange();
    clearWState( WState_Polished );

    // signals and slots connections
    connect( LookupLbl, SIGNAL( previousPageRequested() ), InputServer, SLOT( lookupTablePageUp() ) );
    connect( LookupLbl, SIGNAL( nextPageRequested() ), InputServer, SLOT( lookupTablePageDown() ) );

    connect( InputServer, SIGNAL( updatePreeditStringReq(const QString &, const scim::AttributeList &) ),
        this, SLOT( updatePreeditString(const QString &, const scim::AttributeList & ) ) );
    connect( InputServer, 
        SIGNAL(updateLookupTableReq(const QStringList&, const QStringList&, 
            QValueList< scim :: AttributeList >&, int, int, scim::uint32, size_t & )),
        SLOT( updateLookupTable(const QStringList&, const QStringList&, 
            QValueList< scim :: AttributeList >&, int, int, scim::uint32, size_t & ) ) );
    connect( InputServer, SIGNAL( updateAuxStringReq(const QString &, const scim::AttributeList & ) ),
        this, SLOT(updateAuxString(const QString &, const scim::AttributeList & ) ) );

    connect( InputServer, SIGNAL( showAuxStringReq() ), this, SLOT( showAuxString() ) );
    connect( InputServer, SIGNAL( hideAuxStringReq() ), this, SLOT( hideAuxString() ) );
    connect( InputServer, SIGNAL( showLookupTableReq() ), this, SLOT( showLookupTable() ) );
    connect( InputServer, SIGNAL( showPreeditStringReq() ), this, SLOT( showPreeditString() ) );
    connect( InputServer, SIGNAL( hidePreeditStringReq() ), this, SLOT( hidePreeditString() ) );
    connect( InputServer, SIGNAL( hideLookupTableReq() ),
        this, SLOT( hideLookupTable() ) );
    connect( InputServer, SIGNAL( updateSpotLocationReq( int, int ) ),
        this, SLOT( updateSpotLocation( int, int ) ) );
    connect( InputServer, SIGNAL(updatePreeditCaretReq(int ) ),
        PreEditText, SLOT(setCursorPosition ( int )));
//     connect( InputServer, SIGNAL( turnOnPanelReq() ), this, SLOT( show() ) );
    connect( InputServer, SIGNAL( turnOffPanelReq() ), this, SLOT( hide() ) );
    connect( InputServer, SIGNAL( turnOffPanelReq() ), LookupLbl, SLOT( hide() ) );
    
    connect( LookupLbl, SIGNAL(itemSelected(int )), InputServer, SLOT(selectLookupTableItem(int )));

    StickAction =
        static_cast<KToggleAction*>(allModules->getActionCollection()->action( "stick_inputwindow" ));

    changeSetting();
}

inputWindow::~inputWindow(){
    ScimKdeSettings::setIs_Sticky(sticky);
    ScimKdeSettings::setEmbedded_Lookup_Table(LookupLbl->isAttached());
}

void inputWindow::toggleStick()
{
    StickAction->setIcon( StickAction->isChecked() ? "pin_down": "pin_up" );
    sticky = StickAction->isChecked();
}
void inputWindow::changeSetting()
{
//     kdDebug(18010) << k_lineinfo << " inputWindow::changeSetting()\n";
    if(!ScimKdeSettings::iW_Font().isEmpty())
    {
      QFont customFont;
      customFont.fromString(ScimKdeSettings::iW_Font());
      if(customFont != font())
        setFont(customFont);
    } else
      unsetFont();

    LookupLbl->setVertical(ScimKdeSettings::lookupTable_IsVertical());
    LookupLbl->setEnableMouse(ScimKdeSettings::enableMouse_IW());
    LookupLbl->setEnableHighlight(ScimKdeSettings::highlight_Candidate());

    if(ScimKdeSettings::embedded_Lookup_Table() != LookupLbl->isAttached())
        LookupLbl->switchMode();

    sticky = ScimKdeSettings::is_Sticky();
    StickAction->setChecked(sticky);
    toggleStick();
}

void inputWindow::languageChange()
{
}

void inputWindow::updateAuxString( const QString & aux, const scim::AttributeList & attrs)
{
  AuxText->setText( aux, attrs );
}

void inputWindow::showAuxString()
{
  AuxText->show();
  if( !isVisible() )
      show();
  scheduleAdjustSize();
}

void inputWindow::hideAuxString()
{
  AuxText->hide();
  scheduleAdjustSize();
}

void inputWindow::updateSpotLocation( int x, int y )
{
    insertPointX = x; insertPointY = y;

    if(sticky) return;

    move( x, y );

    scheduleAdjustSize();
}
void inputWindow::updatePreeditString( const QString & newprestr, const scim::AttributeList & atl)
{
    PreEditText->setText( newprestr, atl );
    scheduleAdjustSize();
}

void inputWindow::hidePreeditString()
{
    PreEditText->hide();
    scheduleAdjustSize();
}
void inputWindow::showPreeditString()
{
    PreEditText->show();
    if( !isVisible() )
      show();
    scheduleAdjustSize();
}
void inputWindow::updateLookupTable( const QStringList& labellist, 
                                     const QStringList& lookupstringlist, 
                                     QValueList<scim::AttributeList > & attrslist,
                                     int cursor, int page_start,
                                     scim::uint32 candidates, size_t & exact_item_num)
{
    //the line below should be called after updateContent, but now it's a ugly hack
    //to push_front a highlight attribute to the attrslist
    LookupLbl->updateHighlight( cursor );

    exact_item_num = LookupLbl->updateContent(labellist, lookupstringlist, attrslist);
    LookupLbl->enablePreviousPage(page_start);
    LookupLbl->enableNextPage(page_start + exact_item_num < candidates);
//     LookupLbl->updateHighlight( currentHighlight );
    scheduleAdjustSize();
}

bool inputWindow::can_hide (void)
{
    if (PreEditText->isVisible() ||
        AuxText->isVisible() ||
        (LookupLbl->isAttached() && LookupLbl->isVisible()))
        return false;
    return true;
}

void inputWindow::adjustSize()
{
    if(can_hide())
        hide();
    else
        ScimDragableFrame::adjustSize();

    if(!LookupLbl->isAttached()) {
        if(isVisible())
        {
            std::vector<QRect> places;
            QRect candidate;
            {
                //find all possible locations where we can put the lookuptable
                candidate = LookupLbl->frameGeometry();
                candidate.moveTopLeft(QPoint(insertPointX, frameGeometry().bottomLeft().y() + 5)); //below
                places.push_back(candidate);
                candidate = LookupLbl->frameGeometry();
                candidate.moveTopLeft(QPoint(frameGeometry().topRight().x() + 5, insertPointY)); //right
                places.push_back(candidate);
                candidate = LookupLbl->frameGeometry();
                candidate.moveTopRight(QPoint(frameGeometry().topLeft().x() - 5, insertPointY)); //left
                places.push_back(candidate);
            }
    
            for(uint i=0; i<places.size(); i++)
            {
                //this will verify candidate is in the screen, if not it will be changed
                screenContainsRect(places[i]);
                QRect intersect = places[i] & frameGeometry();
                if ( intersect.isEmpty() )
                {
                    LookupLbl->move(places[i].topLeft());
                    break;
                }
            }
            
        }
        else //all the other two windows are not visible, so just move lookup table to the cursor pos
            LookupLbl->move(insertPointX, insertPointY);

        LookupLbl->adjustSize();
    }

    return;
}

void inputWindow::hideLookupTable()
{
    LookupLbl->hide();
    scheduleAdjustSize();
}
void inputWindow::showLookupTable()
{
    LookupLbl->show();
    if( !isVisible() )
      show();
    scheduleAdjustSize();
}

#include <kgenericfactory.h>
typedef KGenericFactory<InputWindowPlugin> InputWindowPluginFactory;
K_EXPORT_COMPONENT_FACTORY( skimplugin_inputwindow,
                              InputWindowPluginFactory( "skimplugin_inputwindow" ) )

InputWindowPlugin::InputWindowPlugin( QObject *parent, const char *name, const QStringList & /*args*/ )
 : SkimPlugin(InputWindowPluginFactory::instance(), parent, name)
{
    inputw = new inputWindow(static_cast<SkimPluginManager *>(parent), 0,0, TOP_LEVEL_WFLAGS);
    connect( this, SIGNAL(settingsChanged()), inputw, SLOT(changeSetting()));
}

void InputWindowPlugin::toggleStick() {
    inputw->toggleStick();
}

InputWindowPlugin::~InputWindowPlugin()
{
    delete inputw;
}

#include "inputwindow.moc"
