/*
 * This file is part of the M-Edit program (Copyright 1996 by Vincenzo Morello)
 * Permission to use is hereby granted for any purpose.
 *
 * Contains search and replace callbacks.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "mgui.h"
#include "medit.h"
#include "me.h"

extern void AddUndoData(FILE_DATA *pfd,
	char *oldtext, int start, int oldlen,
	char *newtext, int newlen);

void CancelCB(MOBJECT p, void *od, void *ad)
{
	MShellDestroy(p);
}

void GoToLineCB(MOBJECT p, void *od, void *ud)
{
	MOBJECT		shell = (MOBJECT)ud;
	FILE_DATA	*pfd = MObjectGetUserData(shell);

	shell = MDCreategotoline_shell();
	MObjectSetUserData(gotoline_e, pfd);
	MObjectSetUserData(gotoline_ok_pb, gotoline_e);
	MShellRealize(shell);
}

void GotolineOkCB(MOBJECT p, void *od, void *ad)
{
	MOBJECT		ed = MObjectGetUserData(p);
	FILE_DATA	*pfd = MObjectGetUserData(ed);
	int		line;
	char		buff[16];

	MObjectGetText(ed, buff);
	line = atoi(buff);
	MEditSetCursorXY(pfd->edit, 0, line-1);
	MShellDestroy(p);
}

void GotolineEditActCB(MOBJECT p, void *od, void *ad)
{
	FILE_DATA	*pfd = MObjectGetUserData(p);
	int		line;
	char		buff[16];

	MObjectGetText(p, buff);
	line = atoi(buff);
	MEditSetCursorXY(pfd->edit, 0, line-1);
	MShellDestroy(p);
}

void IgnoreCaseCB(MOBJECT p, MVALUE od, void *ad)
{
	FILE_DATA	*pfd = MObjectGetUserData(p);

	pfd->ignore_case = (int)od;
}

void SearchForwardCB(MOBJECT p, void *od, void *ad)
{
	FILE_DATA	*pfd = MObjectGetUserData(p);
	int		curs_pos, len;
	char		buff[50], str[64];

	MObjectGetText(search_e, buff);
	curs_pos = MEditGetCursorPos(pfd->edit);
	if ((curs_pos = MEditFindSubStringForward(
	    pfd->edit, curs_pos, buff, pfd->ignore_case)) >= 0) {
		len = strlen(buff);
		MEditSetCursorPos(pfd->edit, curs_pos+len);
		MEditSetSelection(pfd->edit, curs_pos, curs_pos + len);
		if (pfd->search_text)
			free(pfd->search_text);
		pfd->search_text = malloc(len+1);
		strcpy(pfd->search_text, buff);
	}
	else {
		sprintf(str, "String:\n%s\nnot found", buff);
		MMessageDialog("Warning", str, " Ok " , NULL);
	}
	MShellDestroy(p);
}

void SearchBackwardCB(MOBJECT p, void *od, void *ad)
{
	FILE_DATA	*pfd = MObjectGetUserData(p);
	int		curs_pos, len;
	char		buff[50], str[64];

	MObjectGetText(search_e, buff);
	curs_pos = MEditGetCursorPos(pfd->edit);
	if ((curs_pos = MEditFindSubStringBackward(pfd->edit,
	    curs_pos, buff, pfd->ignore_case)) >= 0) {
		len = strlen(buff);
		MEditSetCursorPos(pfd->edit, curs_pos+len);
		MEditSetSelection(pfd->edit, curs_pos, curs_pos + len);
		if (pfd->search_text)
			free(pfd->search_text);
		pfd->search_text = malloc(len+1);
		strcpy(pfd->search_text, buff);
	}
	else {
		sprintf(str, "String:\n%s\nnot found", buff);
		MMessageDialog("Warning", str, " Ok " , NULL);
	}
	MShellDestroy(p);
}

static void SearchEditActCB(MOBJECT p, char *od, void *ud)
{
	SearchForwardCB((MOBJECT)ud, NULL, NULL);
}

void SearchCB(MOBJECT p, void *od, void *ud)
{
	MOBJECT		shell = (MOBJECT)ud;
	FILE_DATA	*pfd = MObjectGetUserData(shell);

	shell = MDCreatesearch_shell();
	if (pfd->search_text) {
		MObjectSetText(search_e, pfd->search_text);
		MEditSetReplace(search_e);
	}
	MEditSetActCallback(search_e, SearchEditActCB, search_f_pb);
	MObjectSetUserData(search_f_pb, pfd);
	MObjectSetUserData(search_b_pb, pfd);
	MObjectSetUserData(ignore_case_tb, pfd);
	MTButtonSetActivationStatus(ignore_case_tb, pfd->ignore_case);
	MShellRealize(shell);
}

void SearchNextCB(MOBJECT p, void *od, void *ud)
{
	MOBJECT		shell = (MOBJECT)ud;
	FILE_DATA	*pfd = MObjectGetUserData(shell);
	int		curs_pos, end;

	if (pfd->search_text == NULL) {
		MBeep();
		return;
	}
	curs_pos = MEditGetCursorPos(pfd->edit);
	if ((curs_pos = MEditFindSubStringForward(pfd->edit,
	    curs_pos, pfd->search_text, pfd->ignore_case)) >= 0) {
		end = curs_pos + strlen(pfd->search_text);
		MEditSetCursorPos(pfd->edit, end);
		MEditSetSelection(pfd->edit, curs_pos, end);
	}
	else
		MBeep();
}

void SearchPrevCB(MOBJECT p, void *od, void *ud)
{
	MOBJECT		shell = (MOBJECT)ud;
	FILE_DATA	*pfd = MObjectGetUserData(shell);
	int		curs_pos, end;

	if (pfd->search_text == NULL) {
		MBeep();
		return;
	}
	curs_pos = MEditGetCursorPos(pfd->edit);
	if ((curs_pos = MEditFindSubStringBackward(pfd->edit,
	    curs_pos, pfd->search_text, pfd->ignore_case)) >= 0) {
		end = curs_pos + strlen(pfd->search_text);
		MEditSetCursorPos(pfd->edit, curs_pos);
		MEditSetSelection(pfd->edit, curs_pos, end);
	}
	else
		MBeep();
}

void ReplaceCB(MOBJECT p, void *od, void *ud)
{
	MOBJECT		shell = (MOBJECT)ud;
	FILE_DATA	*pfd = MObjectGetUserData(shell);

	shell = MDCreatereplace_shell();
	if (pfd->search_text)
		MObjectSetText(replace_r_e, pfd->search_text);
	if (pfd->replace_text)
		MObjectSetText(replace_w_e, pfd->replace_text);
	MObjectSetUserData(replace_one_pb, pfd);
	MObjectSetUserData(replace_some_pb, pfd);
	MObjectSetUserData(replace_sel_pb, pfd);
	MObjectSetUserData(replace_all_pb, pfd);
	MShellRealize(shell);
}

void ReplaceOneCB(MOBJECT p, void *od, void *ad)
{
	FILE_DATA	*pfd = MObjectGetUserData(p);
	int		curs_pos, oldlen, newlen;
	char		search[50], replace[50], str[64];
	char		*oldtext, *newtext;

	MObjectGetText(replace_r_e, search);
	MObjectGetText(replace_w_e, replace);
	oldlen = strlen(search);
	newlen = strlen(replace);
	if (pfd->search_text)
		free(pfd->search_text);
	pfd->search_text = malloc(oldlen+1);
	if (pfd->search_text)
		strcpy(pfd->search_text, search);
	if (pfd->replace_text)
		free(pfd->replace_text);
	pfd->replace_text = malloc(newlen+1);
	if (pfd->replace_text)
		strcpy(pfd->replace_text, replace);
	curs_pos = MEditGetCursorPos(pfd->edit);
	if ((curs_pos = MEditFindSubStringForward(pfd->edit, curs_pos, search, False)) >= 0) {
		MEditChangeText(pfd->edit, curs_pos, oldlen, replace, newlen);
		pfd->modified = True;
		MObjectSetText(pfd->modified_label, "*");
		oldtext = malloc(oldlen+1);
		if (oldtext) {
			strcpy(oldtext, search);
			newtext = malloc(newlen+1);
			if (newtext) {
				strcpy(newtext, replace);
				AddUndoData(pfd, oldtext, curs_pos, oldlen,
					    newtext, newlen);
			}
			else
				free(oldtext);
		}
	}
	else {
		sprintf(str, "String:\n%s\nnot found", search);
		MMessageDialog("Warning", str, " Ok " , NULL);
	}
	MShellDestroy(p);
}

void ReplaceAllSomeSelExec(MOBJECT p, int all, int sel)
{
	FILE_DATA	*pfd = MObjectGetUserData(p);
	int		curs_pos, oldlen, newlen, sel_end;
	int		changed, ret;
	char		search[50], replace[50], str[64];
	char		*oldtext, *newtext;

	MObjectGetText(replace_r_e, search);
	MObjectGetText(replace_w_e, replace);
	MShellDestroy(p);

	oldlen = strlen(search);
	newlen = strlen(replace);
	if (pfd->search_text)
		free(pfd->search_text);
	pfd->search_text = malloc(oldlen+1);
	strcpy(pfd->search_text, search);
	if (pfd->replace_text)
		free(pfd->replace_text);
	pfd->replace_text = malloc(newlen+1);
	strcpy(pfd->replace_text, replace);

	oldtext = MObjectGetText(pfd->edit, NULL);

	changed = False;
	if (sel)
		MEditGetSelection(pfd->edit, &curs_pos, &sel_end);
	else
		curs_pos = MEditGetCursorPos(pfd->edit);
	while ((curs_pos = MEditFindSubStringForward(pfd->edit, curs_pos, search, False)) >= 0) {
		if (sel) {
			if (curs_pos + oldlen > sel_end)
				break;
		}
		else if (!all) {
			MEditSetCursorPos(pfd->edit, curs_pos);
			MEditSetSelection(pfd->edit, curs_pos, curs_pos+oldlen);
			ret = MMessageDialog("", "Replace Current Selection ?",
					     "Yes", "No", "Stop", NULL);
			if (ret == 2)
				break;
		}
		if (all || sel || ret == 0)
			MEditChangeText(pfd->edit, curs_pos, oldlen, replace, newlen);
		curs_pos += newlen;
		changed = True;
	}
	if (!changed) {
		sprintf(str, "String:\n%s\nnot found", search);
		MMessageDialog("Warning", str, " Ok " , NULL);
		if (oldtext)
			free(oldtext);
	}
	else {
		pfd->modified = True;
		MObjectSetText(pfd->modified_label, "*");
		if (oldtext) {
			newtext = MObjectGetText(pfd->edit, NULL);
			if (newtext)
				AddUndoData(pfd, oldtext, 0, strlen(oldtext),
					    newtext, strlen(newtext));
			else
				free(oldtext);
		}
	}
}

void ReplaceAllCB(MOBJECT p, void *od, void *ad)
{
	ReplaceAllSomeSelExec(p, True, False);
}

void ReplaceSomeCB(MOBJECT p, void *od, void *ad)
{
	ReplaceAllSomeSelExec(p, False, False);
}

void ReplaceSelectionCB(MOBJECT p, void *od, void *ad)
{
	ReplaceAllSomeSelExec(p, False, True);
}
