/* $Revision Header *** Header built automatically - do not edit! ***********
 *
 *	(C) Copyright 1991 by Torsten Jürgeleit
 *
 *	Name .....: load.c
 *	Created ..: Sunday 22-Dec-91 21:22:44
 *	Revision .: 1
 *
 *	Date        Author                 Comment
 *	=========   ====================   ====================
 *	31-Dec-91   Torsten Jürgeleit      new font management
 *	22-Dec-91   Torsten Jürgeleit      Created this file!
 *
 ****************************************************************************
 *
 *	Load template files
 *
 * $Revision Header ********************************************************/

	/* Includes */

#include "includes.h"
#include "defines.h"
#include "imports.h"
#include "protos.h"

	/* Defines */

#define LOAD_FILE_READ_BUFFER_SIZE	2000
#define LOAD_FILE_LINE_BUFFER_SIZE	80
#define LOAD_FILE_FLAGS			(TEXT_FILE_FLAG_TRIM_LINE | TEXT_FILE_FLAG_SKIP_COMMENTS | TEXT_FILE_FLAG_SKIP_EMPTY_LINES | TEXT_FILE_FLAG_LINE_CONTINUATION)

#define BLOCK_TYPE_NONE		0
#define BLOCK_TYPE_HEADER	1
#define BLOCK_TYPE_FONT		2
#define BLOCK_TYPE_TEMPLATE	3
#define BLOCK_TYPE_BOX		4
#define BLOCK_TYPE_TEXTLIST	5
#define BLOCK_TYPE_BORDERDATA	6
#define BLOCK_TYPE_TEXTDATA	7
#define BLOCK_TYPE_GADGETDATA	8

#define HEADER_ITEM_TYPE_LEFTEDGE	1
#define HEADER_ITEM_TYPE_TOPEDGE	2
#define HEADER_ITEM_TYPE_WIDTH		3
#define HEADER_ITEM_TYPE_HEIGHT		4
#define HEADER_ITEM_TYPE_FLAGS		5
#define HEADER_ITEM_TYPE_ID		6

#define FONT_ITEM_TYPE_NAME		1
#define FONT_ITEM_TYPE_YSIZE		2

#define TEMPLATE_ITEM_TYPE_NAME		1
#define TEMPLATE_ITEM_TYPE_TYPE		2
#define TEMPLATE_ITEM_TYPE_FLAGS	3

#define BOX_ITEM_TYPE_X1		1
#define BOX_ITEM_TYPE_Y1		2
#define BOX_ITEM_TYPE_X2		3
#define BOX_ITEM_TYPE_Y2		4

#define TEXTLIST_ITEM_TYPE_TEXT		1

#define BORDERDATA_ITEM_TYPE_TYPE	1

#define TEXTDATA_ITEM_TYPE_TYPE		1
#define TEXTDATA_ITEM_TYPE_FLAGS	2
#define TEXTDATA_ITEM_TYPE_TEXT		3
#define TEXTDATA_ITEM_TYPE_TEXTATTR	4

#define GADGETDATA_ITEM_TYPE_TYPE	1
#define GADGETDATA_ITEM_TYPE_FLAGS	2
#define GADGETDATA_ITEM_TYPE_TEXT	3
#define GADGETDATA_ITEM_TYPE_TEXTATTR	4
#define GADGETDATA_ITEM_TYPE_SPECIAL1	5
#define GADGETDATA_ITEM_TYPE_SPECIAL2	6
#define GADGETDATA_ITEM_TYPE_SPECIAL3	7

	/* Statics */

STATIC struct TemplateList  new_template_list;
STATIC struct TemplateFont  *new_font;
STATIC struct Template      *new_template;

