/*
**	termTimeDate.c
**
**	Phone rate calculation support routines
**
**	Copyright © 1990-1994 by Olaf `Olsen' Barthel
**		All Rights Reserved
**
** :ts=4
*/

#include "termGlobal.h"

	/* SelectTime():
	 *
	 *	Searches for the correct unit/pay conversion values.
	 */

VOID __regargs
SelectTime(struct PhoneEntry *SomeEntry,struct List *List,struct timeval *TimeVal)
{
	struct TimeDateNode			*TimeDateNode;
	struct DateStamp __aligned	 Date;
	struct ClockData			 ClockData;
	UBYTE						 Time;
	BYTE						 FoundOne = FALSE;
	LONG						 i,Last;

		/* If we get a specific time of day, use it. */

	if(TimeVal)
		Amiga2Date(TimeVal -> tv_secs,&ClockData);
	else
	{
			/* Obtain current time and date. */

		DateStamp(&Date);

			/* Convert into a more suitable form (note: seconds are
			 * required as an input value, ice is extra).
			 */

		Amiga2Date(Date . ds_Days * 86400 + Date . ds_Minute * 60 + Date . ds_Tick / TICKS_PER_SECOND,&ClockData);
	}

		/* Apparently, in the US of A the week starts with Sunday, we'll
		 * wrap the week around to let it start with Monday.
		 */

	if(ClockData . wday)
		ClockData . wday--;
	else
		ClockData . wday = 6;

		/* Change the month, too... */

	ClockData . month--;

	if(List)
	{
		if(!List -> lh_Head -> ln_Succ)
			List = NULL;
	}

		/* If no special list to search is given use the phonebook entry. */

	if(!List)
	{
		if(SomeEntry)
			List = (struct List *)&SomeEntry -> TimeDateList;
		else
		{
			PayPerUnit[DT_FIRST_UNIT]	= 0;
			PayPerUnit[DT_NEXT_UNIT]	= 0;
			SecPerUnit[DT_FIRST_UNIT]	= 0;
			SecPerUnit[DT_NEXT_UNIT]	= 0;

			return;
		}
	}

	if(!List -> lh_Head -> ln_Succ)
	{
		PayPerUnit[DT_FIRST_UNIT]	= 0;
		PayPerUnit[DT_NEXT_UNIT]	= 0;
		SecPerUnit[DT_FIRST_UNIT]	= 0;
		SecPerUnit[DT_NEXT_UNIT]	= 0;

		return;
	}

		/* First step: search for current day. */

	TimeDateNode = (struct TimeDateNode *)List -> lh_Head;

		/* Skip first entry. */

	TimeDateNode = (struct TimeDateNode *)TimeDateNode -> VanillaNode . ln_Succ;

		/* First step: search for date settings. */

	while(TimeDateNode -> VanillaNode . ln_Succ)
	{
			/* Does it match a specific date? */

		if(TimeDateNode -> Header . Month == ClockData . month && TimeDateNode -> Header . Day == ClockData . mday)
		{
			FoundOne = TRUE;

			break;
		}

		TimeDateNode = (struct TimeDateNode *)TimeDateNode -> VanillaNode . ln_Succ;
	}

		/* Second step: search for week day settings. */

	if(!FoundOne)
	{
		TimeDateNode = (struct TimeDateNode *)List -> lh_Head;

			/* Skip first entry. */

		TimeDateNode = (struct TimeDateNode *)TimeDateNode -> VanillaNode . ln_Succ;

		while(TimeDateNode -> VanillaNode . ln_Succ)
		{
				/* Does it match a specific day? */

			if(TimeDateNode -> Header . Month == -1 && (TimeDateNode -> Header . Day & (1L << ClockData . wday)))
			{
				FoundOne = TRUE;

				break;
			}

			TimeDateNode = (struct TimeDateNode *)TimeDateNode -> VanillaNode . ln_Succ;
		}
	}

		/* Third step: use default settings. */

	if(!FoundOne)
		TimeDateNode = (struct TimeDateNode *)List -> lh_Head;

		/* Convert current time to packed format. */

	Time = DT_GET_TIME(ClockData . hour,ClockData . min);

		/* Start with a blank. */

	Last = -1;

		/* Look for fitting time. */

	for(i = 0 ; i < TimeDateNode -> Table[0] . Count ; i++)
	{
			/* The time we are looking for must be >= the
			 * current time.
			 */

		if(TimeDateNode -> Table[i] . Time > Time)
		{
			if(i == 0)
				break;
			else
			{
				Last = i - 1;
				break;
			}
		}
		else
			continue;
	}

		/* If none is found, take the last one in the list.
		 * Note that this requires the list to be sorted in
		 * ascending order.
		 */

	if(Last == -1)
		Last = TimeDateNode -> Table[0] . Count - 1;

		/* Fill in the remaining data. */

	PayPerUnit[DT_FIRST_UNIT]	= TimeDateNode -> Table[Last] . PayPerUnit[DT_FIRST_UNIT];
	PayPerUnit[DT_NEXT_UNIT]	= TimeDateNode -> Table[Last] . PayPerUnit[DT_NEXT_UNIT];
	SecPerUnit[DT_FIRST_UNIT]	= TimeDateNode -> Table[Last] . SecPerUnit[DT_FIRST_UNIT];
	SecPerUnit[DT_NEXT_UNIT]	= TimeDateNode -> Table[Last] . SecPerUnit[DT_NEXT_UNIT];
}

