/* Copyright (C) 2002 Philippe Fremy <pfremy@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; see the file COPYING.  If not, write to
	 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
	 Boston, MA 02111-1307, USA.
	 */


#ifndef VIMWIDGET_H
#define VIMWIDGET_H

#include <qxembed.h>
#include <qtimer.h>
#include <qstringlist.h>
#include <qptrlist.h>
#include <kprocess.h>
#include <kwinmodule.h>
#include "xvim.h"
#include <kdebug.h>

enum VDcop {
	Insert=3, //insert mode
	Normal=2, //normal mode
	Cmd=1, //cmd line mode
	Raw=0 //raw commands, using them directly is _NOT_ adviced
};
typedef enum VDcop VimDcop;

class DCmd {
	public:
		DCmd(QString cmd = QString::null, VimDcop mode = Raw) {
			this->mode = mode;
			this->cmd = cmd;
		}
		VimDcop getMode() {
			return mode;
		}
		QString getCmd() {
			return cmd;
		}
	private:
		VimDcop mode;
		QString cmd;
};


class VimWidget: public QXEmbed
{
	Q_OBJECT

	public:
		VimWidget( QWidget *parent=0, const char *name=0, WFlags f = 0 );
		~VimWidget();

		/** Send a command to vim, puttting vim in normal mode first (whatever the
		 * current mode was). */
		void sendNormalCmd( const QString & cmd );

		/** send a command to vim, puttting vim in insert mode first (whatever the
		 * current mode was). */
		void sendInsertCmd( const QString & cmd);

		/** send a command to vim, puttting vim in command-line mode first
		 * (whatever the current mode was). Command-line is when you press ':'
		 * in normal mode. The function automatically prepends with ':' and
		 * appends the newline necessary to make vim process the command line. 
		 * Ex : sendCommandLine("% s/hop/bof/g") to make vim replace all strings
		 * "hop" by "bof".*/
		void sendCmdLineCmd( const QString & cmd );

		/** Convenience function. */
		void setVimVariable( const QString &var, const QString &value = "") { 
			if (value!="" && !value.isEmpty() && !value.isNull() ) sendCmdLineCmd("set " + var + "=" + value ); 
			else sendCmdLineCmd ("set " + var);
		}

		/** send a command to vim, without changing the mode. The result could
		 * differ whether you are in normal mode or in insert mode. Therefore,
		 * you should prefer the previous functions. 
		 */
		void sendRawCmd( const QString & cmd );

		/** Evaluate an expression in vim. Do ":help expr" in vim for more 
		 * details about expressions.
		 * If the returned string is empty, vim has not understood your
		 * expression (vim is not very verbose).
		 *
		 * Remember that :
		 * - vim options must be preceded by a '&'
		 * - strings must be inside single or double quotes
		 * - vim internal variable must be preceded by 'b:', 'w:', 'g:', 'l:'
		 * , 'a:' * or 'v:'. See help about "internal-variable" for more 
		 * details.
		 * - environment must be preceded by '$'
		 * - register must by preceded by '@'
		 *
		 * Examples: 
		 *     evalExpr( "&tabstop" ) 		-> width of a tab
		 *     evalExpr( "v:lang" )   		-> current vim language
		 *     evalExpr( "mode()" )   		-> current editing mode
		 */
		QString evalExpr( const QString &expr );

		//if we aborted consider we started (widgets are actually shown)
		bool hasStarted() { return (abort || _vimReady) ? true : false; }

		bool useDCOP() { return usedcop; }

		QString serverName() { return _serverName; }

	protected slots:
		void embedVimWid( WId wid );

	signals:
		// emitted when the server is ready to manage requests
		void vimReady();

	protected:
		void focusInEvent( QFocusEvent *e ) { kdDebug() << "FocusIN" <<endl;
		QXEmbed::focusInEvent( e ); }

		void focusOutEvent( QFocusEvent *e ) { kdDebug()<< "FocusOUT" << endl;
		QXEmbed::focusOutEvent( e );}

		//this is the real eval expr
		QString X11EvalExpr( const QString &expr );
		QString DcopEvalExpr( const QString &expr );

		void closeVim();
		virtual bool close( bool alsoDelete );

		//X11
		void processX11Cmd(QString newCmd = QString());
		//DCOP
		void processDcopCmd(QString newCmd = QString(), VimDcop v=Raw );
		
		bool setExecutable();

		bool _dying;
		bool abort;
		QString _serverName;
		QString _vimExecutable;
		bool _vimReady;
		KWinModule *kwm;
		//config file
		bool hideMenu;
		bool hideTool;
		bool usedcop;
		int guitype;

		//actions queues, one dor dcop, one for X11, will be optimized some day
		QStringList _pendingCmd;
		QPtrList<DCmd> dcopcmd;
};

#endif // VIMWIDGET_H
