/* 
	Paige Header/Footer Implementation file
	
	File:		pgHdrFtr.c

	by T. R. Shaw <tshaw@oitc.com>

	Copyright © 1994-1995 OITC, Inc.
	All rights reserved.
	
	pgHdrFtr.c - Header/footer routines for translation of RTF files to Paige.

	This software has been privately developed and falls within 
	DFARS 252.227-7013(c)(1) and associated regulations and it or its
	derivatives may not be used outside of the License agreement with 
	T. R. Shaw and OITC.  Copyright may not be removed.
	
	info@oitc.com
	http://www.oitc.com/

	Revision History
	07/03/95	1.0b1	TRS - Initial beta for external customer Paige release
*/

#include "pgHdrFtr.h"
#include "pgUtils.h"
#include "pgExceps.h"
#include "pgEmbed.h"
#include "machine.h"


/* creates the the specified header or footer.  If there is already an entry, it returns 
	the previous entry or MEM_NULL. You must dispose of the returned entry. To remove 
	an entry, just call pgSetHeaderFooter with new_ref = MEM_NULL. */
	
PG_PASCAL (pg_ref) pgNewHeaderFooter(pg_ref pg, long section_type)
{
	paige_rec_ptr	pg_rec;
	rectangle		page_bounds;
	rectangle		vis_bounds;
	pg_ref			result;
	short 			i;
	
	result = pgDuplicate (pg);
	pgSetAttributes(pg, pgGetAttributes(pg) & ~COUNT_LINES_BIT);
	
	//Adjust bounds for header/footer
	pgAreaBounds (result, &page_bounds, &vis_bounds);
	page_bounds.bot_right.v = vis_bounds.top_left.v + DEFAULT_HDR_FTR_SIZE;
	pgSetAreaBounds (result, &page_bounds, &vis_bounds);

	pg_rec = UseMemory(result);
	pg_rec->doc_pg = pg;
	pg_rec->pg_type = section_type;
	
	for (i = 0; i < 4; i++)
	{
		pg_rec->headers[i] = pg_rec->footers[i] = MEM_NULL;
	}
	
	pg_rec->hdr_ftr_loc[0] = pg_rec->hdr_ftr_loc[1] = 0;
	
	UnuseMemory(result);

	return pgSetHeaderFooter(pg, section_type, result);
}


/* Returns the header or footer.  If resolve is set, we return any appropriate header using
	the following approach: If a left or right is not available, try to return the main. If
	main is not available and we are in a subdocument, try again */
	
PG_PASCAL (pg_ref) pgGetHeaderFooter(pg_ref pg, long section_type, pg_boolean resolve)
{
	paige_rec_ptr	pg_rec;
	pg_ref			ref = MEM_NULL;

	pg_rec = UseMemory(pg);
	
	if ((section_type & SPCL_SECTION_MASK) == MAIN_HEADER)
	{
		//Its a header
		ref = pg_rec->headers[section_type & 0x3];
		if (!ref && resolve)
		{
			//Find a alternate header
			if (!(ref = pg_rec->headers[0]) && pg_rec->pg_type != MAIN_DOCUMENT)
				ref = pgGetHeaderFooter(pg_rec->doc_pg, section_type, resolve);
		}
	}
	else
	{
		//Its a footer
		ref = pg_rec->footers[section_type & 0x3];
		if (!ref && resolve)
		{
			//Find a alternate footer
			if (!(ref = pg_rec->footers[0]) && pg_rec->pg_type != MAIN_DOCUMENT)
				ref = pgGetHeaderFooter(pg_rec->doc_pg, section_type, resolve);
		}
	}
	
	UnuseMemory(pg);
	
	return ref;
}


/* Returns the header or footer location.  If there is no ref -1 is returned */
	
PG_PASCAL (pg_fixed) pgGetHeaderFooterLoc(pg_ref pg, long section_type)
{
	paige_rec_ptr	pg_rec;
	pg_fixed		result = -1;

	pg_rec = UseMemory(pg);
	
	if ((section_type & SPCL_SECTION_MASK) == MAIN_HEADER)
	{
		//Its a header
		if (pg_rec->headers[0] || pg_rec->headers[1] || pg_rec->headers[2] || pg_rec->headers[3])
			result = pg_rec->hdr_ftr_loc[0];
	}
	else
	{
		//Its a footer
		if (pg_rec->footers[0] || pg_rec->footers[1] || pg_rec->footers[2] || pg_rec->footers[3])
			result = pg_rec->hdr_ftr_loc[1];
	}
	
	UnuseMemory(pg);
	
	return result;
}


