
/* Import/Export functions for PAIGE library.  This file contains miscellaneious utility functions
that can be called from both C and C++. */

#include "Paige.h"
#include "defprocs.h"
#include "pgText.h"
#include "pgDefStl.h"
#include "pgSelect.h"
#include "pgTxr.h"
#include "pgEdit.h"
#include "pgEmbed.h"
#include "pgTxtWid.h"
#include "machine.h"


static void copy_style_run (paige_rec_ptr pg, long position, memory_ref source_ref, memory_ref target_ref);
static void merge_text_blocks (paige_rec_ptr pg, text_block_ptr import_blocks,
		long target_pos, long num_import_blocks);
static long find_breaking_char (pg_char_ptr text, long text_size, pg_char cr_char);
static long insert_default_item (memory_ref runref, pg_short_t style_item);
static long find_par_position (pg_import_ptr import_ptr, pg_char cr_char);


/* pgBeginImport sets up a pg_ref to receive very fast importing. Using this method, PAIGE
does not need to go through all the gyrations with style, paragraph and miscellaneious formatting. */

PG_PASCAL (void) pgBeginImport (pg_ref pg, long import_position)
{
	paige_rec_ptr		pg_rec;
	pgm_globals_ptr		mem_globals;
	pg_import_ptr		import_ptr;
	style_run_ptr		run;
	style_info_ptr		style;
	memory_ref			import_ref;
	text_block_ptr		block;
	long				memory_id;

	pg_rec = UseMemory(pg);
	mem_globals = pg_rec->globals->mem_globals;
	memory_id = pg_rec->mem_id;
	
	import_ref = MemoryAllocClearID(mem_globals, sizeof(pg_import_rec), 1, 0, memory_id);
	import_ptr = UseMemory(import_ref);
	import_ptr->previous_import = pg_rec->import_control;
	pg_rec->import_control = import_ref;
	
	import_ptr->target_pos = import_position;
	import_ptr->t_blocks = MemoryAllocClearID(mem_globals, sizeof(text_block), 1, 4, memory_id);
	block = UseMemory(import_ptr->t_blocks);
	pgInitTextblock(pg_rec, 0, MEM_NULL, block, FALSE);
	UnuseMemory(import_ptr->t_blocks);

	import_ptr->t_style_run = MemoryAllocID(mem_globals, sizeof(style_run), 0, 8, memory_id);
	import_ptr->par_style_run = MemoryAllocID(mem_globals, sizeof(style_run), 0, 8, memory_id);

	run = pgFindRunFromRef(pg_rec->t_style_run, import_position, NULL);
	import_ptr->last_style_item = run->style_item;
	UnuseMemory(pg_rec->t_style_run);

	run = pgFindRunFromRef(pg_rec->par_style_run, import_position, NULL);
	import_ptr->last_par_item = run->style_item;
	UnuseMemory(pg_rec->par_style_run);

	style = UseMemoryRecord(pg_rec->t_formats, (long)import_ptr->last_style_item, 0, TRUE);
	import_ptr->last_font_index = style->font_index;
	UnuseMemory(pg_rec->t_formats);

	UnuseMemory(import_ref);
	UnuseMemory(pg);
}


/* pgEndImport terminates the "import mode" set up by calling pgBeginImport() above. */

