#include <tqwidget.h>
#include <tqpopupmenu.h>
#include <tqtimer.h>

#include <tdeversion.h>
#include <kdebug.h>
#include <tdeconfig.h>
#include <tdeapplication.h>

#include <tdeparts/part.h>

#include <tdetexteditor/document.h>
#include <tdetexteditor/view.h>
#include <tdetexteditor/viewcursorinterface.h>
#include <tdetexteditor/popupmenuinterface.h>
#include <tdetexteditor/editinterface.h>
#include <tdetexteditor/selectioninterface.h>
#include <tdetexteditor/view.h>
#include <kxmlguiclient.h>
#include <kxmlguifactory.h>
#include <tdemainwindow.h>
#include <tdeactioncollection.h>
#include <tdelocale.h>
#include <tdestdaccel.h>

#include "toplevel.h"
#include "partcontroller.h"
#include "core.h"
#include "multibuffer.h"
#include "kdeveditorutil.h"

#include "editorproxy.h"

using namespace KTextEditor;

EditorProxy *EditorProxy::s_instance = 0;


EditorProxy::EditorProxy()
  : TQObject()
{
	m_delayedLineTimer = new TQTimer( this );
	connect( m_delayedLineTimer,  TQ_SIGNAL( timeout() ), this, TQ_SLOT(setLineNumberDelayed()) );
	TDEConfig *config = kapp->config();

	m_delayedViewCreationCompatibleUI = true;

	TDEAction *ac = new TDEAction( i18n("Show Context Menu"), 0, this,
		TQ_SLOT(showPopup()), TopLevel::getInstance()->main()->actionCollection(), "show_popup" );
    TDEShortcut cut ;/*= TDEStdAccel::shortcut(TDEStdAccel::PopupMenuContext);*/
    cut.append(KKey(CTRL+Key_Return));
    ac->setShortcut(cut);
}


EditorProxy *EditorProxy::getInstance()
{
  if (!s_instance)
    s_instance = new EditorProxy;

  return s_instance;
}

void EditorProxy::setLineNumberDelayed()
{
	if( !this ) return; ///This should fix a strange crash I use to encounter, where setLineNumberDelayed is called with this == NULL
  setLineNumber(m_delayedPart, m_delayedLine, m_delayedCol);
}


void EditorProxy::setLineNumber(KParts::Part *part, int lineNum, int col)
{
  if (!part || !part->inherits("KTextEditor::Document"))
    return;

  if ( lineNum < 0 )
    return;

  KURL url = dynamic_cast<KParts::ReadOnlyPart*>( part )->url();
  ViewCursorInterface *iface = dynamic_cast<ViewCursorInterface*>(part->widget());
  if (iface)
  {
#if KDE_IS_VERSION(3,5,5)
#else
    if (!part->widget()->hasFocus()) //workaround for TQXIMInputContext crashes. Keep for KDE <=3.5.4!
    {
      m_delayedPart = part;
      m_delayedLine = lineNum;
      m_delayedCol = col;
			m_delayedLineTimer->start( 1, true );
		} else
#endif
     iface->setCursorPositionReal(lineNum, col == -1 ? 0 : col);
  }
  else {
    // Save the position for a rainy day (or when the view gets activated and wants its position)
    for (TQValueList<MultiBuffer*>::ConstIterator it = m_editorParts.begin(); it != m_editorParts.end(); ++it)
        if ((*it)->hasURL( url )) {
            (*it)->registerDelayedActivation( part, lineNum, col );
        return;
      }

    // Shouldn't hit this?
    Q_ASSERT(false);
  }
}

void EditorProxy::installPopup( KParts::Part * part )
{

	if ( part->inherits("KTextEditor::Document") && part->widget())
	{
		PopupMenuInterface *iface = dynamic_cast<PopupMenuInterface*>(part->widget());
		if (iface)
		{
			KTextEditor::View * view = static_cast<KTextEditor::View*>( part->widget() );

			TQPopupMenu * popup = static_cast<TQPopupMenu*>( part->factory()->container("tdetexteditor_popup", view ) );

			if (!popup)
			{
				kdWarning() << k_funcinfo << "Popup not found!" << endl;
				return;
			}

			TDEAction * action = NULL;
			//If there is a tab for this file, we don't need to plug the closing menu entries here
			TDEConfig *config = TDEGlobal::config();
			config->setGroup("UI");
			bool m_tabBarShown = ! config->readNumEntry("TabWidgetVisibility", 0);
			if (!m_tabBarShown)
			{
				action = TopLevel::getInstance()->main()->actionCollection()->action( "file_close" );
				if ( action && !action->isPlugged( popup ) )
				{
					popup->insertSeparator( 0 );
					action->plug( popup, 0 );
				}
				action = TopLevel::getInstance()->main()->actionCollection()->action( "file_closeother" );
				if ( action && !action->isPlugged( popup ) )
					action->plug( popup, 1 );
			}

			iface->installPopup( popup );

			connect(popup, TQ_SIGNAL(aboutToShow()), this, TQ_SLOT(popupAboutToShow()));

			// ugly hack: mark the "original" items
			m_popupIds.resize(popup->count());
			for (uint index=0; index < popup->count(); ++index)
				m_popupIds[index] = popup->idAt(index);
		}
	}
}