/* Sets the the specified header or footer.  If there is already an entry, it returns 
	the previous entry or MEM_NULL. You must dispose of the returned entry. To remove 
	an entry, just call pgSetHeaderFooter with new_ref = MEM_NULL. */
	
PG_PASCAL (pg_ref) pgSetHeaderFooter(pg_ref pg, long section_type, pg_ref new_ref)
{
	paige_rec_ptr	pg_rec;
	pg_ref			result = MEM_NULL;

	pg_rec = UseMemory(pg);
	
	if ((section_type & SPCL_SECTION_MASK) == MAIN_HEADER)
	{
		//Its a header
		result = pg_rec->headers[section_type & 0x3];
		pg_rec->headers[section_type & 0x3] = new_ref;
	}
	else
	{
		//Its a footer
		result = pg_rec->footers[section_type & 0x3];
		pg_rec->footers[section_type & 0x3] = new_ref;
	}
	
	UnuseMemory(pg);

	//Just to be sure
	pg_rec = UseMemory(new_ref);
	pg_rec->doc_pg = pg;
	pg_rec->pg_type = section_type;
	UnuseMemory(new_ref);
	
	return result;
}


/* Sets the header or footer location.  If there is no ref -1 is returned */
	
PG_PASCAL (void) pgSetHeaderFooterLoc(pg_ref pg, long section_type, pg_fixed loc)
{
	paige_rec_ptr	pg_rec;
	pg_fixed		result = -1;

	pg_rec = UseMemory(pg);
	
	if ((section_type & SPCL_SECTION_MASK) == MAIN_HEADER)
	{
		//Its a header
		pg_rec->hdr_ftr_loc[0] = loc;
	}
	else
	{
		//Its a footer
		pg_rec->hdr_ftr_loc[1] = loc;
	}
	
	UnuseMemory(pg);
}


/* pgNumAugmentedPages returns the number of pages based upon pg_doc_info and headers and footers.  */

PG_PASCAL (short) pgNumAugmentedPages (pg_ref pg)
{
	paige_rec_ptr	pg_rec;
	
	pg_rec = UseMemory(pg);
	
	//„„pg_rec->
	
	UnuseMemory(pg);
	
	return 0;
}


/* pgPageModify is the default modify-page function. This gets called for each repeating page.
This default function does not do anything. */

PG_PASCAL (void) pgPageModifyHdrFtr(paige_rec_ptr pg, long page_num, rectangle_ptr margins)
{
	long		section_type_h;
	long		section_type_f;
	long		gutter_top;
	long		gutter_left;
	long		gutter_bottom;
	long		gutter_right;
	long		line_adjust;
	pg_fixed	loc;
	pg_ref		ref;
	short		page_modulo;

	if (pg->flags2 & HAS_TITLE_PAGE)
	{
		if (page_num == 0)
			return;
		if (page_num == 1 && (pg->flags2 & PAGE_AFTER_TITLE))
			return;
	}
	
	gutter_top = gutter_left = gutter_bottom = gutter_right = line_adjust = 0;
	
	if (pg->flags & COUNT_LINES_BIT) 
	{
		line_adjust = pgHiWord(pgRoundFixed(pg->doc_info.line_num_loc));
	}
	
	page_modulo = page_num & 1;
	page_modulo = (page_modulo + (pg->flags2 >> 3) + 1);
	
	section_type_h = MAIN_HEADER + page_modulo;
	section_type_f = MAIN_FOOTER + page_modulo;

	if (pg->flags2 & (RIGHT_EVEN_PAGES | LEFT_EVEN_PAGES))
	{
		section_type_h = MAIN_HEADER + page_modulo;
		section_type_f = MAIN_FOOTER + page_modulo;
		
		if (page_modulo == 1)
			gutter_left = pgHiWord(pgRoundFixed(pg->doc_info.gutter)) + line_adjust;
		else gutter_right = pgHiWord(pgRoundFixed(pg->doc_info.gutter)) + line_adjust;
		
	}
	else
	{
		page_modulo = 0;
	}
		
	section_type_h = MAIN_HEADER + page_modulo;
	section_type_f = MAIN_FOOTER + page_modulo;

	if (ref = pgGetHeaderFooter(pg->myself, section_type_h, TRUE))
	{
		//Got a header
		if ((loc = pgGetHeaderFooterLoc(pg->myself, section_type_h)) != -1)
		{
			rectangle	page_bounds;
			rectangle	vis_bounds;
		
			gutter_top = pgHiWord(pgRoundFixed(loc));
			
			//Adjust top for size
			pgAreaBounds (pg->myself, &page_bounds, &vis_bounds);
			gutter_top += vis_bounds.bot_right.v - margins->top_left.v;
			
		}
	}
	if (ref = pgGetHeaderFooter(pg->myself, section_type_f, TRUE))
	{
		//Got a header
		if ((loc = pgGetHeaderFooterLoc(pg->myself, section_type_f)) != -1)
		{
			gutter_bottom = pgHiWord(pgRoundFixed(loc));
		}
	}
	
	//Increment margins in casewe are called in an override chain
	margins->top_left.v += gutter_top;
	margins->top_left.h += gutter_left;
	margins->bot_right.v += gutter_bottom;
	margins->bot_right.h += gutter_right;
}