struct List * __regargs
FindTimeDate(struct List *Patterns,STRPTR Number)
{
	struct PatternNode	*Node;
	UBYTE				 Dst[516];

	if(Kick30)
	{
		for(Node = (struct PatternNode *)Patterns -> lh_Head ; Node -> Node . ln_Succ ; Node = (struct PatternNode *)Node -> Node . ln_Succ)
		{
			if(ParsePatternNoCase(Node -> Pattern,Dst,516) != -1)
			{
				if(MatchPatternNoCase(Dst,Number))
					return(&Node -> List);
			}
		}
	}
	else
	{
		UBYTE	Src[256];
		STRPTR	Index;

		for(Node = (struct PatternNode *)Patterns -> lh_Head ; Node -> Node . ln_Succ ; Node = (struct PatternNode *)Node -> Node . ln_Succ)
		{
			strcpy(Index = Src,Node -> Pattern);

			while(*Index)
			{
				*Index = ToUpper(*Index);

				Index++;
			}

			if(ParsePatternNoCase(Src,Dst,516) != -1)
			{
				if(MatchPatternNoCase(Dst,Number))
					return(&Node -> List);
			}
		}
	}

	return(NULL);
}

VOID __regargs
DeletePatternNode(struct PatternNode *Pattern)
{
	if(Pattern)
	{
		struct TimeDateNode	*Node,
							*NextNode;

		for(Node = (struct TimeDateNode *)Pattern -> List . lh_Head ; NextNode = (struct TimeDateNode *)Node -> VanillaNode . ln_Succ ; Node = NextNode)
			FreeTimeDateNode(Node);
			
		FreeVecPooled(Pattern);
	}
}

struct PatternNode * __regargs
CreatePatternNode(STRPTR Comment)
{
	struct PatternNode *Node;

	if(Node = (struct PatternNode *)AllocVecPooled(sizeof(struct PatternNode),MEMF_ANY | MEMF_CLEAR))
	{
		struct TimeDateNode *TimeDateNode;

		Node -> Node . ln_Name = Node -> Comment;

		strcpy(Node -> Comment,Comment);

		NewList(&Node -> List);

		if(TimeDateNode = CreateTimeDateNode(-1,-1,"",2))
		{
			AddTail(&Node -> List,&TimeDateNode -> VanillaNode);

			return(Node);
		}

		FreeVecPooled(Node);
	}

	return(NULL);
}

VOID __regargs
DeletePatternList(struct List *List)
{
	if(List)
	{
		struct PatternNode	*Pattern,
							*NextPattern;

		for(Pattern = (struct PatternNode *)List -> lh_Head ; NextPattern = (struct PatternNode *)Pattern -> Node . ln_Succ ; Pattern = NextPattern)
			DeletePatternNode(Pattern);

		FreeVecPooled(List);
	}
}

struct List * __regargs
LoadTimeDateList(STRPTR Name,LONG *Error)
{
	struct IFFHandle	*Handle;
	struct List			*List = NULL;

	*Error = 0;

	if(Handle = (struct IFFHandle *)AllocIFF())
	{
		if(Handle -> iff_Stream = Open(Name,MODE_OLDFILE))
		{
			InitIFFasDOS(Handle);

			if(!(*Error = OpenIFF(Handle,IFFF_READ)))
			{
				STATIC LONG Stops[3 * 2] =
				{
					ID_TERM, ID_VERS,
					ID_TERM, ID_NAME,
					ID_TERM, ID_DATE
				};

				struct ContextNode *Chunk;

				if(!(*Error = StopChunks(Handle,Stops,3)))
				{
					if(List = (struct List *)AllocVecPooled(sizeof(struct MinList),MEMF_ANY))
					{
						struct PatternNode *Pattern = NULL;

						NewList(List);

						while(!ParseIFF(Handle,IFFPARSE_SCAN))
						{
							Chunk = CurrentChunk(Handle);

							if(Chunk -> cn_ID == ID_NAME)
							{
								if(Pattern = (struct PatternNode *)AllocVecPooled(sizeof(struct PatternNode),MEMF_ANY | MEMF_CLEAR))
								{
									if(ReadChunkBytes(Handle,Pattern -> Pattern,Chunk -> cn_Size) == Chunk -> cn_Size)
									{
										NewList(&Pattern -> List);

										Pattern -> Node . ln_Name = Pattern -> Comment;

										AddTail(List,Pattern);
									}
									else
									{
										*Error = IoErr();

										FreeVecPooled(Pattern);

										break;
									}
								}
								else
								{
									*Error = ERR_NO_MEM;

									break;
								}
							}

							if(Chunk -> cn_ID == ID_DATE)
							{
								struct TimeDateNode	*Node;
								WORD				 Count = (Chunk -> cn_Size - sizeof(struct TimeDateHeader)) / sizeof(struct TimeDate);

								if(!Pattern)
								{
									*Error = IFFERR_MANGLED;

									break;
								}

								if(Node = CreateTimeDateNode(-1,-1,"",Count))
								{
									if(ReadChunkBytes(Handle,&Node -> Header,sizeof(struct TimeDateHeader)) == sizeof(struct TimeDateHeader))
									{
										if(ReadChunkRecords(Handle,Node -> Table,sizeof(struct TimeDate),Count) == Count)
										{
											AdaptTimeDateNode(Node);

											AddTail(&Pattern -> List,&Node -> VanillaNode);
										}
										else
										{
											*Error = IoErr();

											FreeTimeDateNode(Node);

											break;
										}
									}
									else
									{
										*Error = IoErr();

										FreeTimeDateNode(Node);

										break;
									}
								}
							}
						}
					}
				}

				CloseIFF(Handle);
			}

			Close(Handle -> iff_Stream);
		}
		else
			*Error = IoErr();

		FreeIFF(Handle);
	}
	else
		*Error = ERR_NO_MEM;

	if(*Error)
	{
		DeletePatternList(List);

		return(NULL);
	}
	else
		return(List);
}

