#include <qmsgbox.h>

#include "FindReplace.h"
#include "KColorMLE.h"



//////////////////////////////////////////////////////////////////////////
//
// Find Methods
// 
//////////////////////////////////////////////////////////////////////////
void KSyntaxMultiLineEdit::Search()
{
	// hide possibly visible replace dialog:
  if (replace_dialog)
		if (replace_dialog->isVisible())
			replace_dialog->hide();

  if(!srchdialog)
  {
    srchdialog = new KEdSrch(0, "searchdialog");
    connect(srchdialog, SIGNAL(search_signal()), this, SLOT(searchSlot()));
    connect(srchdialog, SIGNAL(search_done_signal()), this, SLOT(searchDoneSlot()));
  }

  if(hasMarkedText())
  {
	QString mark = markedText();
	if(!mark.isEmpty() && !mark.contains('\n'))
    	srchdialog->setText(mark);
	deselect();
  }

  last_search = NONE;

  clearFocus();

  QPoint point = mapToGlobal (QPoint (0,0));

  QRect pos = geometry();
  srchdialog->setGeometry(point.x() + ((pos.width()  - srchdialog->width()) >> 1),
			   			  point.y() + ((pos.height() - srchdialog->height()) >> 1), 
						  srchdialog->width(), srchdialog->height());
  srchdialog->show();
}
//////////////////////////////////////////////////////////////////////////



//////////////////////////////////////////////////////////////////////////
void KSyntaxMultiLineEdit::searchSlot()
{
  int line, col;

  if (!srchdialog)
    return;

  QString to_find_string = srchdialog->getText();
  getCursorPosition(&line,&col);
  
  if (last_search != NONE && srchdialog->directionIsBackward())
    col = col - pattern.length() - 1 ;

again:
  int  result = doSearch(to_find_string, srchdialog->case_sensitive(),
			 			 FALSE, (!srchdialog->directionIsBackward()),line,col);
    
  if(result == 0)
  {
    if(!srchdialog->directionIsBackward())
    { // forward search
    
      int query = QMessageBox::information(srchdialog,
					   klocale->translate("Find"), 
					   klocale->translate("End of document reached.\nContinue from the beginning?"), 
					   klocale->translate("Yes"),
					   klocale->translate("No"),
					   "",
					   0,1);
      if (query == 0)
      {
		line = 0;
		col = 0;
		goto again;
      }
    }
    else
    { //backward search
      
      int query = QMessageBox::information(srchdialog,
					   klocale->translate("Find"), 
					   klocale->translate("Beginning of document reached.\nContinue from the end?"), 
					   klocale->translate("Yes"),
					   klocale->translate("No"),
					   "",
					   0,1);
      if (query == 0)
      {
		QString string = textLine( numLines() - 1 );
		line = numLines() - 1;
		col  = string.length();
		last_search = BACKWARD;
		goto again;
      }
    }
  }
  else
  {
    emit cursorPosChanged(); 
  }
}
//////////////////////////////////////////////////////////////////////////



//////////////////////////////////////////////////////////////////////////
void KSyntaxMultiLineEdit::searchDoneSlot()
{
  	if (!srchdialog)
    	return;

  	srchdialog->hide();
  	setFocus();
  	last_search = NONE;
}
//////////////////////////////////////////////////////////////////////////



