#include <support.h>

#include "global.h"
#include "clipbrd.h"
#include "icon.h"
#include "memory.h"
#include "menu.h"
#include "obj.h"
#include "rsc.h"
#include "text.h"
#include "window.h"
#include "makro.h"

EXTERN BOOLEAN f_to_desk;

/* exportierte Variablen *******************************************************/
BOOLEAN	makro_play, makro_rec;


/*******************************************************************************/
#define MAKRO_PLAY_LEN 100				/* Makrolen expanded */
#define MAKRO_DEF_LEN  100				/* einzelne Makrolnge */

#define UNUSED	0							/* Werte fr mode */
#define TASTEN	1
#define BLOCK	2

/*******************************************************************************/
typedef struct 
{
	WORD		mode;
	WORD		len;
	WORD		key;			/* F1 .. F20 */
	UBYTE		name[10];
	union
	{
		UWORD	puffer[MAKRO_DEF_LEN];
		RING	text;
	} daten;
} T_MAKRO;

/* lokale Variablen ************************************************************/
LOCAL UWORD		makro_puffer[MAKRO_PLAY_LEN],
					*makro_ptr, *makro_end;
LOCAL T_MAKRO 	makro_list[MAKRO_ANZ],
					*makro_rec_ptr,
					*makro_play_ptr;
LOCAL WORD		makro_play_counter;


GLOBAL BOOLEAN pre_makro(KEYDATA *key)
{
	if (makro_play)								/* Macro abspielen */
	{
retry:
		if (makro_ptr < makro_end)
		{
			WORD	ks, kr;
	
			norm2gem(*makro_ptr, &kr, &ks);
			gem2key(ks, kr, key);
			makro_ptr++;
			return TRUE;
		}
		else											/* Abspielen beenden */
		{
			if (makro_play_counter > 1)
			{
				makro_play = FALSE;
				start_play(makro_play_ptr->key, makro_play_counter-1);
				goto retry;
			}
			else
				end_play();
		}
	}
	return FALSE;
}

GLOBAL VOID post_makro(KEYDATA *key)
{
	if (makro_rec && !makro_play)				/* Zeichen erfassen */
														/* wenn echtes Zeichen */
	{
		WORD pos = makro_rec_ptr->len;
		if (pos < MAKRO_DEF_LEN)
		{
			makro_rec_ptr->daten.puffer[pos] = key->normkey;
			makro_rec_ptr->len++;
		}
		else
			mybeep();
	}
}

GLOBAL VOID start_blk_rec(UBYTE *name, WORD key, RINGP r)
{
	WORD		new, i;
	T_MAKRO	*m;

	new = -1;
	m = makro_list;
	for (i=0; i<MAKRO_ANZ; i++,m++)			/* Eintrag suchen */
	{
		if (m->mode==UNUSED)						/* Leerer Eintrag */
			new = i;
		else if (m->key == key)					/* Alten Eintrag berschreiben */
		{
			new = i;
			break;
		}
	}
	if (new >- 1)
	{
		m = makro_list+new;
		if (m->mode == BLOCK)
			free_textring(&m->daten.text);
		else
			init_textring(&m->daten.text);
		m->len = 0;								/* leeren */
		m->mode = BLOCK;
		m->key = key;
		doppeln(r,&m->daten.text);
		strcpy(m->name,name);
	}
}


GLOBAL VOID start_rec(VOID)
{
	WORD		new, i;
	T_MAKRO	*m;

	if (makro_rec_ptr!=NULL)
	{
		m = makro_rec_ptr;
		if (m->key == -1)
			m->key = UNUSED;
		makro_rec_ptr = NULL;
	}
	new = -1;
	m = makro_list;
	for (i=0; i<MAKRO_ANZ; i++,m++)			/* Eintrag suchen */
	{
		if (m->mode==UNUSED)						/* Leerer Eintrag */
			new = i;
	}
	if (new>-1)										/* Gefunden */
	{
		m = &makro_list[new];
		makro_rec = TRUE;							/* Zeichen erfassen */
		makro_rec_ptr = m;
		m->len = 0;									/* leeren */
		m->key = -1;
		m->name[0] = EOS;
		print_headline(" Makro-Rec ");
		menu_text(menu, MSRECORD, STRING(MSTOPSTR));
	}
}


GLOBAL VOID end_rec(BOOLEAN one_more)
{
	WORD len = makro_rec_ptr->len;

	makro_rec = FALSE;
	if (len>1)
	{
		if (one_more)
			makro_rec_ptr->len--;					/* letztes ^M raus */
		makro_rec_ptr->mode = TASTEN;				/* Makro ist O.K. */
	}
	else
		makro_rec_ptr = NULL;
	print_headline("            ");
	menu_text(menu, MSRECORD, STRING(MRECSTR));
}