PG_PASCAL (void) pgEndImport (pg_ref pg, pg_boolean keep_selection, short draw_mode)
{
	paige_rec_ptr		pg_rec;
	pg_import_ptr		import_ptr;
	memory_ref			import_ref;
	text_block_ptr		block, import_block, last_import_block;
	t_select_ptr		selections;
	pg_boolean			result = FALSE;
	long				num_blocks, target_pos;

	pg_rec = UseMemory(pg);

	if ((import_ref = pg_rec->import_control) != MEM_NULL) {
		
		import_ptr = UseMemory(import_ref);
		pg_rec->import_control = import_ptr->previous_import;
		
		num_blocks = GetMemorySize(import_ptr->t_blocks);
		target_pos = import_ptr->target_pos;

		if (result = (pg_boolean)(import_ptr->t_length) != 0) {
			
			import_block = UseMemory(import_ptr->t_blocks);
			
			if (num_blocks > 1) {
				
				last_import_block = &import_block[num_blocks - 1];
				
				if (last_import_block->begin == last_import_block->end) {
					
					DisposeNonNilMemory(last_import_block->text);
					DisposeMemory(last_import_block->lines);
					UnuseMemory(import_ptr->t_blocks);
					
					--num_blocks;
					SetMemorySize(import_ptr->t_blocks, num_blocks);
					import_block = UseMemory(import_ptr->t_blocks);
				}
			}

			if (pg_rec->t_length == 0) {
				// We can just insert everything, empty doc.
				
				block = UseMemory(pg_rec->t_blocks);
				
				if (import_block->text && block->text)
					MemoryCopy(import_block->text, block->text);
				
				block->end = import_block->end - import_block->begin;
				block->flags = NEEDS_CALC;
				UnuseMemory(pg_rec->t_blocks);
				
				if (num_blocks > 1) {
					long			append_qty;
					
					append_qty = num_blocks - 1;

					block = AppendMemory(pg_rec->t_blocks, append_qty, FALSE);
					pgBlockMove(&import_block[1], block, sizeof(text_block) * append_qty);
					UnuseMemory(pg_rec->t_blocks);
				}
			}
			else
				merge_text_blocks(pg_rec, import_block, target_pos, num_blocks);

			UnuseMemory(import_ptr->t_blocks);
			
			// Adjust all the formats and the total text length:
			
			pg_rec->t_length += import_ptr->t_length;
			copy_style_run(pg_rec, target_pos, import_ptr->t_style_run, pg_rec->t_style_run);
			copy_style_run(pg_rec, target_pos, import_ptr->par_style_run, pg_rec->par_style_run);

			SetMemorySize(pg_rec->select, 2);
			selections = UseMemory(pg_rec->select);
			
			if (keep_selection)
				selections->offset = import_ptr->target_pos;
			else
				selections->offset = target_pos + import_ptr->t_length;

			selections[1].offset = selections->offset;

			selections->flags = selections[1].flags = SELECTION_DIRTY;
			UnuseMemory(pg_rec->select);
			
			pg_rec->change_ctr += 1;
		}

	// First text block is never inserted directly (only the other blocks get inserted).
	
		import_block = UseMemory(import_ptr->t_blocks);
		DisposeMemory(import_block->lines);
		DisposeNonNilMemory(import_block->text);
		UnuseAndDispose(import_ptr->t_blocks);

		DisposeMemory(import_ptr->t_style_run);
		DisposeMemory(import_ptr->par_style_run);

		UnuseAndDispose(import_ref);
		
		pgInvalCharLocs(pg_rec);
		
		if (draw_mode)
			pgUpdateText(pg_rec, NULL, 0, pg_rec->t_length, MEM_NULL, NULL, draw_mode, TRUE);
	}

	UnuseMemory(pg);
}


/* pgInsertText is a convenience utility used for importing. It allows a block of text
to be inserted with a specified format and paragraph format applied. */