//////////////////////////////////////////////////////////////////////////
int KSyntaxMultiLineEdit::doSearch(QString s_pattern, bool case_sensitive, 
		    					   bool wildcard, bool forward, int line, int col)
{

  (void) wildcard; // reserved for possible extension to regex


  int i, length;  
  int pos = -1;

  if(forward)
  {
    QString string;

    for(i = line; i < numLines(); i++) 
    {
      string = textLine(i);

      pos = string.find(s_pattern, i == line ? col : 0, case_sensitive);
      
      if( pos != -1)
      {
      	length = s_pattern.length();

		setCursorPosition(i,pos,FALSE);
      
		for(int l = 0 ; l < length; l++)
		{
	  		cursorRight(TRUE);
		}
      
		setCursorPosition( i , pos + length, TRUE );
		pattern = s_pattern;
		last_search = FORWARD;

		return 1;
      }
    }
  }
  else
  { // searching backwards

    QString string;
    
    for(i = line; i >= 0; i--) 
    {
      string = textLine(i);
      int line_length = string.length();

      pos = string.findRev(s_pattern, line == i ? col : line_length , case_sensitive);

      if (pos != -1)
      {
		length = s_pattern.length();

		if( ! (line == i && pos > col ) )
		{
	  		setCursorPosition(i ,pos ,FALSE );
      
	  		for(int l = 0 ; l < length; l++)
	  		{
	    		cursorRight(TRUE);
	  		}	
      
	  		setCursorPosition(i ,pos + length ,TRUE );
	  		pattern = s_pattern;
	  		last_search = BACKWARD;
	  		return 1;
 		}
  	  }
    }
  }
  
  return 0;
}
//////////////////////////////////////////////////////////////////////////



//////////////////////////////////////////////////////////////////////////
int KSyntaxMultiLineEdit::repeatSearch() 
{
  	if(!srchdialog)
      	return 0;

  	if(pattern.isEmpty()) // there wasn't a previous search
    	return 0;

  	searchSlot();

  	setFocus();  
	return 1;
}
//////////////////////////////////////////////////////////////////////////



//////////////////////////////////////////////////////////////////////////
//
// Goto Methods
//
//////////////////////////////////////////////////////////////////////////
void KSyntaxMultiLineEdit::GotoLine() 
{
	if(!gotodialog)
		gotodialog = new KEdGotoLine(this, "gotodialog", numLines());

	clearFocus();

	gotodialog->show();
	gotodialog->markText();
	
		// this seems to be not necessary
		// gotodialog->setFocus();
		
	if(gotodialog->result()) 
	{
		setCursorPosition(gotodialog->getLineNumber() - 1 , 0, FALSE);
		emit cursorPosChanged();
		setFocus();
//		delete gotodialog;
//		gotodialog = 0;
	}
}
//////////////////////////////////////////////////////////////////////////



//////////////////////////////////////////////////////////////////////////
//
// Replace Methods
//
//////////////////////////////////////////////////////////////////////////
void KSyntaxMultiLineEdit::Replace()
{
	// alternative: search<->replace:
  if (srchdialog)
	if (srchdialog->isVisible())
		srchdialog->hide();
  

  if (!replace_dialog)
  {
    replace_dialog = new KEdReplace(0, "replace_dialog");
    connect(replace_dialog,SIGNAL(find_signal()),this,SLOT(replaceSearchSlot()));
    connect(replace_dialog,SIGNAL(replace_signal()),this,SLOT(replaceSlot()));
    connect(replace_dialog,SIGNAL(replace_all_signal()),this,SLOT(replaceAllSlot()));
    connect(replace_dialog,SIGNAL(replace_done_signal()),this,SLOT(replaceDoneSlot()));
  }

  if(hasMarkedText())
  {
	QString mark = markedText();
	if(!mark.isEmpty() && !mark.contains('\n'))
    	srchdialog->setText(mark);
	deselect();
  }

  last_replace = NONE;
  this->clearFocus();

  QPoint point = this->mapToGlobal (QPoint (0,0));

  QRect pos = this->geometry();
  replace_dialog->setGeometry(point.x() + pos.width()/2  - replace_dialog->width()/2,
			   point.y() + pos.height()/2 - replace_dialog->height()/2, 
			   replace_dialog->width(),
			   replace_dialog->height());
  replace_dialog->show();
  replace_dialog->result();
}
//////////////////////////////////////////////////////////////////////////



//////////////////////////////////////////////////////////////////////////
void KSyntaxMultiLineEdit::replaceSlot()
{
  if (!replace_dialog)
    return;

  if(!can_replace)
  {
      QApplication::beep();
      return;
  }

  int line,col, length;

  QString string = replace_dialog->getReplaceText();
  length = string.length();

  cut();

  getCursorPosition(&line,&col);

  insertAt(string,line,col);
//  setModified();
  emit textChanged();
  can_replace = FALSE;

  setCursorPosition(line,col);
  for( int k = 0; k < length; k++)
  {
    cursorRight(TRUE);
  }
}
//////////////////////////////////////////////////////////////////////////



