/*
 * $Source: $
 * $Revision: $
 * $Date: $
 * $State: $
 * $Author: $
 *
 *
 * $Log: $
 * Revision 3.1  3/10/92 wade
 * added IMAGE_KEY type
 *
 * 6/22/92 wade
 * Added util_get_stack()
 *
 */

/*  
 *	Copyright (c) 1991 by the Massachusetts Institute of Technology,
 *	For copying and distribution information, see the file
 *	"mit-copyright.h".
 *
 * 	utilMgr.c  - WADE 9/26/89
 *		These routines are general routines.  Hopefully, all routines in this file
 *		can be used by any application.
 *	
 *	util_remove_leading_blanks
 *	get_field
 *
 */
 
#include <Limits.h>
#include <Types.h>
#include <QuickDraw.h>
#include <Fonts.h>
#include <Events.h>
#include <Controls.h>
#include <Windows.h>
#include <Menus.h>
#include <TextEdit.h>
#include <Dialogs.h>
#include <Desk.h>
#include <Scrap.h>
#include <ToolUtils.h>
#include <Memory.h>
#include <SegLoad.h>
#include <Files.h>
#include <OSUtils.h>
#include <Traps.h>
#include <Lists.h>
#include <string.h>
#include <time.h>
#include <stdio.h>
#include "pips.h"
#include "prototype.h"
#include "mit-copyright.h"
 
Boolean get_field( char *buf, int field, char *value );
void	util_remove_leading_blanks( char *string );

static	Handle  start_ptr = NULL;
static	Handle	last_ptr = NULL;
 /*     
 *
 * 	util_remove_leading_blanks:
 * 
 *	remove leading blanks from parameter string.
 *
 */
 void
 util_remove_leading_blanks( string )
 char	*string;
 {
 	char	*ptr;
	
	/* assume each line is ended by at least a "\0" character */
	ptr = string;
	while ( *ptr == ' ' )
		ptr++;
	
	if ( ptr != string )
		strcpy(string,ptr);
}

/*     
 *
 * get_field:
 * 
 *
 */
 Boolean
get_field(buf,field,value) 
char	*buf;
int		field;
char	*value;
{
	char	*curr_ptr;
	int		ctr;
	char	*last_ptr;
	int		rc;
	Str255	locker;
	Str255	path;
	Str255  flags;
	
	/* special case (like a symbalic field) to return the list type */
	/* this is a cluge, but we need to determine what record format we */
	/* are parsing, it's either from show "s" or a traversal "w" transaction */
	if ( field < 1) {
		if (field == TYPE ) {
			rc = get_field(buf,LOCKER,locker); 
			if (rc) rc = get_field(buf,PATH,path);
			if (rc) rc = get_field(buf,FLAGS,flags);
		}
		else
			if (field == S_TYPE) {
			rc = get_field(buf,S_LOCKER,locker); 
			if (rc) rc = get_field(buf,S_PATH,path);
			if (rc) rc = get_field(buf,S_FLAGS,flags);
		}
		
		/* this is really bad, but here it is .... */
		if (strlen(path) == 0)
			value[0] = MENU_ITEM; /* subject record */
		else
			if (!strcmp(path,PHONE_KEY))
				value[0] = PHONE_ITEM; /* this is a phone type record */
			else 
				if (!strcmp(path,SERVER_KEY))
					value[0] = SERVER_ITEM;	/* worldwide techinfo servers */
				else
					if (atoi(flags) & IMAGE_KEY)
						value[0] = IMAGE_ITEM;	/* worldwide techinfo servers */
					else
						/* must be a text item */
						value[0] = TEXT_ITEM;
		return rc;
	}
	
	curr_ptr = buf;
	last_ptr = buf;
	
	for (ctr = 1; ctr <= field; ctr++) {
		curr_ptr = strstr(curr_ptr,":");
		if ( curr_ptr == NULL )
			curr_ptr = buf + strlen(buf);
		else
			if (ctr != field) {
				curr_ptr = curr_ptr + 1;
				last_ptr = curr_ptr;
			}
	}
	
	if (curr_ptr == last_ptr) {
		value[0] = '\0';
		return true;
	}
		
	strncpy(value,last_ptr,curr_ptr - last_ptr );
	value[curr_ptr - last_ptr] = '\0';
	
	return true;
}

typedef struct stack {
		Handle next_ptr;
		Handle prev_ptr;
		Str255 body; 
		int    node_item;
		Str255 window_title;
	} NODES;
	