STATIC BYTE *block_keywords[] = {
	"PROJECTHEADER",
	"FONT",
	"TEMPLATE",
	"BOX",
	"TEXTLIST",
	"BORDERDATA",
	"TEXTDATA",
	"GADGETDATA",
	NULL
};
STATIC BYTE *header_keywords[] = {
	"LEFTEDGE",
	"TOPEDGE",
	"WIDTH",
	"HEIGHT",
	"FLAGS",
	"ID",
	NULL
};
STATIC BYTE *font_keywords[] = {
	"NAME",
	"YSIZE",
	NULL
};
STATIC BYTE *template_keywords[] = {
	"NAME",
	"TYPE",
	"FLAGS",
	NULL
};
STATIC BYTE *box_keywords[] = {
	"X1",
	"Y1",
	"X2",
	"Y2",
	NULL
};
STATIC BYTE *textlist_keywords[] = {
	"TEXT",
	NULL
};
STATIC BYTE *borderdata_keywords[] = {
	"TYPE",
	NULL
};
STATIC BYTE *textdata_keywords[] = {
	"TYPE",
	"FLAGS",
	"TEXT",
	"TEXTATTR",
	NULL
};
STATIC BYTE *gadgetdata_keywords[] = {
	"TYPE",
	"FLAGS",
	"TEXT",
	"TEXTATTR",
	"SPECIAL1",
	"SPECIAL2",
	"SPECIAL3",
	NULL
};
	/* Load project */

   SHORT
load_project(USHORT mode)
{
   struct FileRequester  *freq = project_file_requester;
   SHORT status = EDITOR_STATUS_NORMAL;

   /* Display ARP file requester and check if user selected cancel */
   IChangeMousePointer(ewin, NULL);
   freq->fr_FuncFlags &= ~FRF_DoColor;
   if (mode == LOAD_MODE_NORMAL) {
      freq->fr_Hail = PROJECT_LOAD_HAIL_TEXT;
   } else {
      freq->fr_Hail = PROJECT_APPEND_HAIL_TEXT;
   }
   if (FileRequest(freq)) {
      struct TemplateList  *new_tl = &new_template_list;
      struct FileData      *fd;
      BYTE  path[LONG_DSIZE + LONG_FSIZE + 1];
      SHORT len = strlen(freq->fr_File) - 4;

      /* Prepare file name and project name */
      if (len < 1 || Strcmp(freq->fr_File + len, ".tpl")) {
	 strcat(freq->fr_File, ".tpl");
	 len += 4;
      }

      /* Build full path for project file */
      strcpy(&path[0], freq->fr_Dir);
      TackOn(&path[0], freq->fr_File);

      /* Open file */
      if (!(fd = IOpenTextFile(&path[0], LOAD_FILE_READ_BUFFER_SIZE,
			    LOAD_FILE_LINE_BUFFER_SIZE, LOAD_FILE_FLAGS))) {
	 status = EDITOR_ERROR_OPEN_FAILED;
      } else {

	 /* Init new template list */
	 NewList((struct List *)&new_tl->tl_Fonts);
	 NewList((struct List *)&new_tl->tl_Templates);
	 new_tl->tl_BorderTemplates = 0;
	 new_tl->tl_TextTemplates   = 0;
	 new_tl->tl_GadgetTemplates = 0;
	 new_tl->tl_Flags           = DEFAULT_TEMPLATE_LIST_FLAGS;

	 /* Read all templates */
	 while ((status = parse_block(fd, new_tl, BLOCK_TYPE_NONE,
					    mode)) == EDITOR_STATUS_NORMAL);
	 /* Install and display new template list */
	 if (status == EDITOR_STATUS_EOF) {
	    struct TemplateList  *tl = &template_list;
	    struct TemplateFont  *tf;
	    struct Template      *tp;
	    struct List          *list;

	    /* First set normal status */
	    status = EDITOR_STATUS_NORMAL;

	    /* Remove unused template fonts from new template list */
	    tf = get_head((struct List *)&new_tl->tl_Fonts);
	    while (tf) {
	       struct TemplateFont  *next_tf = get_succ((struct Node *)
							   &tf->tf_MinNode);
	       if (!tf->tf_UseCount) {
		  Remove((struct Node *)&tf->tf_MinNode);
		  free_template_font(tf);
	       }
	       tf = next_tf;
	    }
	    if (mode == LOAD_MODE_NORMAL) {

	       /* Overwrite old template list */
	       if ((status = new_project(tl, new_tl->tl_Flags)) ==
						     EDITOR_STATUS_NORMAL) {
		  /* Copy template fonts from new to original template list */
		  list = (struct List *)&new_tl->tl_Fonts;
		  while (tf = (struct TemplateFont *)RemHead(list)) {
		     AddTail((struct List *)&tl->tl_Fonts,
					    (struct Node *)&tf->tf_MinNode);
		  }

		  /* Copy templates from new to original template list */
		  list = (struct List *)&new_tl->tl_Templates;
		  while (tp = (struct Template *)RemHead(list)) {
		     add_template_to_list(tl, tp, FALSE);
		     display_template(tp);
		  }

		  /* Copy template list data */
		  tl->tl_Flags = new_tl->tl_Flags &
						~TEMPLATE_LIST_FLAG_CHANGED;
		  strcpy(&tl->tl_ProjectID[0], &new_tl->tl_ProjectID[0]);
		  change_project_name(tl, freq->fr_File, len);
	       }
	    } else {

	       /* Append new template list to old one */
	       list = (struct List *)&new_tl->tl_Templates;
	       while (tp = (struct Template *)RemHead(list)) {
		  struct TextAttr  *old_ta, *new_ta;

		  /* Open template font in original template list and close it in new one */
		  switch (TEMPLATE_GROUP(tp)) {
		     case TEMPLATE_GROUP_TEXT :
			old_ta = tp->tp_Data.tp_TextData.td_TextAttr;
			if (!(new_ta = open_template_font_by_attributes(tl,
			      (BYTE *)old_ta->ta_Name, old_ta->ta_YSize))) {
			   status = EDITOR_ERROR_INVALID_FONT;
			} else {
			   tp->tp_Data.tp_TextData.td_TextAttr = new_ta;
			   close_template_font(new_tl, old_ta);
			}
			break;

		     case TEMPLATE_GROUP_GADGET :
			old_ta = tp->tp_Data.tp_GadgetData.gd_TextAttr;
			if (!(new_ta = open_template_font_by_attributes(tl,
			      (BYTE *)old_ta->ta_Name, old_ta->ta_YSize))) {
			   status = EDITOR_ERROR_INVALID_FONT;
			} else {
			   tp->tp_Data.tp_GadgetData.gd_TextAttr = new_ta;
			   close_template_font(new_tl, old_ta);
			}
			break;
		  }

		  if (status != EDITOR_STATUS_NORMAL) {
		     free_template(new_tl, tp);
		  } else {

		     /* Add template to original template list */
		     if (tp->tp_Flags & TEMPLATE_FLAG_DEFAULT_NAME) {
			add_template_to_list(tl, tp, TRUE);
		     } else {
			add_template_to_list(tl, tp, FALSE);
		     }
		     display_template(tp);
		     tl->tl_Flags |= TEMPLATE_LIST_FLAG_CHANGED;
		  }
       	       }
	    }
	    if (status == EDITOR_STATUS_NORMAL) {
	       ISetGadgetAttributes(egl, EDITOR_GADGET_TEMPLATES, 0L,
		   USE_CURRENT_VALUE, USE_CURRENT_VALUE, &tl->tl_Templates);
	    }
	 }
	 ICloseTextFile(fd);

	 /* If error then free incomplete loaded template list */
	 if (status != EDITOR_STATUS_NORMAL) {
	    free_template_list(new_tl);
	 }
      }
   }
   IRestoreMousePointer(ewin);
   if (status != EDITOR_STATUS_NORMAL) {
      show_error(status);
   }
   return(status);
}
	/* Parse block of load file */

   STATIC SHORT