BOOL __regargs
SaveTimeDateList(STRPTR Name,struct List *List,LONG *Error)
{
	*Error = 0;

	if(List -> lh_Head -> ln_Succ)
	{
		struct IFFHandle *Handle;

		if(Handle = (struct IFFHandle *)AllocIFF())
		{
			BOOL Created;

			if(Handle -> iff_Stream = Open(Name,MODE_NEWFILE))
			{
				Created = TRUE;

				InitIFFasDOS(Handle);

				if(!(*Error = OpenIFF(Handle,IFFF_WRITE)))
				{
					if(!(*Error = PushChunk(Handle,ID_TERM,ID_FORM,IFFSIZE_UNKNOWN)))
					{
						if(!(*Error = PushChunk(Handle,0,ID_VERS,IFFSIZE_UNKNOWN)))
						{
							struct TermInfo TermInfo;

							TermInfo . Version	= TermVersion;
							TermInfo . Revision	= TermRevision;

							if(WriteChunkRecords(Handle,&TermInfo,sizeof(struct TermInfo),1) == 1)
							{
								if(!(*Error = PopChunk(Handle)))
								{
									struct PatternNode *Node;

									for(Node = (struct PatternNode *)List -> lh_Head ; !(*Error) && Node -> Node . ln_Succ ; Node = (struct PatternNode *)Node -> Node . ln_Succ)
									{
										if(!(*Error = PushChunk(Handle,0,ID_NAME,296)))
										{
											if(WriteChunkBytes(Handle,Node -> Pattern,296) == 296)
											{
												if(!(*Error = PopChunk(Handle)))
												{
													struct TimeDateNode *TimeDateNode;

													for(TimeDateNode = (struct TimeDateNode *)Node -> List . lh_Head ; TimeDateNode -> VanillaNode . ln_Succ ; TimeDateNode = (struct TimeDateNode *)TimeDateNode -> VanillaNode . ln_Succ)
													{
														if(!(*Error = PushChunk(Handle,0,ID_DATE,sizeof(struct TimeDateHeader) + TimeDateNode -> Table[0] . Count * sizeof(struct TimeDate))))
														{
															if(WriteChunkBytes(Handle,&TimeDateNode -> Header,sizeof(struct TimeDateHeader)) != sizeof(struct TimeDateHeader))
															{
																*Error = IoErr();

																break;
															}
															else
															{
																if(WriteChunkBytes(Handle,TimeDateNode -> Table,TimeDateNode -> Table[0] . Count * sizeof(struct TimeDate)) != TimeDateNode -> Table[0] . Count * sizeof(struct TimeDate))
																{
																	*Error = IoErr();

																	break;
																}
																else
																{
																	if(*Error = PopChunk(Handle))
																		break;
																}
															}
														}
														else
															break;
													}
												}
											}
											else
												*Error = IoErr();
										}
									}
								}
							}
						}

						if(!(*Error))
							*Error = PopChunk(Handle);
					}

					CloseIFF(Handle);
				}

				Close(Handle -> iff_Stream);
			}
			else
			{
				*Error = IoErr();

				Created = FALSE;
			}

			if(Created)
			{
				if(*Error)
					DeleteFile(Name);
				else
					AddProtection(Name,FIBF_EXECUTE);
			}

			FreeIFF(Handle);
		}
		else
			*Error = ERR_NO_MEM;
	}

	if(*Error)
		return(FALSE);
	else
		return(TRUE);
}