//////////////////////////////////////////////////////////////////////////
void KSyntaxMultiLineEdit::replaceAllSlot()
{

  if (!replace_dialog)
    return;

  QString to_find_string = replace_dialog->getText();
  getCursorPosition(&replace_all_line,&replace_all_col);

  if (last_replace != NONE && replace_dialog->directionIsBackward())
  {
    replace_all_col = replace_all_col  - pattern.length() - 1 ;
  }
  
  deselect();

again:

  setAutoUpdate(FALSE);
  int result = 1;

  while(result)
  {

    result = doReplace(to_find_string, replace_dialog->case_sensitive(),
		       FALSE, (!replace_dialog->directionIsBackward()),
		       replace_all_line,replace_all_col,TRUE);
  }

  setAutoUpdate(TRUE);
  update();
    
  if(!replace_dialog->directionIsBackward())
  { // forward search
    
    int query = QMessageBox::information(
				   this,
				   klocale->translate("Find"), 
				   klocale->translate("End of document reached.\n"\
						      "Continue from the beginning?"), 
				   klocale->translate("Yes"),
				   klocale->translate("No"),
				   "",
				   0,1);
    if (query == 0)
    {
      replace_all_line = 0;
      replace_all_col = 0;
      goto again;
    }
  }
  else
  { //backward search
    
    int query = QMessageBox::information(
				   this,
				   klocale->translate("Find"), 
				   klocale->translate("Beginning of document reached.\n"\
						      "Continue from the end?"), 
				   klocale->translate("Yes"),
				   klocale->translate("No"),
				   "",
				   0,1);
    if (query == 0)
    {
      QString string = textLine( numLines() - 1 );
      replace_all_line = numLines() - 1;
      replace_all_col  = string.length();
      last_replace = BACKWARD;
      goto again;
    }
  }

  emit cursorPosChanged(); 
}
//////////////////////////////////////////////////////////////////////////



//////////////////////////////////////////////////////////////////////////
void KSyntaxMultiLineEdit::replaceSearchSlot()
{
  int line, col;

  if (!replace_dialog)
    return;

  QString to_find_string = replace_dialog->getText();
  getCursorPosition(&line,&col);
  
  //printf("col %d length %d\n",col, pattern.length());

  if (last_replace != NONE && replace_dialog->directionIsBackward())
  {
    col = col  - pattern.length() -1;
    if (col < 0 ) 
    {
      if(line !=0)
      {
		col = strlen(textLine(line - 1));
		line --;
      }
      else
      {
		int query = QMessageBox::information(
			 this,
			 klocale->translate("Replace"), 
			 klocale->translate("Beginning of document reached.\n"\
					    "Continue from the end?"), 
			 klocale->translate("Yes"),
			 klocale->translate("No"),
			 "",
			 0,1);

	  	if (query == 0)
	  	{
	  		QString string = textLine( numLines() - 1 );
	  		line = numLines() - 1;
	  		col  = string.length();
	  		last_replace = BACKWARD;
	  	}
      }
    }
  }

again:

  //  printf("Col %d \n",col);

  int  result = doReplace(to_find_string, replace_dialog->case_sensitive(),
			 			  false, (!replace_dialog->directionIsBackward()), line, col, false);
    
  if(result == 0){
    if(!replace_dialog->directionIsBackward())
    { // forward search
    
      int query = QMessageBox::information(
				     this,
				     klocale->translate("Replace"), 
				     klocale->translate("End of document reached.\n"\
							"Continue from the beginning?"), 
				     klocale->translate("Yes"),
				     klocale->translate("No"),
				     "",
				     0,1);
      if (query == 0){
	line = 0;
	col = 0;
	goto again;
      }
    }
    else{ //backward search
      
      int query = QMessageBox::information(
					   this,
					   klocale->translate("Replace"), 
					   klocale->translate("Beginning of document reached.\n"\
							      "Continue from the end?"), 
					   klocale->translate("Yes"),
					   klocale->translate("No"),
					   "",
					   0,1);
      if (query == 0){
	QString string = textLine( numLines() - 1 );
	line = numLines() - 1;
	col  = string.length();
	last_replace = BACKWARD;
	goto again;
      }
    }
  }
  else{

    emit cursorPosChanged(); 
  }
}
//////////////////////////////////////////////////////////////////////////