util_push_stack(string, title)
char *string;
char *title;
{
	
	Handle	fifo_ptr;
	NODES	*node_ptr;
	NODES	*help_ptr;

	fifo_ptr = NewHandle(sizeof(NODES));
	node_ptr = (NODES *)*fifo_ptr;
	help_ptr = (NODES *)*fifo_ptr;
		
	if ( start_ptr == NULL ) {
		start_ptr = fifo_ptr;
		node_ptr -> node_item = 1;
	}
		
	strcpy(node_ptr -> body,string);
	strcpy(node_ptr -> window_title, title);
	node_ptr -> next_ptr = NULL;
	node_ptr -> prev_ptr = last_ptr;
	
	if (last_ptr != NULL ) {
		node_ptr = (NODES *)*last_ptr;
		node_ptr -> next_ptr = fifo_ptr;
		help_ptr -> node_item = node_ptr -> node_item + 1;
	}
	last_ptr = fifo_ptr;
	
}

Boolean
util_pop_stack(string)
char *string;
{
	NODES	*node_ptr;
	
	*string = '\0';
		
	if (last_ptr != NULL) {
		node_ptr = (NODES *)*last_ptr;
		
		if ( node_ptr -> prev_ptr != NULL ) {
			last_ptr = node_ptr -> prev_ptr;
		
			node_ptr = (NODES *)*last_ptr;
			DisposHandle(node_ptr -> next_ptr);
 			node_ptr -> next_ptr = NULL;
			strcpy(string,node_ptr -> body);
		}
		else {
			DisposHandle(last_ptr);
			last_ptr = NULL;
			start_ptr = NULL;
		}
			
		return true;
	}
	return false;
}

Boolean
util_query_stack(string)
char *string;
{
	NODES	*node_ptr;
	
	*string = '\0';
	
	if (last_ptr != NULL) {
		node_ptr = (NODES *)*last_ptr;
		strcpy(string,node_ptr -> body);
		return true;
	}
	else
		return false;
}

/*
 *
 *  util_get_stack_count:  This routine returns the number of items
 *  in the list.
 *
 */

Boolean
util_get_stack_count()
{
	NODES	*node_ptr;
	
	if (last_ptr != NULL) {
		node_ptr = (NODES *)*last_ptr;
		return (node_ptr -> node_item);
	}
	else
		return false;
}

/*
 *
 *  util_get_stack_count:  This routine returns the information for a
 *  specific item in the list.  It could have been used for the
 *  util_query_stack(), but I did not want to change this routine.
 *
 */

Boolean
util_get_stack_item(short get_node_item, char *transaction, char *title)
{
	NODES	*node_ptr;
	
	/* scan linked list for get_node_item */
	node_ptr = NULL;
	if (start_ptr != NULL)
		node_ptr = (NODES *)*start_ptr;
	while(node_ptr != NULL && node_ptr -> node_item != get_node_item) {
		node_ptr = (NODES *)*node_ptr -> next_ptr;
	}
	
	if (node_ptr == NULL)
		return false;

	/* get the data for this node item */
	strcpy(transaction,node_ptr -> body);
	strcpy(title,node_ptr -> window_title);
	return (node_ptr -> node_item);
}

/*
 *
 *  util_check_stack:  Determine if the stack exists inorder to disable/enable menu items.
 *		Return true if the stack exists.
 *
 */
Boolean
util_check_stack()
{
	if ( start_ptr == last_ptr ) 
		return false;
	else 
		return true;
		
}
/*
 *
 *  util_delete_stack:  Remove the entire stack.  Used when we
 *	switch from one server to another.
 *
 */
util_delete_stack()
{
	Str255	dummy_string;
	
	/* continue while there are items on the stack */
	/* we don't care about the argument */
	while(util_pop_stack(dummy_string));		
}

/*
 *
 *  search_str:  Routine to search for one string inside another,
 *		  case or not.
 *
 *	The code was written by SRZ.
 *
 */