GLOBAL BOOLEAN start_play(WORD key, WORD anz)
{
	WORD		i;
	T_MAKRO	*m;
	BOOLEAN	ret = FALSE;

	if (key == -1)				/* aktuelles Makro */
	{
		m = makro_rec_ptr;
		if (m == NULL)
		{
			mybeep();
			return FALSE;
		}
	}
	else							/* Funktionstaste */
	{
		m = makro_list;
		for (i=0; i<MAKRO_ANZ; i++,m++)			/* Eintrag suchen */
			if (m->mode!=UNUSED && m->key==key)
				break;
		if (i == MAKRO_ANZ)
		{
			if (!f_to_desk)						/* Ping nur, wenn nicht an AV-Server */
				mybeep();
			return FALSE;
		}
	}
	if (m->mode == TASTEN)						/* Eintrag gefunden */
	{
		if (!makro_play)							/* Neues M. starten */
		{
			memcpy(makro_puffer, m->daten.puffer, m->len * (short) sizeof(UWORD));
			makro_end = makro_puffer+m->len;
			makro_ptr = makro_puffer;
			makro_play = TRUE;
			makro_play_ptr = m;
			makro_play_counter = max(1,anz);
			print_headline(" Makro-Play ");
			ret = TRUE;
		}
		else											/* Makro ruft Makro auf */
		{
			WORD len_old = (short) (makro_end - makro_ptr);
			WORD len_new = m->len;
			if (len_old+len_new < MAKRO_PLAY_LEN)
			{
				/* Alten Rest nach hinten verschieben */
				memmove(&makro_puffer[len_new],makro_ptr, len_old * (short) sizeof(UWORD));
				/* Neues Makro einfgen */
				memcpy(makro_puffer,m->daten.puffer,m->len * (short) sizeof(UWORD));
				makro_end = makro_puffer+(len_old+len_new);
				makro_ptr = makro_puffer;
				ret = TRUE;
			}
			else
				mybeep();
		}
	}
	else if(m->mode==BLOCK && !makro_rec && !makro_play)
	{
		RING t;

		init_textring(&t);
		doppeln(&m->daten.text,&t);
		clip_takes_text(&t);
		do_action(DO_PASTE);
		ret = TRUE;
	}
	else												/* Kein Eintrag gefunden */
		mybeep();
	return ret;
}

GLOBAL VOID end_play(VOID)
{
	if (makro_play)
	{
		makro_play = FALSE;
		makro_play_ptr = NULL;
		print_headline("            ");
	}
}

GLOBAL VOID del_makro(WORD key)
{
	T_MAKRO	*m;
	WORD		i;

	m = makro_list;
	for (i = MAKRO_ANZ; (--i) >= 0; m++)
	{
		if (m->mode != UNUSED && m->key == key)
		{
			if (makro_rec_ptr != NULL && makro_rec_ptr == m)
				m->key = -1;
			else
			{
				if (m->mode == BLOCK)
					kill_textring(&m->daten.text);
				m->mode = UNUSED;
			}
			break;
		}
	}
}


/*
 * Makro-String aus CFG in Puffer wandeln.
*/
GLOBAL VOID set_makro_str(UBYTE *ptr)
{
	UBYTE		*p;
	WORD		i, l;
		
	if (*ptr == '"')
	{
		for (i = MAKRO_ANZ; (--i) >= 0; )	/* leeren Eintrag suchen */
			if (makro_list[i].mode == UNUSED)
				break;

		if (i >= 0)
		{
			ptr += 1;						/* " berspringen */
			p = strchr(ptr, '"');
			*p = EOS;
			strcpy(makro_list[i].name, ptr);
			ptr = p + 2;					/* ", berspringen */
			
			p = strchr(ptr, ',');
			*p = EOS;
			makro_list[i].key = (WORD)strtol(ptr, NULL, 16);
			makro_list[i].mode = TASTEN;
	
			ptr = p + 1;
			l = 0;
			while (ptr)
			{
				p = strchr(ptr, ',');
				if (p)
					*p = EOS;
				makro_list[i].daten.puffer[l] = (WORD)strtol(ptr, NULL, 16);
				l++;
				if (p == NULL)
					ptr = NULL;
				else
					ptr = p + 1;
			}
			makro_list[i].len = l;
		}
	}
}


