#include "global.h"
#include "block.h"
#include "edit.h"
#include "memory.h"
#include "obj.h"
#include "rsc.h"
#include "text.h"

#define	CMD_NONE	0
#define	CMD_KRIT	1
#define	CMD_SORT	2

LOCAL WORD		last_cmd = CMD_NONE,
					start_x = 0, end_x = 0;		/* Kriterium */
LOCAL LONG		start_z = 0, end_z = 0;		/* Bereich */
LOCAL ZEILEP	p1, p2;
LOCAL BOOLEAN	sort_down = FALSE;			/* FLASE: a..z  TRUE: z..a */
LOCAL BOOLEAN	sort_grkl = TRUE;				/* Gro/Klein unterscheiden */

/*
 * Die nationalen Sonderzeichen werden auf die entsprechenden Vokale umgemappt
 * und somit direkt hinter sie sortiert.
 * Die Idee stammt aus dem Modul 'Strings' der MM2-Lib von Thomas Tempelmann.
*/
LOCAL UBYTE		sort_tab[] = 
{
	0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
	0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
	0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
	0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
	0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
	0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
	0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
	0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
	'C','u','e','a','a','a','a','c','e','e','e','i','i','i','A','A',
	'E','a','A','o','o','o','u','u','y','O','U',0x9B,0x9C,0x9D,'s',0x9F,
	'a','i','o','u','n','N','a','o',0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
	'a','o','O','o','o','O','A','A','O',0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
	'i','I',0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
	0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
	0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
	0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
};


LOCAL WORD my_strnicmp(UBYTE *s1, UBYTE *s2, WORD n)
{
	register UBYTE	c1, c2;
	register LONG	count;

	if (!s1)
		return s2 ? -1 : 0;
	
	if (!s2) 
		return 1;

	count = n;
	do 
	{
		c1 = *s1++; 
		c2 = *s2++; 
		if (sort_grkl)
		{
			c1 = nkc_toupper(c1);
			c2 = nkc_toupper(c2);
		}
	} 
	while (--count >= 0 && c1 && c1 == c2);

	if (count < 0)
		return(0);

	if (c1 == c2)
		return 0;
	else if (c1 == '\0')
		return -1;
	else if (c2 == '\0')
		return 1;
	else
		return (sort_tab[c1] - sort_tab[c2]);
}


LOCAL WORD laufcmp(ZEILEP l1, ZEILEP l2)
{
	WORD	n;
	
	if (start_x == 0 && end_x == 0)			/* ganze Zeilen vergleichen */
	{
		return my_strnicmp(TEXT(l1), TEXT(l2), l1->len);
	}
	else												/* nur teilweise vergleichen */
	{
		/* Zeile krzer als Kriterium-Start? */
		if (l2->len < start_x)
			return 1;

		/* Zeile krzer als Kriterium-Lnge? */
		if (l2->len < end_x)
			n = l2->len - start_x + 1;
		else
			n = end_x - start_x + 1;

		return my_strnicmp(TEXT(l1) + start_x, TEXT(l2) + start_x, n);
	}
}


/*
 * Langsam, aber dafr optimal simpel: Insertion Sort.
*/
LOCAL VOID insert_sort(RINGP r, ZEILEP ins)
{
	ZEILEP	col, lauf;

	lauf = LAST(r);
	if (sort_down)
		while (!IS_FIRST(lauf) && (laufcmp(lauf, ins) < 0))
			VORG(lauf);
	else
		while (!IS_FIRST(lauf) && (laufcmp(lauf, ins) > 0))
			VORG(lauf);
	
	col = new_col(TEXT(ins), ins->len);
	col_insert(lauf, col);
	r->lines++;
}

LOCAL VOID do_sort(TEXTP t_ptr, RINGP r)
{
	ZEILEP	start, ende, lauf;

	start = get_line(&t_ptr->text, start_z);
	ende = get_line(&t_ptr->text, end_z);
	init_textring(r);
	lauf = start;
	while (lauf != ende)
	{
		insert_sort(r, lauf);
		NEXT(lauf);
	}
	/* erste, leere Zeile entfernen */
	col_delete(r, FIRST(r));

	/* leere Zeile am Ende anhngen */
	lauf = new_col("", 0);
	col_append(r, lauf);
}

LOCAL VOID clear_sort(VOID)
{
	last_cmd = CMD_NONE;
	start_z = 0;
	end_z = 0;
	start_x = 0;
	end_x = 0;
}

VOID sort_block(TEXTP t_ptr)
{
	/* halbe Zeile markiert -> aufrunden zur nchsten */
	if (!(last_cmd == CMD_KRIT) && (t_ptr->x2 > 0) && !(IS_LAST(t_ptr->p2)))
	{
		t_ptr->z2++;
		t_ptr->p2 = t_ptr->p2->nachf;
	}

	if ((t_ptr->z2 > t_ptr->z1 + 1) || (last_cmd == CMD_KRIT))
	{
		RING	r;
		WORD	antw;
		UBYTE	str[26];

		if (last_cmd == CMD_KRIT)
		{
			clear_info(t_ptr);
			start_x = t_ptr->x1;
			end_x = t_ptr->x2 - 1;
		}
		else
		{
			start_z = t_ptr->z1;
			end_z = t_ptr->z2;
			p1 = t_ptr->p1;
			p2 = t_ptr->p2;
		}
		
		select_objc(sort, BSUP, !sort_down);
		select_objc(sort, BSDOWN, sort_down);
		select_objc(sort, BSGRKL, sort_grkl);

		sprintf(str, STRING(SZEILESTR), start_z, end_z);
		str[24] = EOS;
		objc_setstring(sort, BSZEILEN, str);
		sprintf(str, STRING(SSPALTSTR), start_x, end_x);
		str[24] = EOS;
		objc_setstring(sort, BSSPALTEN, str);
			
		antw = handle_dial(sort, 0);
		switch (antw)
		{
			case BSKRIT :
				last_cmd = CMD_KRIT;
				set_info(t_ptr, STRING(SKRITSTR));
				make_chg(t_ptr->link, POS_CHANGE, 0);
				break;
			
			case BSORT :
				last_cmd = CMD_SORT;
				break;
			
			case BSABBRUCH :
				clear_sort();
				break;
		}
		undo_state(sort, antw, SELECTED);
		if (last_cmd == CMD_SORT)
		{
			sort_down = get_select(sort, BSDOWN);
			sort_grkl = get_select(sort, BSGRKL);

			do_sort(t_ptr, &r);
			
			/* ursprnglichen Block wieder herstellen und ersetzen */
			t_ptr->z1 = start_z;
			t_ptr->z2 = end_z;
			t_ptr->x1 = 0;
			t_ptr->x2 = 0;
			t_ptr->p1 = p1;
			t_ptr->p2 = p2;
			blk_paste(t_ptr, &r);
			kill_textring(&r);
			clear_sort();
		}
		restore_edit();
	}
	else
		note(1, SORTERR);
}