PG_PASCAL (pg_boolean) pgInsertText (pg_ref pg, pg_char_ptr data, long length,
		font_info_ptr font, style_info_ptr style, par_info_ptr paragraph, short draw_mode)
{
	paige_rec_ptr			pg_rec;
	pg_short_t				style_index;
	pg_boolean				inserted_something = FALSE;
	
	if (!length)
		return	FALSE;

	pg_rec = UseMemory(pg);
	
	if (pg_rec->import_control) {
		pg_import_ptr		import_ptr;
		pg_char_ptr			text, source_text;
		style_info_ptr		style_access;
		par_info_ptr		par_access;
		text_block_ptr		block;
		style_info			added_style;
		style_run_ptr		run;
		pg_boolean			cached_file;
		long				num_blocks, cr_break, threefourths_of_max, par_position;
		long				initial_block_size, source_size, style_position;
		long				inserted_default;

		import_ptr = UseMemory(pg_rec->import_control);
		num_blocks = GetMemorySize(import_ptr->t_blocks);
		block = UseMemoryRecord(import_ptr->t_blocks, num_blocks - 1, USE_ALL_RECS, TRUE);

		threefourths_of_max = pg_rec->globals->max_block_size - (pg_rec->globals->max_block_size / 4);
		initial_block_size = block->end - block->begin;
		source_text = data;
		source_size = length;
		cached_file = (pg_boolean)(pg_rec->cache_file != MEM_NULL);
		
		if (initial_block_size >= threefourths_of_max) {
		
			if (cr_break = find_breaking_char(source_text, source_size, (pg_char)pg_rec->globals->line_wrap_char)) {
				long				end_pos;
				
				if (!cached_file) {
				
					text = AppendMemory(block->text, cr_break, FALSE);
					pgBlockMove(source_text, text, cr_break * sizeof(pg_char));
					UnuseMemory(block->text);
				}

				block->end += cr_break;
				end_pos = block->end;
				block = AppendMemory(import_ptr->t_blocks, 1, TRUE);
				pgInitTextblock(pg_rec, end_pos, MEM_NULL, block, cached_file);				
				source_size -= cr_break;
				source_text += cr_break;
			}
		}

		if (source_size) {
			
			if (!cached_file) {
			
				text = AppendMemory(block->text, source_size, FALSE);
				pgBlockMove(source_text, text, source_size * sizeof(pg_char));
				UnuseMemory(block->text);
			}

			block->end += source_size;
		}

		import_ptr->t_length += length;
		
		UnuseMemory(import_ptr->t_blocks);
	
	// Insert the new formats:
		
		style_index = import_ptr->last_style_item;
		style_position = import_ptr->t_length - length;

		if (font) {
			
			if (style)
				added_style = *style;
			else
				GetMemoryRecord(pg_rec->t_formats, (long)import_ptr->last_style_item, &added_style);
			
			added_style.font_index = pgAddNewFont(pg_rec, font);
			import_ptr->last_font_index = added_style.font_index;
			style_index = pgAddStyleInfo(pg_rec, NULL, for_next_insert_reason, &added_style);
		}
		else
		if (style) {
			
			added_style = *style;
			added_style.font_index = import_ptr->last_font_index;
			style_index = pgAddStyleInfo(pg_rec, NULL, for_next_insert_reason, &added_style);
		}
		
		if (style_index != import_ptr->last_style_item) {
			
			if (style_position > 0)
				inserted_default = insert_default_item(import_ptr->t_style_run, import_ptr->last_style_item);
			else
				inserted_default = 0;

			run = AppendMemory(import_ptr->t_style_run, 1, FALSE);
			run->offset = style_position;
			run->style_item = style_index;
			UnuseMemory(import_ptr->t_style_run);
			
			style_access = UseMemory(pg_rec->t_formats);
			style_access[style_index].used_ctr += 1;
			
			if (inserted_default)
				style_access[inserted_default - 1].used_ctr += 1;

			UnuseMemory(pg_rec->t_formats);
		}

		import_ptr->last_style_item = style_index;

		if (paragraph) {
			
			style_index = pgAddParInfo(pg_rec, NULL, for_next_insert_reason, paragraph);
			
			if (style_index != import_ptr->last_par_item) {
				
				if ((par_position = find_par_position(import_ptr, (pg_char)pg_rec->globals->line_wrap_char)) > 0)
					inserted_default = insert_default_item(import_ptr->par_style_run, import_ptr->last_par_item);
				else
					inserted_default = 0;

				run = AppendMemory(import_ptr->par_style_run, 1, FALSE);
				run->offset = par_position;
				run->style_item = style_index;
				UnuseMemory(import_ptr->par_style_run);

				par_access = UseMemory(pg_rec->par_formats);
				par_access[style_index].used_ctr += 1;
				
				if (inserted_default)
					par_access[inserted_default - 1].used_ctr += 1;

				UnuseMemory(pg_rec->par_formats);
			}

			import_ptr->last_par_item = style_index;
		}

		UnuseMemory(pg_rec->import_control);
	}
	else {
		style_info			style_mask;
		par_info			par_mask;
		font_info			font_mask;
		short				use_draw_mode;

		if (pg_rec->num_selects)
			pgDelete(pg, NULL, draw_none);
		
		pgFillBlock(&style_mask, sizeof(style_info), -1);
		pgFillBlock(&par_mask, sizeof(par_info), -1);
		pgFillBlock(&font_mask, sizeof(font_info), -1);

		if (font) {
			
			if (style)
				pgSetStyleAndFont(pg, NULL, style, &style_mask, font, &font_mask, draw_none);
			else
				pgSetFontInfo(pg, NULL, font, &font_mask, draw_none);
		}
		else
		if (style)
			pgSetStyleInfo(pg, NULL, style, &style_mask, draw_none);
		
		if (paragraph)
			use_draw_mode = draw_none;
		else
			use_draw_mode = draw_mode;

		inserted_something = pgInsert(pg, data, length, CURRENT_POSITION, data_insert_mode, 0, draw_mode);
		
		if (paragraph) {
			select_pair			apply_range;
			
			apply_range.end = pgCurrentInsertion(pg_rec);
			apply_range.begin = apply_range.end - length;
			pgSetParInfo(pg, &apply_range, paragraph, &par_mask, draw_none);
			
			if (draw_mode)
				pgUpdateText(pg_rec, NULL, 0, pg_rec->t_length, MEM_NULL, NULL, draw_mode, TRUE);
		}
	}

	UnuseMemory(pg);
	
	return		inserted_something;
}