char *
util_search_str(tp, tlen, sp, slen, case_sense)
char *tp, *sp;
int tlen, slen;
int case_sense;
{
     char *ep,lc,uc,*cp;

     if (slen == 0)
	  return(NULL);
     ep = tp + tlen - slen +1;
     lc = *sp;
     uc = lc;
     if (!case_sense && islower(*sp)) {
	  uc = toupper(lc);
     } else if (!case_sense && isupper(*sp)) {
	  lc = tolower(uc);
     }

     cp = tp;
     for (cp = tp; cp < ep; cp++) {
	  if (*cp != lc && *cp != uc) {
	       continue;
	  }
	  if (case_sense) {
	       if (!memcmp(cp, sp, slen))
		    return(cp);
	  } else {
	       if (!strncasecmp(cp, sp, slen))
		    return(cp);
	  }
     }
     return(NULL);
}

/* #$%^#$%^ Mac doesn't have an easily accessible case-insensitive case
   comparison routine.  Thus we plagiarize */

/*
 * Copyright (c) 1987 Regents of the University of California.
 * All rights reserved.  The Berkeley software License Agreement
 * specifies the terms and conditions for redistribution.
 */

/*
 * This array is designed for mapping upper and lower case letter
 * together for a case independent comparison.  The mappings are
 * based upon ascii character sequences.
 */
static char charmap[] = {
	'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
	'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
	'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
	'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
	'\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
	'\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
	'\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
	'\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
	'\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
	'\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
	'\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
	'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
	'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
	'\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
	'\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
	'\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
	'\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
	'\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
	'\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
	'\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
	'\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
	'\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
	'\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
	'\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337',
	'\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
	'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
	'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
	'\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
};

strcasecmp(s1, s2)
	register char *s1, *s2;
{
	register char *cm = charmap;

	while (cm[*s1] == cm[*s2++])
		if (*s1++ == '\0')
			return(0);
	return(cm[*s1] - cm[*--s2]);
}

strncasecmp(s1, s2, n)
	register char *s1, *s2;
	register int n;
{
	register char *cm = charmap;

	while (--n >= 0 && cm[*s1] == cm[*s2++])
		if (*s1++ == '\0')
			return(0);
	return(n < 0 ? 0 : cm[*s1] - cm[*--s2]);
}

/*     
 *
 * put_field:
 * 
 *
 */
 Boolean
util_put_field(buf,buf_length,field,value) 
char	*buf;
int		 buf_length;
int		 field;
char	*value;
{
	char	*curr_ptr;
	char	*last_ptr;
	Str255	temp;
	short	temp_size;
	short	nochange;
	short	found_one;
	char	*lp;
	short	ctr;
	
	curr_ptr = NULL;
	last_ptr = buf;
	
	found_one = 0;
	for (lp=buf,ctr=1; ctr <= buf_length && found_one < field; lp++,ctr++) {
		if (!strncmp(lp,DELIM,1)) {
			found_one++;
			if (found_one == field)
				curr_ptr = lp;
			else
				last_ptr = lp;
		}
	}
	
	if (last_ptr != buf && (last_ptr+1) != curr_ptr)
		last_ptr++;
		
	/* insert value into buff */
	if (curr_ptr != last_ptr ) {
		/* save second half of string in a temporary buffer */
		temp_size = buf_length-(curr_ptr-buf);
		strncpy(temp,curr_ptr,temp_size);
		
		/* check for a null field */
		/* if we are pointing at the DELM, move it up one */
		if (!strncmp(last_ptr,DELIM,1))
			last_ptr++;
			
		/* add new value to first half */
		strncpy(last_ptr,value,strlen(value));
		
		/* add second half of string to first half and new value */
		nochange = last_ptr - buf;
		last_ptr = last_ptr + strlen(value);
		strncpy(last_ptr,temp,temp_size);
		
		/* null terminate the string */
		buf[temp_size + strlen(value) + nochange] = NULL;
		return true;
	}
	else
		return false;
}  /* put_field */

/*     
 *
 * util_date_conv:
 * Convert unix time to a char string.
 *
 */
util_date_conv(dates,time_string)
char	*dates;
char	**time_string;
{
	time_t	seconds;
	char	*hhmmss_ptr;

	/* add the seconds since 1970 with the seconds from 1/1/04 - 1/1/70 */
	seconds = ((long int)atol(dates) * (long int)86400) + 2082844800 - 1;
	*time_string = ctime(&seconds);
	
	/* strip out hh:mm:ss, since all dates will have the same time stamp */
	hhmmss_ptr = strstr(*time_string,"23:59:59");
	if ( hhmmss_ptr != NULL ) {
		*(hhmmss_ptr-1) = '\0';	
		sprintf(*time_string,"%s%s",*time_string,hhmmss_ptr+8);
	}
}