/*
 * Puffer in Makro-String fr CFG wandeln.
*/
GLOBAL BOOLEAN get_makro_str(WORD nr, UBYTE *ptr)
{
	UBYTE	s[5];
	WORD	j;

	if (makro_list[nr].name[0] != EOS)
	{
		sprintf(ptr, "\"%s\",%X", makro_list[nr].name, makro_list[nr].key);
		for (j = 0; j < makro_list[nr].len; j++)
		{
			sprintf(s, ",%X", makro_list[nr].daten.puffer[j]);
			strcat(ptr, s);
		}
		return TRUE;
	}
	return FALSE;
}


GLOBAL VOID init_makro(VOID)
{
	WORD 		i;
	T_MAKRO	*m;

	makro_play = makro_rec = FALSE;
	for (i = MAKRO_ANZ, m = makro_list; (--i) >= 0; m++)
		m->mode = UNUSED;
}


/***************************************************************************/
/* Dialog ******************************************************************/
/***************************************************************************/

LOCAL VOID makro_on_key(UBYTE *name, WORD key)
{
	T_MAKRO	*m;

	if (makro_rec_ptr!=NULL)
	{
		del_makro(key);
		m = makro_rec_ptr;
		makro_rec_ptr = NULL;
		m->key = key;
		strcpy(m->name, name);
	}
}


LOCAL VOID get_makro_name(WORD scan, UBYTE *name)
{
	WORD		i;
	T_MAKRO	*m;

	*name = EOS;
	m = makro_list;
	for (i = MAKRO_ANZ; (--i) >= 0; m++)
		if (m->mode != UNUSED && m->key == scan)
		{
			strcpy(name, m->name);
			break;
		}
}


LOCAL VOID show_makro(WORD nr)	/* 0..19 */
{
	UBYTE	name[9];

	if (nr < 10)
		get_makro_name(0x3B00 + (nr * 0x100), name);
	else
		get_makro_name(0x5400 + ((nr - 10) * 0x100), name);

	objc_setstring(funktionstasten, FNNAME, name);
	draw_Objc(funktionstasten, FNNAME, 1);

	disable_objc(funktionstasten, FNDELETE, (name[0] == EOS));
	draw_Objc(funktionstasten, FNDELETE, 1);
}

GLOBAL VOID makro_dial(VOID)
{
	WORD		antw, y, edit_obj;
	UBYTE		name[9];
	DIALINFO	dial;
	BOOLEAN	quit = FALSE;
	WORD		makro_nr = 0;

	save_clip();

	disable_objc(funktionstasten, FNBLOCK, ist_leer(&clip_text));
	objc_setstring(funktionstasten, FNKEY, " F1");

	open_dial(funktionstasten, &dial);
	dial_draw(&dial);
	show_makro(makro_nr);
	edit_obj = FNNAME;
	do
	{
		antw = dial_do(&dial, &edit_obj) & 0x7FFF;
		switch (antw)
		{
			case FNSTR :
			case FNCIRCLE :
			case FNKEY :
				if (antw == FNKEY)
					y = popup_select(funktionstasten, FNKEY, popups, FUNCPOP, FALSE, DO_POPUP);
				else
					y = popup_select(funktionstasten, FNKEY, popups, FUNCPOP, FALSE, DO_CYCLE);
				y -= POPF1;
				if (y >= 0)
				{
					makro_nr = y;
					show_makro(makro_nr);
				}
				break;
			case FNDELETE:
				if (makro_nr < 10)
					del_makro(0x3B00 + (makro_nr * 0x100));
				else
					del_makro(0x5400 + ((makro_nr - 10) * 0x100));
				show_makro(makro_nr);
				select_objc(funktionstasten, antw, FALSE);
				draw_Objc(funktionstasten, antw, 1);
				break;
			case FNRECORD:
			case FNBLOCK:
				objc_getstring(funktionstasten, FNNAME, name);
				select_objc(funktionstasten, antw, FALSE);
				draw_Objc(funktionstasten, antw, 1);
				if (*name == EOS)
					note(1, MKNAME);
				else
					quit = TRUE;
				break;
			default:
				quit = TRUE;
				break;
		}
	}
	while (!quit);
	select_objc(funktionstasten, antw, FALSE);
	dial_end(&dial);
	if (antw == FNRECORD)
	{
		if (makro_nr < 10)
			makro_on_key(name, 0x3B00 + (makro_nr * 0x100));
		else
			makro_on_key(name, 0x5400 + ((makro_nr - 10) * 0x100) );
	}
	if (antw == FNBLOCK)
	{
		if (makro_nr < 10)
			start_blk_rec(name, 0x3B00 + (makro_nr * 0x100), &clip_text);
		else
			start_blk_rec(name, 0x5400 + ((makro_nr - 10) * 0x100), &clip_text);
	}
}