// pgInsertEmbed is here for historical reasons but our import-export does not use it.

PG_PASCAL (pg_boolean) pgInsertEmbed (pg_ref pg, embed_ref ref,
		short stylesheet_option, embed_callback callback, long callback_refcon,
		font_info_ptr font, style_info_ptr style, short draw_mode)
{
	paige_rec_ptr			pg_rec;
	style_info_ptr			use_style;
	style_info				stylemask, embed_style;
	font_info				font_mask;
	pg_char					embed_chars[2];
	pg_boolean				result;

	pg_rec = UseMemory(pg);
	
	if (!pg_rec->import_control) {

		style_info	s_mask;
		font_info	f_mask;
		
		pgInitFontMask (&f_mask, SET_MASK_BITS);
		pgInitStyleMask (&s_mask, SET_MASK_BITS);
			
		pgSetStyleAndFont (pg, NULL, style, &s_mask, font, &f_mask, draw_mode);
	
		result = pgInsertEmbedRef (pg, ref, CURRENT_POSITION, stylesheet_option, callback, callback_refcon, draw_mode);
	}
	else {
	
		embed_chars[0] = DUMMY_LEFT_EMBED;
		embed_chars[1] = DUMMY_RIGHT_EMBED;
	    
	    if (style)
	    	use_style = style;
	    else {
	        
	        embed_style = pg_rec->globals->def_style;
	    	use_style = &embed_style;
	    }
	
		pgInitEmbedStyleInfo(pg_rec, 0, ref, stylesheet_option, callback,
					callback_refcon, use_style, &stylemask, font, &font_mask, FALSE);
		 
		result = pgInsertText(pg, embed_chars, 2, font, use_style, NULL, draw_none);
	}

	UnuseMemory(pg);
	
	return	result;
}

/* pgConvertResolution returns the value to use for this machine assuming pointvalue point size. */

PG_PASCAL (short) pgConvertResolution (paige_rec_ptr pg, short pointvalue)
{
	pg_fixed		point_size;
	
	point_size = pointvalue;
	point_size <<= 16;
	point_size = pgPointsizeToScreen(pg->myself, point_size);
	point_size >>= 16;
	
	return	(short)point_size;
}

/* pgResolutionConvert does the reverse of pgConvertResolution. */

PG_PASCAL (short) pgResolutionConvert (paige_rec_ptr pg, short value)
{
	pg_fixed		point_size;
	
	point_size = value;
	point_size <<= 16;
	point_size = pgScreenToPointsize(pg->myself, point_size);
	point_size >>= 16;
	
	return	(short)point_size;
}


/* pgInitTranslatorRec initializes a PAIGE translator record to its defaults. Note, the
translator record is assumed to be initialized to all zeros upon entry. */