void EditorProxy::popupAboutToShow()
{
	TQPopupMenu *popup = (TQPopupMenu*)sender();
	if (!popup)
	return;
	
	// ugly hack: remove all but the "original" items
	for (int index=popup->count()-1; index >= 0; --index)
	{
		int id = popup->idAt(index);
		if (m_popupIds.contains(id) == 0)
		{
			TQMenuItem *item = popup->findItem(id);
			if ( item && item->popup() )
				delete item->popup();
			else
				popup->removeItemAt(index);
		} 
	}

	KTextEditor::Document * doc = dynamic_cast<KTextEditor::Document*>( PartController::getInstance()->activePart() );
	if (!doc ) return;

	unsigned int line;
	unsigned int col;
	if ( !KDevEditorUtil::currentPositionReal( &line, &col, doc ) ) return;

	TQString wordstr;
	TQString selection = KDevEditorUtil::currentSelection( doc );
	if ( !selection.isEmpty() && selection.contains('\n') != 0 )
	{
		wordstr = selection;
	}
	else
	{
		wordstr = KDevEditorUtil::currentWord( doc );
	}

	TQString linestr = KDevEditorUtil::currentLine( doc );
	
	EditorContext context( doc->url(), line, col, linestr, wordstr );
	Core::getInstance()->fillContextMenu( popup, &context );

	// Remove redundant separators (any that are first, last, or doubled)
	bool lastWasSeparator = true;
	for( uint i = 0; i < popup->count(); ) 
	{
		int id = popup->idAt( i );
		if( lastWasSeparator && popup->findItem( id )->isSeparator() ) 
		{
			popup->removeItem( id );
			// Since we removed an item, don't increment i
		} else 
		{
			lastWasSeparator = false;
			i++;
		}
	}
	if( lastWasSeparator && popup->count() > 0 )
		popup->removeItem( popup->idAt( popup->count() - 1 ) );
}

void EditorProxy::showPopup( )
{
	kdDebug(9000) << k_funcinfo << endl;

	if ( KParts::Part * part = PartController::getInstance()->activePart() )
	{
		ViewCursorInterface *iface = dynamic_cast<ViewCursorInterface*>( part->widget() );
		if ( iface )
		{
			KTextEditor::View * view = static_cast<KTextEditor::View*>( part->widget() );
			TQPopupMenu * popup = static_cast<TQPopupMenu*>( view->factory()->container("tdetexteditor_popup", view ) );

			if ( popup )
			{
				popup->exec( view->mapToGlobal( iface->cursorCoordinates() ) );
			}
		}
	}
}

void EditorProxy::registerEditor(MultiBuffer* wrapper)
{
  m_editorParts.append(wrapper);
}

void EditorProxy::deregisterEditor(MultiBuffer* wrapper)
{
  m_editorParts.remove(wrapper);
}

TQWidget * EditorProxy::widgetForPart( KParts::Part * part )
{
	if ( !part ) return 0;

	if (part->widget())
		return part->widget();

    KURL url = dynamic_cast<KParts::ReadOnlyPart*>( part )->url();

    for (TQValueList<MultiBuffer*>::ConstIterator it = m_editorParts.begin(); it != m_editorParts.end(); ++it)
        if ((*it)->hasURL( url ))
			return *it;

	return 0L;
}

TQWidget * EditorProxy::topWidgetForPart( KParts::Part * part )
{
	if ( !part ) return 0;

    KURL url = dynamic_cast<KParts::ReadOnlyPart*>( part )->url();

    for (TQValueList<MultiBuffer*>::ConstIterator it = m_editorParts.begin(); it != m_editorParts.end(); ++it)
        if ((*it)->hasURL( url ))
			return *it;

	if (part->widget())
		return part->widget();

	return 0L;
}

bool EditorProxy::isDelayedViewCapable( )
{
	return m_delayedViewCreationCompatibleUI;
}

TQWidget *EditorProxy::findPartWidget(KParts::Part *part)
{
    for (TQValueList<MultiBuffer*>::ConstIterator it = m_editorParts.begin(); it != m_editorParts.end(); ++it)
        if ((*it)->hasPart(part))
            return *it;

    if (part->widget())
        return part->widget();

    return 0L;
}

#include "editorproxy.moc"
