/* ###########################################################################
 *
 *                 The MiniBuffer Class
 *                 read minibuffer.h for more
 *                 information.
 * 
 *           Copyright (C) 1995 1996 Matthias Ettrich
 *           and the LyX Team.  
 * 
 * ###########################################################################
 */

#include "config.h"
#include "definitions.h"
#include "buffer.h" 
#include "keybind.h" 
#include "lyx.h"
#include "minibuffer.h"  

extern FD_form_main *fd_form_main;

void MiniBuffer::TimerCB(FL_OBJECT *, long tmp)
{
	MiniBuffer *obj= (MiniBuffer*)tmp;
	obj->Init();
}


void MiniBuffer::bufferCB(FL_OBJECT *ob, long tmp)
{
	// called when minibuffer changes by user typing
	MiniBuffer *obj = (MiniBuffer*) tmp;
	const char *cmd = fl_get_input(ob);
	if (lyx_debug_level)
	fprintf(stderr,"MiniBuffer NOW: `%s'\n",cmd);
	if (obj->cur_cmd) delete obj->cur_cmd;
	obj->cur_cmd = StringCopy(cmd);
}


void MiniBuffer::AbortingCB(FL_OBJECT *, long tmp)
{
	MiniBuffer *obj = (MiniBuffer*)tmp;
	fl_set_object_shortcut(obj->execcommand, "", 1);
	fl_set_object_shortcut(obj->abortcommand, "", 1);
	fl_set_focus_object(fd_form_main->form_main,fd_form_main->work_area);
	obj->Init();
   
}


void MiniBuffer::ExecutingCB(FL_OBJECT *, long tmp)
{
	MiniBuffer *obj = (MiniBuffer*)tmp;
	//fprintf(stderr,"Getting ready to execute: `%s'\n",obj->cur_cmd);
	fl_set_object_shortcut(obj->execcommand, "", 1);
	fl_set_object_shortcut(obj->abortcommand, "", 1);
	fl_set_focus_object(fd_form_main->form_main,fd_form_main->work_area);
	if (!obj->cur_cmd || obj->cur_cmd[1] <= ' ') { 
		obj->Init();
		return ; }
	obj->Set("Executing:", obj->cur_cmd);
	char *res;
        char *arg = (char *) strchr(obj->cur_cmd, ' ');
        if (arg) {
	   *(arg++) = '\0';      
	   // Eat white spaces
	   while (arg[0]==' ') arg++;
	}
        //fprintf(stderr, "ARG[%s|%s]", obj->cur_cmd, arg);
	if ((res=DispatchFunction(LookupLyxFunc(obj->cur_cmd),arg))){
		obj->Set("No match!", res);
		obj->shows_no_match = true;
	}
	else
		obj->Init();
	return ;
}


void MiniBuffer::ExecCommand()
{
  Set("",NULL,NULL,0);
  fl_set_focus_object(fd_form_main->form_main,the_buffer);
  fl_set_object_shortcut(execcommand, "^M", (long)this);
  fl_set_object_shortcut(abortcommand, "^[^g", (long)this);
}


FL_OBJECT *MiniBuffer::add(int type, FL_Coord x, FL_Coord y,
			   FL_Coord w, FL_Coord h, const char *label)
{
	FL_OBJECT *obj;
	
	the_buffer = obj = fl_add_input(type,x,y,w,h,label);
        fl_set_object_boxtype(obj,FL_DOWN_BOX);
        fl_set_object_resize(obj, FL_RESIZE_ALL);
        fl_set_object_gravity(obj, SouthWestGravity, SouthEastGravity);
        fl_set_object_color(obj,FL_MCOL,FL_MCOL);
        fl_set_object_lsize(obj,FL_NORMAL_SIZE);
        fl_set_object_callback(obj,bufferCB,(long)this);
        fl_set_object_return(obj,FL_RETURN_ALWAYS);

        execcommand = fl_add_button(FL_HIDDEN_BUTTON,0,0,0,0,"");
        fl_set_object_callback(execcommand,ExecutingCB,(long)this);
        abortcommand = fl_add_button(FL_HIDDEN_BUTTON,0,0,0,0,"");
        fl_set_object_callback(abortcommand,AbortingCB,(long)this);

	// timer
	timer = fl_add_timer(FL_HIDDEN_TIMER, 0,0,0,0, "Timer");
	fl_set_object_callback(timer, TimerCB, (long)this);
	
	return obj;
}


// Added optional arg `delay_secs', defaults to 4.
//When 0, no timeout is done. RVDK_PATCH_5 
void MiniBuffer::Set(const char* s1, const char* s2,
		   const char* s3, int delay_secs)
{
	if (s2 || s3) {
		char* s1a = (char*) s1;
		char* s2a = (char*) s2;
		char* s3a = (char*) s3;
		if (!s1a)
			s1a = "";
		if (!s2a)
			s2a = "";
		if (!s3a)
			s3a = "";
		sprintf(text,"%s %s %s", s1a, s2a, s3a);
	} else {
		sprintf(text,"%s",(s1) ? s1 : "");
	}
	
	if (!the_buffer->focus)
		fl_set_input(the_buffer, text);
	
	XFlush(fl_display);
	//  if ( delay_secs > 0 )
	setTimer(delay_secs);
}


void MiniBuffer::Init()
{
   char* s="";
   extern kb_sequence keyseq;
   extern unsigned meta_fake_bit;

   // When meta-fake key is pressed, show the key sequence so far + "M-".
   if ( meta_fake_bit != 0 ) {
          keyseq.print(text, 190, true);
          strcat(text, " M-");
   }

   // Else, when a non-complete key sequence is pressed,
   // show the available options.
   else if ( keyseq.length > 0 ) 
          keyseq.printOptions(text, 190);
   
   // Else, show the buffer state.
   else {
          if (bufferlist.current()->text){
                  if (!bufferlist.current()->isLyxClean())
                          s = "(Changed)";
                  sprintf(text,"Current document: %s %s", 
                                  bufferlist.current()->filename, 
                                  s);
//                                lyxstyle.NameOfClass(bufferlist.current()->parameters.textclass));
          }
          else
                  sprintf(text,"* No document open * ");
   }
   
   fl_set_input(the_buffer, text);
   XFlush(fl_display);
}


// allows to store and reset the contents one time. Usefull for
// status messages like "load font" (Matthias)
void MiniBuffer::Store()
{
  if (text_stored)
    delete text_stored;
  text_stored = StringCopy(fl_get_input(the_buffer));
}


void MiniBuffer::Reset()
{
  if (text_stored){
    Set(text_stored);
    delete text_stored;
    text_stored = NULL;
  }
}

void MiniBuffer::Activate()
{
  fl_activate_object(the_buffer);
  fl_activate_object(execcommand);
  fl_activate_object(abortcommand);
}

void MiniBuffer::Deactivate()
{
  fl_deactivate_object(the_buffer);
  fl_deactivate_object(execcommand);
  fl_deactivate_object(abortcommand);
}