PG_PASCAL (void) pgInitTranslatorRec (pg_globals_ptr globals, pg_translator_ptr translator_ptr)
{
	translator_ptr->data = MemoryAllocClear(globals->mem_globals, sizeof(pg_char), TRANSLATOR_BUFFER_SIZE, 0);
	translator_ptr->format = globals->def_style;
	translator_ptr->par_format = globals->def_par;
	translator_ptr->font = globals->def_font;
	translator_ptr->stylesheet_table = MemoryAllocClear(globals->mem_globals, sizeof(style_table), 0, 1);
}


/* pgDisposeTranslatorRec disposes any structures it made when creating the translator */

PG_PASCAL (void) pgDisposeTranslatorRec (pg_translator_ptr translator_ptr)
{
	DisposeNonNilMemory(translator_ptr->data);
	DisposeNonNilMemory(translator_ptr->stylesheet_table);
}


/* pgDetermineFileType returns the file type based on the file's contents.  This function
only determines the predefined, known types.  Upon entry, starting_position is the first
byte in the file. */

PG_PASCAL (pg_filetype) pgDetermineFileType (pg_file_unit fileref, file_io_proc io_proc,
		long starting_position)
{
	file_io_proc			use_io_proc;
	pg_filetype				result = pg_unknown_type;
	
	if ((use_io_proc = io_proc) == NULL)
		use_io_proc = pgOSReadProc;
	
	if (pgVerifyFile((file_ref)fileref, use_io_proc, starting_position) == NO_ERROR)
		result = pg_paige_type;
	else
	if (pgVerifyRTF((pg_file_unit)fileref, use_io_proc, starting_position) == NO_ERROR)
		result = pg_rtf_type;

	return		result;
}


/* pgMapCharacters maps the characters from one OS to another based on character_table. */

PG_PASCAL (void) pgMapCharacters (pg_globals_ptr globals, pg_char_ptr chars, long num_chars, pg_char_ptr character_table)
{
	register pg_char_ptr		table_ptr;
	register long				byte_qty;

	table_ptr = chars;
	
	for (byte_qty = 0; byte_qty < num_chars; ++byte_qty, ++table_ptr) {
	
	#ifdef UNICODE
		
		if (*table_ptr < 0x100)
	#endif
		if (*table_ptr >= HIGH_CHARS_BASE) {
			
			if ((*table_ptr = character_table[(*table_ptr - HIGH_CHARS_BASE)]) == N_A)
				*table_ptr = globals->unknown_char[0];
		}
	}
}


/* pgGetCacheFileRef returns the cached file reference, if any. */

PG_PASCAL (file_ref) pgGetCacheFileRef (pg_ref pg)
{
	paige_rec_ptr		pg_rec;
	file_ref			result = MEM_NULL;

	pg_rec = UseMemory(pg);
	result = pg_rec->cache_file;
	UnuseMemory(pg);

	return		result;
}


/* pgCompareFontTable compares the two font names. The table_font contains a font name equiv. following
the "[" char. The initial table name can have a "*" wild card at the end. If a match is made,
the byte count to the first char after "[" is returned. */

PG_PASCAL (short) pgCompareFontTable (pg_char_ptr source_font, pg_char_ptr table_font)
{
	register pg_char_ptr		source_ptr, table_ptr;
	register short				byte_ctr;

	source_ptr = source_font;
	table_ptr = table_font;
	byte_ctr = 0;
	
	for (;;) {
		
		if (*source_ptr++ != *table_ptr++)
			return	0;
		
		++byte_ctr;
		
		if (*table_ptr == '*' || (*table_ptr == '[' && *source_ptr == 0))
			break;
	}
	
	for (;;) {
		
		++byte_ctr;
		
		if (*table_ptr++ == '[')
			break;
	}
	
	return		byte_ctr;
}


/* pgVerifyRTF walks through the given file and verifies if it is an RTF file. */