parse_block(struct FileData  *fd, struct TemplateList  *tl,
					     USHORT block_type, USHORT mode)
{
   SHORT status = EDITOR_STATUS_NORMAL;

   if (block_type == BLOCK_TYPE_FONT) {
      struct TemplateFont  *tf;

      if (!(tf = new_font = AllocMem((LONG)sizeof(struct TemplateFont),
					 (LONG)MEMF_PUBLIC | MEMF_CLEAR))) {
	 status = EDITOR_ERROR_OUT_OF_MEM;
      } else {
	 struct TextAttr  *ta = &tf->tf_TextAttr;

	 /* Init new template font */
	 ta->ta_Style    = FS_NORMAL;
	 ta->ta_Flags    = FPF_ROMFONT;
	 tf->tf_UseCount = 0;
      }
   } else {
      if (block_type == BLOCK_TYPE_TEMPLATE) {
	 struct Template  *tp;

	 if (!(tp = new_template = AllocMem((LONG)sizeof(struct Template),
					 (LONG)MEMF_PUBLIC | MEMF_CLEAR))) {
	    status = EDITOR_ERROR_OUT_OF_MEM;
	 } else {

	    /* Init new template */
	    NewList(&tp->tp_TextList);
	    tp->tp_Node.ln_Name = &tp->tp_TemplateName[0];
	 }
      }
   }
   if (status == EDITOR_STATUS_NORMAL) {

      /* Block loop */
      do {
	 BYTE c, *keyword, *arg;

	 switch (IReadTextLine(fd)) {
	    case TEXT_FILE_STATUS_NORMAL :

	       /* Mark end of keyword */
	       keyword = arg = fd->fd_Line;
	       while ((c = *arg++) != ' ' && c != '=' && c != '\0');
	       if (c == '\0') {
		  status = EDITOR_ERROR_NO_ARGUMENT;
	       } else {
		  *(arg - 1) = '\0';

		  /* Strip double quotes from string argument */
		  if (*arg == '"') {
		     arg++;
		     *(arg + (strlen(arg) - 1)) = '\0';
		  }

	          /* Check keyword */
	          if (!Strcmp(keyword, "BEGIN")) {

		     /* Begin new block */
		     status = parse_block(fd, tl, search_keyword(arg,
						 &block_keywords[0]), mode);
		  } else {
		     if (!Strcmp(keyword, "END")) {

			/* End current block */
			if (search_keyword(arg, &block_keywords[0]) !=
							       block_type) {
			   status = EDITOR_ERROR_END_WRONG_BLOCK;
			} else {
			   status = EDITOR_STATUS_EOB;
			}
		     } else {

			/* Parse item */
			status = parse_item(tl, block_type, keyword, arg,
								      mode);
		     }
		  }
	       }
	       break;

	    case TEXT_FILE_STATUS_EOF :
	       status = EDITOR_STATUS_EOF;
	       break;

	    case TEXT_FILE_ERROR_LINE_TOO_LONG :
	       status = EDITOR_ERROR_LINE_TOO_LONG;
	       break;

	    default :
	       status = EDITOR_ERROR_READ_FAILED;
	       break;
	 }
      } while (status == EDITOR_STATUS_NORMAL);
      if (status != EDITOR_STATUS_EOB) {

	 /* Free incomplete block */
	 switch (block_type) {
	    case BLOCK_TYPE_FONT :
	       free_template_font(new_font);
	       break;

	    case BLOCK_TYPE_TEMPLATE :
	       free_template(tl, new_template);
	       break;

	    case BLOCK_TYPE_TEXTLIST :
	       free_template_text_list(new_template);
	       break;
	 }
      } else {
	 if (block_type == BLOCK_TYPE_FONT) {
	    AddTail((struct List *)&tl->tl_Fonts,
				      (struct Node *)&new_font->tf_MinNode);
	 } else {
	    if (block_type == BLOCK_TYPE_TEMPLATE) {
	       struct Template      *tp;
	       struct Box           *box;
	       struct BorderData    *bd;
	       struct TextData      *td;
	       struct GadgetData    *gd;

	       /* Init new template */
	       tp  = new_template;
	       box = &tp->tp_Box;
	       tp->tp_Node.ln_Name = &tp->tp_TemplateName[0];
	       switch (TEMPLATE_GROUP(tp)) {
		  case TEMPLATE_GROUP_BORDER :

		     /* Init border template */
		     bd                = &tp->tp_Data.tp_BorderData;
		     bd->bd_LeftEdge   = box->bo_X1;
		     bd->bd_TopEdge    = box->bo_Y1;
		     bd->bd_Width      = box->bo_X2 - box->bo_X1 + 1;
		     bd->bd_Height     = box->bo_Y2 - box->bo_Y1 + 1;
		     (bd + 1)->bd_Type = INTUISUP_DATA_END;
		     break;

		  case TEMPLATE_GROUP_TEXT :

		     /* Init text template */
		     td                = &tp->tp_Data.tp_TextData;
		     td->td_LeftEdge   = box->bo_X1;
		     td->td_TopEdge    = box->bo_Y1;
		     (td + 1)->td_Type = INTUISUP_DATA_END;
		     break;

		  case TEMPLATE_GROUP_GADGET :

		     /* Init gadget template */
		     gd                = &tp->tp_Data.tp_GadgetData;
		     gd->gd_LeftEdge   = box->bo_X1;
		     gd->gd_TopEdge    = box->bo_Y1;
		     gd->gd_Width      = box->bo_X2 - box->bo_X1 + 1;
		     gd->gd_Height     = box->bo_Y2 - box->bo_Y1 + 1;
		     (gd + 1)->gd_Type = INTUISUP_DATA_END;
		     break;
	       }
	       add_template_to_list(tl, tp, FALSE);
	    }
	 }
	 status = EDITOR_STATUS_NORMAL;
      }
   }
   return(status);
}
	/* Parse block of load file */

   STATIC SHORT