// Save a headers and footers in the document

PG_PASCAL (pg_error) pgSaveHdrFtr (pg_ref pg, long PG_FAR *file_position, const pg_file_key_ptr keys,
		pg_short_t num_keys, file_io_proc write_proc, file_io_proc write_data_proc, 
		file_ref filemap, long doc_element_info)
{
	paige_rec_ptr	pg_rec;
	pg_error		err = MEM_NULL;
	
	pg_rec = UseMemory(pg);
	
	PG_TRY (pg_rec->globals->mem_globals) 
	{
		short	i;
		
		PG_FAIL_ERROR(pgTerminateFile (pg, file_position, write_proc, filemap));
		
		for (i = 0; i < 4; i++)
		{
			PG_FAIL_ERROR(pgTerminateFile (pg, file_position, write_proc, filemap));
			if (pg_rec->headers[i])
			{
				PG_FAIL_ERROR(pgSaveDoc(pg_rec->headers[i], file_position, keys, num_keys, write_proc, filemap, doc_element_info));
				PG_FAIL_ERROR(pgSaveAllEmbedRefs(pg_rec->headers[i], write_proc, write_data_proc, file_position, filemap));
			}
			
			PG_FAIL_ERROR(pgTerminateFile (pg, file_position, write_proc, filemap));
			if (pg_rec->footers[i])
			{
				PG_FAIL_ERROR(pgSaveDoc(pg_rec->footers[i], file_position, keys, num_keys, write_proc, filemap, doc_element_info));
				PG_FAIL_ERROR(pgSaveAllEmbedRefs(pg_rec->footers[i], write_proc, write_data_proc, file_position, filemap));
			}
		}
	}
	PG_CATCH
	{
		err = PG_GET_ERROR();
	}
	PG_ENDTRY
	
	UnuseMemory(pg);
	
	return err;
}


// Read a headers and footers in the document

PG_PASCAL (pg_error) pgReadHdrFtr (pg_ref pg, long PG_FAR *file_position, const pg_file_key_ptr keys,
		pg_short_t num_keys, file_io_proc read_proc, file_ref filemap)
{	
	paige_rec_ptr	pg_rec;
	pg_error		err = MEM_NULL;
	
	pg_rec = UseMemory(pg);
	
	PG_TRY (pg_rec->globals->mem_globals) 
	{
		short	i;
		
		for (i = 0; i < 4; i++)
		{
			PG_FAIL_NIL(pg_rec->headers[i] = pgNewHeaderFooter(pg, i | MAIN_HEADER));
			PG_FAIL_ERROR(pgReadDoc (pg_rec->headers[i], file_position, keys, num_keys, read_proc, filemap));
			if (!pgTextSize(pg_rec->headers[i]))
			{
				pgDispose(pg_rec->headers[i]);
				pg_rec->headers[i] = MEM_NULL;
			}

			PG_FAIL_NIL(pg_rec->footers[i] = pgNewHeaderFooter(pg, i | MAIN_FOOTER));
			PG_FAIL_ERROR(pgReadDoc (pg_rec->footers[i], file_position, keys, num_keys, read_proc, filemap));
			if (!pgTextSize(pg_rec->footers[i]))
			{
				pgDispose(pg_rec->footers[i]);
				pg_rec->footers[i] = MEM_NULL;
			}
		}
	}
	PG_CATCH
	{
		err = PG_GET_ERROR();
	}
	PG_ENDTRY
	
	UnuseMemory(pg);
	
	return err;
}