PG_PASCAL (pg_boolean) pgVerifyRTF (pg_file_unit fileref, file_io_proc io_proc,
		long starting_position)
{
	file_io_proc			use_io_proc;
	long					position, datasize;
	pg_bits8				verify_buffer[5];
	pg_boolean				result = BAD_TYPE_ERR;

	datasize = 6;
	pgFillBlock(verify_buffer, datasize, 0);
	
	if ((use_io_proc = io_proc) == NULL)
		use_io_proc = pgOSReadProc;
	
	position = starting_position;
	
	if ((use_io_proc((void PG_FAR *)verify_buffer, io_data_direct, &position, &datasize, (file_ref)fileref)) == NO_ERROR) {
		
		if (verify_buffer[0] == RTF_GROUPBEGIN_CHAR)
			if (verify_buffer[1] == RTF_COMMAND_CHAR)
				if (verify_buffer[2] == 'r' && verify_buffer[3] == 't' && verify_buffer[4] == 'f')
					result = NO_ERROR;
	}

	position = starting_position;
	use_io_proc((void PG_FAR *)NULL, io_set_fpos, &position, NULL, (file_ref)fileref);
	
	return		result;
}



/************************************** Local Functions *********************************/


/* copy_style_run inserts a style_run into source_ref and adjusts all the offsets. */

static void copy_style_run (paige_rec_ptr pg, long position, memory_ref source_ref, memory_ref target_ref)
{
	style_run_ptr			run, source_run;
	style_run				first_target_run;
	long					rec_num, num_source_runs;
	
	if ((num_source_runs = GetMemorySize(source_ref)) > 0) {
		
		source_run = UseMemory(source_ref);
		run = pgFindRunFromRef(target_ref, position, &rec_num);
		first_target_run = *run;
		UnuseMemory(target_ref);
		
		if (first_target_run.offset == position)
			DeleteMemory(target_ref, rec_num, 1);
		else
			rec_num += 1;
		
		run = InsertMemory(target_ref, rec_num, num_source_runs);
		
		while (num_source_runs) {
			
			*run = *source_run;
			run->offset += position;
			
			++run;
			++source_run;
			--num_source_runs;
		}

		UnuseMemory(target_ref);
		UnuseMemory(source_ref);
	}

	run = UseMemoryRecord(target_ref, GetMemorySize(target_ref) - 1, 0, TRUE);
	run->offset = pg->t_length + ZERO_TEXT_PAD;
	UnuseMemory(target_ref);
}


/* merge_text_blocks merges import_blocks into the text blocks of pg. */