//////////////////////////////////////////////////////////////////////////
void KSyntaxMultiLineEdit::replaceDoneSlot()
{
  if (!replace_dialog)
    return;
  
  replace_dialog->hide();
  setFocus();

  last_replace = NONE;
  can_replace  = FALSE;
}
//////////////////////////////////////////////////////////////////////////



//////////////////////////////////////////////////////////////////////////
int KSyntaxMultiLineEdit::doReplace(QString s_pattern, bool case_sensitive, 
									bool wildcard, bool forward, int line, int col, bool replace_all)
{
  (void) wildcard; // reserved for possible extension to regex

  int line_counter, length;  
  int pos = -1;

  QString string;
  QString stringnew;
  QString replacement;
  
  replacement = replace_dialog->getReplaceText();
  line_counter = line;
  replace_all_col = col;

  if(forward)
  {
    int num_lines = numLines();
	
    while (line_counter < num_lines)
    {
      string = "";
      string = textLine(line_counter);

      if (replace_all)
		pos = string.find(s_pattern, replace_all_col, case_sensitive);
      else
		pos = string.find(s_pattern, line_counter == line ? col : 0, case_sensitive);

      if (pos == -1 )
      {
		line_counter ++;
		replace_all_col = 0;
		replace_all_line = line_counter;
      }

      if( pos != -1)
      {
		length = s_pattern.length();
	
		if(replace_all)
		{ // automatic

		  	stringnew = string.copy();
		  	stringnew.replace(pos, length, replacement);

			removeLine(line_counter);
			insertLine(stringnew.data(),line_counter);

		  	replace_all_col = replace_all_col + replacement.length();
		  	replace_all_line = line_counter;

//		    setModified();
	        textChanged();
		}
		else
		{ // interactive
		  	setCursorPosition(line_counter , pos, false);
		  	setCursorPosition(line_counter , pos + length, true);
			updateCell(line_counter, 0, false);
		  	pattern = s_pattern;
	  		last_replace = FORWARD;
		  	can_replace = TRUE;
		  	return 1;
		}	
      }
    }
  }
  else
  { // searching backwards

    while(line_counter >= 0)
    {

      string = "";
      string = textLine(line_counter);

      int line_length = string.length();

      if( replace_all )
      	pos = string.findRev(s_pattern, replace_all_col , case_sensitive);
      else
		pos = string.findRev(s_pattern, 
			   line == line_counter ? col : line_length , case_sensitive);

      if(pos == -1)
      {
		line_counter--;

		if(line_counter >= 0)
		{
	  		string = "";
	  		string = textLine(line_counter);
	  		replace_all_col = string.length();
	  
		}
		replace_all_line = line_counter;
      }


      if (pos != -1)
      {
		length = s_pattern.length();

		if(replace_all)
		{ // automatic

		  	stringnew = string.copy();
			stringnew.replace(pos,length,replacement);
	
			removeLine(line_counter);
	  		insertLine(stringnew.data(),line_counter);

	  		replace_all_col = replace_all_col - replacement.length();
	  		replace_all_line = line_counter;

//	  setModified();
			textChanged();

		}
		else
		{ // interactive
		  if( ! (line == line_counter && pos > col ) )
		  {
		    setCursorPosition(line_counter, pos, false);
		    setCursorPosition(line_counter, pos + length, true);
			updateCell(line, 0, false);
		    pattern = s_pattern;
	
		    last_replace = BACKWARD;
		    can_replace = TRUE;
		    return 1;
		  }
		}
      }
    }
  }
  
  return 0;
}
//////////////////////////////////////////////////////////////////////////