parse_item(struct TemplateList  *tl, USHORT block_type, BYTE *keyword,
						     BYTE *arg, USHORT mode)
{
   struct TextAttr    *ta;
   struct Template    *tp;
   struct Box         *box;
   struct BorderData  *bd;
   struct TextData    *td;
   struct GadgetData  *gd;
   SHORT status = EDITOR_STATUS_NORMAL;

   switch (block_type) {
      case BLOCK_TYPE_HEADER :

	 /* Read header data */
	 if (mode == LOAD_MODE_NORMAL) {
	    struct NewWindow  *nwin = &project_new_window;

	    switch (search_keyword(keyword, &header_keywords[0])) {
	       case HEADER_ITEM_TYPE_LEFTEDGE :
		  nwin->LeftEdge = Atol(arg);
		  break;

	       case HEADER_ITEM_TYPE_TOPEDGE :
		  nwin->TopEdge = Atol(arg);
		  break;

	       case HEADER_ITEM_TYPE_WIDTH :
		  nwin->Width = Atol(arg);
		  break;

	       case HEADER_ITEM_TYPE_HEIGHT :
		  nwin->Height = Atol(arg);
		  break;

	       case HEADER_ITEM_TYPE_FLAGS :
		  tl->tl_Flags = Atol(arg);
		  break;

	       case HEADER_ITEM_TYPE_ID :
		  strcpy(&tl->tl_ProjectID[0], arg);
		  break;
	    }
	 }
	 break;

      case BLOCK_TYPE_FONT :

	 /* Read template font data */
	 ta = &new_font->tf_TextAttr;
	 switch (search_keyword(keyword, &font_keywords[0])) {
	    case FONT_ITEM_TYPE_NAME :
	       status = duplicate_string(arg, (BYTE **)&ta->ta_Name);
	       break;

	    case FONT_ITEM_TYPE_YSIZE :
	       ta->ta_YSize = Atol(arg);
	       break;
	 }
	 break;

      case BLOCK_TYPE_TEMPLATE :

	 /* Read template data */
	 tp = new_template;
	 switch (search_keyword(keyword, &template_keywords[0])) {
	    case TEMPLATE_ITEM_TYPE_NAME :
	       strcpy(&tp->tp_TemplateName[0], arg);
	       break;

	    case TEMPLATE_ITEM_TYPE_TYPE :
	       tp->tp_Type = Atol(arg);
	       break;

	    case TEMPLATE_ITEM_TYPE_FLAGS :
	       tp->tp_Flags = Atol(arg);
	       break;
	 }
	 break;

      case BLOCK_TYPE_BOX :
	 
	 /* Read box data */
	 box = &new_template->tp_Box;
	 switch (search_keyword(keyword, &box_keywords[0])) {
	    case BOX_ITEM_TYPE_X1 :
	       box->bo_X1 = Atol(arg);
	       break;

	    case BOX_ITEM_TYPE_Y1 :
	       box->bo_Y1 = Atol(arg);
	       break;

	    case BOX_ITEM_TYPE_X2 :
	       box->bo_X2 = Atol(arg);
	       break;

	    case BOX_ITEM_TYPE_Y2 :
	       box->bo_Y2 = Atol(arg);
	       break;
	 }
	 break;

      case BLOCK_TYPE_TEXTLIST :

	 /* Read text list */
	 switch (search_keyword(keyword, &textlist_keywords[0])) {
	    case TEXTLIST_ITEM_TYPE_TEXT :
	       status = add_template_text_list_entry(new_template, arg);
	       break;
	 }
	 break;

      case BLOCK_TYPE_BORDERDATA :

	 /* Read border data */
	 bd = &new_template->tp_Data.tp_BorderData;
	 switch (search_keyword(keyword, &borderdata_keywords[0])) {
	    case BORDERDATA_ITEM_TYPE_TYPE :
	       bd->bd_Type = Atol(arg);
	       break;
	 }
	 break;

      case BLOCK_TYPE_TEXTDATA :

	 /* Read text data */
	 td = &new_template->tp_Data.tp_TextData;
	 switch (search_keyword(keyword, &textdata_keywords[0])) {
	    case TEXTDATA_ITEM_TYPE_TYPE :
	       td->td_Type = Atol(arg);
	       break;

	    case TEXTDATA_ITEM_TYPE_FLAGS :
	       td->td_Flags = Atol(arg);
	       break;

	    case TEXTDATA_ITEM_TYPE_TEXT :
	       if (td->td_Type == TEXT_DATA_TYPE_TEXT) {
		  status = duplicate_string(arg, &td->td_Text);
	       } else {
		  td->td_Text = (BYTE *)Atol(arg);
	       }
	       break;

	    case TEXTDATA_ITEM_TYPE_TEXTATTR :
	       if (!(td->td_TextAttr = open_template_font_by_num(tl,
						      (USHORT)Atol(arg)))) {
		  status = EDITOR_ERROR_INVALID_FONT;
	       }
	       break;
	 }
	 break;

      case BLOCK_TYPE_GADGETDATA :

	 /* Read gadget data */
	 tp = new_template;
	 gd = &tp->tp_Data.tp_GadgetData;
	 switch (search_keyword(keyword, &gadgetdata_keywords[0])) {
	    case GADGETDATA_ITEM_TYPE_TYPE :
	       gd->gd_Type = Atol(arg);
	       break;

	    case GADGETDATA_ITEM_TYPE_FLAGS :
	       gd->gd_Flags = Atol(arg);
	       break;

	    case GADGETDATA_ITEM_TYPE_TEXT :
	       if (*arg == '0') {
		  gd->gd_Text = NULL;
	       } else {
		  status = duplicate_string(arg, &gd->gd_Text);
	       }
	       break;

	    case GADGETDATA_ITEM_TYPE_TEXTATTR :
	       if (!(gd->gd_TextAttr = open_template_font_by_num(tl,
						      (USHORT)Atol(arg)))) {
		  status = EDITOR_ERROR_INVALID_FONT;
	       }
	       break;

	    case GADGETDATA_ITEM_TYPE_SPECIAL1 :
	       gd->gd_SpecialData.gd_Data.gd_Data1 = Atol(arg);
	       break;

	    case GADGETDATA_ITEM_TYPE_SPECIAL2 :
	       gd->gd_SpecialData.gd_Data.gd_Data2 = Atol(arg);
	       break;

	    case GADGETDATA_ITEM_TYPE_SPECIAL3 :
	       switch (gd->gd_Type) {
		  case GADGET_DATA_TYPE_BUTTON :
		  case GADGET_DATA_TYPE_CHECK :
		  case GADGET_DATA_TYPE_INTEGER :
		  case GADGET_DATA_TYPE_SLIDER :
		  case GADGET_DATA_TYPE_SCROLLER :
		  case GADGET_DATA_TYPE_COUNT :
		  case GADGET_DATA_TYPE_PALETTE :
		     gd->gd_SpecialData.gd_Data.gd_Data3 = (VOID *)Atol(arg);
		     break;
		  case GADGET_DATA_TYPE_STRING :
		     status = duplicate_string(arg,
			     (BYTE **)&gd->gd_SpecialData.gd_Data.gd_Data3);
		     break;
		  case GADGET_DATA_TYPE_MX :
		  case GADGET_DATA_TYPE_CYCLE :
		     status = build_template_text_array(tp);
		     break;
		  case GADGET_DATA_TYPE_LISTVIEW :
		     gd->gd_SpecialData.gd_ListViewData.gd_ListViewList = &tp->tp_TextList;
		     break;
	       }
	       break;
	 }
	 break;
   }
   return(status);
}
	/* Search keyword in given list */

   STATIC USHORT
search_keyword(BYTE *keyword, BYTE **keyword_list)
{
   BYTE   *word;
   USHORT count = 0, num = 0;

   while (word = *keyword_list++) {
      count++;
      if (!Strcmp(word, keyword)) {
	 num = count;
	 break;
      }
   }
   return(num);
}