static void merge_text_blocks (paige_rec_ptr pg, text_block_ptr import_blocks,
		long target_pos, long num_import_blocks)
{
	text_block_ptr			block, last_block;
	pg_char_ptr				text, source_text;
	pg_short_t				block_num, last_block_num, end_char;
	long					num_blocks, local_position, first_block_size;
	long					end_block_size, end_pos;

	block = pgFindTextBlock(pg, target_pos, &block_num, FALSE, TRUE);
	local_position = target_pos - block->begin;
	first_block_size = import_blocks->end - import_blocks->begin;

	if (num_import_blocks > 1) {
		// Adjust beginning and ending text so we can just append
		
		source_text = UseMemory(block->text);

		if (local_position > 0) {
			
			text = InsertMemory(import_blocks->text, 0, local_position);
			pgBlockMove(source_text, text, local_position * sizeof(pg_char));
			UnuseMemory(import_blocks->text);
			
			import_blocks->end = import_blocks->begin + GetMemorySize(import_blocks->text);
		}
		
		if ((end_block_size = block->end - target_pos) > 0) {
			
			last_block = &import_blocks[num_import_blocks - 1];
			text = AppendMemory(last_block->text, end_block_size, FALSE);
			pgBlockMove(&source_text[local_position], text, end_block_size * sizeof(pg_char));
			UnuseMemory(last_block->text);
			
			last_block->end = last_block->begin + GetMemorySize(last_block->text);
		}

		UnuseMemory(block->text);
		
		first_block_size = import_blocks->end - import_blocks->begin;
		import_blocks->begin = block->begin;
		import_blocks->end = block->begin + first_block_size;

		DisposeNonNilMemory(block->text);
		DisposeMemory(block->lines);
		UnuseMemory(pg->t_blocks);
		DeleteMemory(pg->t_blocks, 0, 1);
		
		block = InsertMemory(pg->t_blocks, 0, num_import_blocks);
		pgBlockMove(import_blocks, block, num_import_blocks * sizeof(text_block));
		
	// See if ending block terminates on a CR or not:
		
		num_blocks = GetMemorySize(pg->t_blocks);
		last_block_num = (pg_short_t)((long)block_num + num_import_blocks);
		
		if (last_block_num < (pg_short_t)num_blocks) {
		
			last_block = UseMemoryRecord(pg->t_blocks, last_block_num - 1, 0, FALSE);
			source_text = UseMemory(last_block->text);
			end_char = (pg_short_t)source_text[last_block->end - last_block->begin - 1];
			
			if (end_char != pg->globals->line_wrap_char) {
				long			text_size;
				
				text_size = GetMemorySize(last_block->text);
				text = InsertMemory(last_block[1].text, 0, text_size);
				pgBlockMove(source_text, text, text_size * sizeof(pg_char));
				last_block[1].end += text_size;
				last_block[1].flags |= NEEDS_CALC;
				UnuseMemory(last_block[1].text);
				
				DisposeNonNilMemory(last_block->text);
				DisposeMemory(last_block->lines);
				
				UnuseMemory(pg->t_blocks);
				DeleteMemory(pg->t_blocks, last_block_num - 1, 1);
				
				block = UseMemory(pg->t_blocks);
			}
		}
	}
	else {
		
		text = InsertMemory(block->text, local_position, first_block_size);
		pgBlockMove(UseMemory(import_blocks->text), text, first_block_size * sizeof(pg_char));
		UnuseMemory(import_blocks->text);
		UnuseMemory(block->text);

		block->flags = NEEDS_CALC;
		block->end += first_block_size;
	}
	
	block = UseMemoryRecord(pg->t_blocks, (long)block_num, 0, FALSE);
	
	num_blocks = GetMemorySize(pg->t_blocks) - (long)block_num;
	end_pos = block->begin;

	while (num_blocks) {
		
		block->end = (block->end - block->begin) + end_pos;
		block->begin = end_pos;
		end_pos = block->end;
		block->flags |= NEEDS_PAGINATE;

		++block;
		--num_blocks;
	}

	UnuseMemory(pg->t_blocks);
}


/* find_breaking_char returns the first text_block breaking char that it finds. If one is found
then its position + 1 is returned. */

static long find_breaking_char (pg_char_ptr text, long text_size, pg_char cr_char)
{
	register pg_char_ptr		text_ptr;
	register long				ctr;
	
	text_ptr = text;
	
	for (ctr = 1; ctr <= text_size; ++ctr)
		if (*text_ptr++ == cr_char)
			return	ctr;
	
	return		0;
}


/* find_par_position locates the text position for the current paragraph. This only gets
called after a new insertion so the ending byte is the current end-of-doc. */

static long find_par_position (pg_import_ptr import_ptr, pg_char cr_char)
{
	text_block_ptr			block;
	register pg_char_ptr	text;
	long					text_size, position;

	block = UseMemoryRecord(import_ptr->t_blocks, GetMemorySize(import_ptr->t_blocks) - 1, 0, TRUE);
	
	if ((text_size = GetMemorySize(block->text)) > 0) {
	
		text = UseMemory(block->text);
		text_size -= 1;
		text += text_size;

		while (text_size) {
			
			--text;
			
			if (*text == cr_char)
				break;
			
			--text_size;
		}

		UnuseMemory(block->text);
	}

	position = block->begin + text_size;
	UnuseMemory(import_ptr->t_blocks);
	
	return		position;
}

/* insert_default_item inserts the default beginning record if there are no records so far. 
If something is done,  the style_item + 1 is returned. */

static long insert_default_item (memory_ref runref, pg_short_t style_item)
{
	style_run_ptr			run;
	long					result = 0;

	if (GetMemorySize(runref) == 0) {
		
		run = AppendMemory(runref, 1, TRUE);
		run->style_item = style_item;
		result = (long)style_item;
		++result;
		UnuseMemory(runref);
	}
	
	return	result;
}
