#include "include/glbtypes.h"
#include "include/glbproto.h"
#include "include/globvars.h"


listnode lnd_cdre(listnode l)
{
if (l!=NULL)
	while (l->next!=NULL)
		l=l->next;
return l;
}

listnode mk_listnode(listnode l)
{
l=lnd_cdre(l);
if (l!=NULL)
	{
	if(l->next==NULL)
		{
		l->next=my_malloc(sizeof(struct _listnode_));
		l->next->next=NULL;
		l->next->data=my_malloc(32);
		} 
	}
else
	{
	l=my_malloc(sizeof(struct _listnode_));
	l->next=NULL;
	l->data=my_malloc(32);
	};
return l;
}

listnode mk_set_lnd(listnode l,void PTR data,enum lnd_attr attr)
{
l=lnd_cdre(l);
if (l!=NULL)
	{
	if(l->next==NULL)
		{
		l->next=my_malloc(sizeof(struct _listnode_));
		l->next->next=NULL;
		l->next->data=data;
		l->next->attr=attr;
		} 
	}
else
	{
	l=my_malloc(sizeof(struct _listnode_));
	l->next=NULL;
	l->data=data;
	l->attr=attr;
	};
return lnd_cdre(l);
};

listnode mk_head_lnd(listnode lst,void PTR data,enum lnd_attr attr)
{
listnode l;
l=my_malloc(sizeof(struct _listnode_));
l->next=lst;
l->data=data;
l->attr=attr;
return l;
};

listnode rm_listnode(listnode l)
{
if (l!=NULL)
	{
	if(l->next!=NULL)
		{
		rm_listnode(l->next);
		switch(l->next->attr)
			{
			case	TWOLISTS:
			case	FUNCAVAR:
			case	LABELDEF:
			case	LABELREQ:
				rm_listnode((listnode)l->next->data);break;
			case	OPDEFPTR:
			case    TYPEDEFN:
			case	FUNCDEFN:
			case	FUNDEFNL:
				l->next->data=NULL;break;
			default:
				if (l->next->data!=NULL)
					Free(l->next->data);
			};
		Free(l->next);
		l->next=NULL;
		};
	}
return l;
}

listnode rm_last_node(listnode l)
{
listnode l1;
if(l==NULL) 
	return NULL;
l1=lnd_cdre(l);
while ((l->next!=NULL)&(l->next!=l1)) 
	l=l->next;
rm_listnode(l);
return l;
}

listnode rm_lnd_all(listnode l)
{
if (l!=NULL)
	{
	rm_listnode(l);
	Free(l);
	};
return NULL;
}

listnode lnd_iapnde(listnode l,char PTR s)
{
l=lnd_cdre(l);
Strcpy(l->data,s);
return l;
}

listnode lnd_sapnde(listnode l,char PTR s)
{
l=lnd_cdre(l);
l->next=my_malloc(sizeof(struct _listnode_));
l=l->next;
l->next=NULL;
l->data=my_malloc(Strlen(s));
Strcpy(l->data,s);
return l;
}

listnode lnd_asapnde(listnode l,char PTR s,enum lnd_attr attr)
{
l=lnd_cdre(l);
if(l!=NULL)
	{
	l->next=my_malloc(sizeof(struct _listnode_));
	l->next->next=NULL;
	l->next->attr=attr;
	l=l->next;
	}
else
	l=my_malloc(sizeof(struct _listnode_));
l->next=NULL;
l->data=my_malloc(Strlen(s));
Strcpy(l->data,s);
l->attr=attr;
return l;
}

listnode lnd_rapnde(listnode l1,listnode l2)
{
l1=lnd_cdre(l1);
l1->next=l2;
return l1;
}

listnode lnd_capnde(listnode l1,listnode l2)
{
lnd_rapnde(l1,copylist(l2));
return l1;
}


int lnd_count(listnode l)
{
int i;
for(i=0;l!=NULL;i++) l=l->next;
i--;
return i;
};

listnode get_nth_lnd(listnode l, int n)
{
if (l==NULL) 
	return NULL;
for(;(n>1)&(l->next!=NULL);n--) l=l->next;
return l;
};

listnode lnd_reverse_r(listnode l)
{
listnode l1,l2;
if(l==NULL)
	return NULL;
if(l->next==NULL)
	return l;
for(l1=l;l1->next->next!=NULL;l1=l1->next);
l2=l1->next;l1->next=NULL;
l2->next=lnd_reverse_r(l); /* recursively reverse the rest */
return l2;
};

listnode rm_cdr_next(listnode l)
{
listnode res;
if(l==NULL)
	return NULL;
res=l->next;
l->next=NULL;
rm_lnd_all(l);

return res;
};




listnode copylist(listnode l)
{
listnode lptr,l1;
if (l==NULL) 
	return NULL;
l1=my_malloc(sizeof(struct _listnode_));
lptr=l1;
while((l!=NULL))
	{
	lptr->attr=l->attr;

	switch(l->attr)
		{
		case 	TWOLISTS:
		case	FUNCAVAR:
		case	LABELDEF:
		case	LABELREQ:
			lptr->data=(char PTR)copylist((listnode) l->data);/* for dumb AIX cc */
			break;

		case	OPDEFPTR:
		case	TYPEDEFN:
			lptr->data=l->data;
			l->data=NULL;
			break;

		default:
			lptr->data=my_malloc(Strlen(l->data));
			Strcpy(lptr->data,l->data);
			break;
		};

	l=l->next;
	if (l!=NULL) 
		lptr->next=my_malloc(sizeof(struct _listnode_)); 
	else
		lptr->next=NULL;
	lptr=lptr->next;
	};
return l1;
};

listnode lnd_find(listnode l,char * data,enum lnd_attr attr)
{
listnode res=NULL;
for(;l!=NULL;l=l->next)
	{
	if(l->data!=NULL)
		{
		if((l->data==data)&(l->attr==attr))
			return l;
		if((data==NULL)&(l->attr==attr))
			return l;
		switch(l->attr)
			{
			case 	TWOLISTS:
			case	FUNCAVAR:
			case	LABELDEF:
			case	LABELREQ:
			if((res=lnd_find((listnode)l->data,data,attr))!=NULL)
					return res;
				break;

			case	OPDEFPTR:
			case	TYPEDEFN:
			case	VARDLIST:
			case	TYPELIST:
			/* these types of data can't be compared using Strcmp */
				break;

			default:
				if(data!=NULL)
					if((!Strcmp(l->data,data))&(l->attr==attr))
						return l;
			};
		};
	};
return NULL;
};

listnode lnd_replace(listnode l,void * d1,enum lnd_attr a1,void * d2,enum lnd_attr a2,int saveold,int repeat)
/* saveold: 0 - return old value as a new listnode, 1 - replace values and
return listnode, 2 - Free old data, replace and return listnode;
repeat: times to repeat, 0 for infinite;
Notes: with saveold=0 and repeat!=1 function returns list
Function returns last replaced listnode */
	{
	listnode res,ltmp=NULL;
	int i;
	for(i=0;(i<repeat)||(repeat==0);i++)
		{	
		res=lnd_find(l,(char *)d1,a1);
		if(res==NULL)
			{
			if(repeat==0)
				return ltmp;
			else
				return NULL;
			}
		else
			if((repeat==0)&(saveold!=0))
				ltmp=res; 
			/* to make it return something even if repeat=0 */
		if(saveold==0)
			{
			ltmp=mk_head_lnd(ltmp,res->data,res->attr);
			res->data=(char *)d2;
			res->attr=a2;

			if(i==repeat-1)
				return ltmp;
			};
		if(saveold==2)
			if(res->data!=NULL)
				Free(res->data);
		res->data=(char *)d2;
		res->attr=a2;
		};
	return res;
	};

void printlist(listnode l)
{
if (l!=NULL)
	{
	int i=1;
	while((l!=NULL))
		{

		printf("%2d:%25s  ³  ",i,(l->attr==TWOLISTS)?"<<new list>":((l->attr==OPDEFPTR)?"<<operator definition>>":l->data));
		switch (l->attr)
			{
		case TWOLISTS: printf("(this argument is another list)\n---\n");
				printlist((listnode)l->data);printf("---\n");break;

		case FUNCAVAR: printf("(this argument is a function list)\n---\n");
				printlist((listnode)l->data);printf("---\n");break;

		case OPDEFPTR: /* printf("(this argument is a operator definition)\n");*/
				printf("   [%s]  ³  %s\n",((defined_op)l->data)->form,((defined_op)l->data)->defn);
				break;
		case VARIABLE: printf("(this argument is a variable)\n");break;
		case ASSOCVAR: printf("(this argument is associated variable)\n");break;
		case BRACKETT: printf("(this argument is a brackett)\n");break;
		case FUNCTION: printf("(this argument is a name of function)\n");break;
		default:  printf("(this argument is a part of operator)\n");break;
			};
		l=l->next;
		i++;
		};
	};
};

void printlist1(listnode l,int step)
{
if (l!=NULL)
	{
	int i=1;
	while((l!=NULL))
		{

		printf("%*s%2d:%*s  ³  ",step,"",i,30-step,(l->attr==TWOLISTS)?"<<new list>":((l->attr==OPDEFPTR)?"<<operator definition>>":l->data));
		switch (l->attr)
			{
		case TWOLISTS: printf("(this argument is another list)\n");
				printlist1((listnode)l->data,step+1);break;

		case FUNCAVAR: printf("(this argument is a function list)\n");
				printlist1((listnode)l->data,step+1);break;

		case OPDEFPTR: /* printf("(this argument is a operator definition)\n");*/
				printf("   [%s]  ³  %s\n",((defined_op)l->data)->form,((defined_op)l->data)->defn);
				break;
		case VARIABLE: printf("(this argument is a variable)\n");break;
		case ASSOCVAR: printf("(this argument is associated variable)\n");break;
		case BRACKETT: printf("(this argument is a brackett)\n");break;
		case FUNCTION: printf("(this argument is a name of function)\n");break;
		default:  printf("(this argument is a part of operator)\n");break;
			};
		l=l->next;
		i++;
		};
	};
};

int printlist2(listnode l,int step,int j)
{
if (l!=NULL)
	{
	int i=1;
	while((l!=NULL))
		{

		if((l->attr!=LABELDEF)&(l->attr!=LABELREQ))
		printf("%*s%2d:%*s  ³  ",step,"",i,30-step,(l->attr==TWOLISTS)?(char PTR)"<<new list>":((l->attr==OPDEFPTR)?(char PTR)"<<operator definition>>":l->data));

		switch (l->attr)
			{
		case TWOLISTS: printf("(this argument is another list)\n");
				j=printlist2((listnode)l->data,step+1,j);break;

		case FUNCAVAR: printf("(this argument is a function list)\n");
				j=printlist2((listnode)l->data,step+1,j);break;

		case OPDEFPTR: /* printf("(this argument is a operator definition)\n");*/
				printf("   [%s]  ³  %s\n",((defined_op)l->data)->form,((defined_op)l->data)->defn);
				j++;break;
		case VARIABLE: printf("(this argument is a variable)\n");j++;break;
		case ASSOCVAR: printf("(this argument is associated variable)\n");j++;break;
		case BRACKETT: printf("(this argument is a brackett)\n");j++;break;
		case INLCBVAR: printf("(this argument is inline code block variable\n");j++;break;
		case FUNCTION: printf("(this argument is a name of function)\n");j++;break;
		case TYPELIST: printf("(this argument is a type list)\n");j++;break;
		case VARDLIST: printf("(this argument is a vardecl list)\n");j++;break;
		case LABELDEF:
		case LABELREQ:
				if(l->data!=NULL)
					printf("%*s%2d:%*s -> %s  ³  %s label\n",step,"",1,30-step,((listnode)l->data)->data,(((listnode)l->data)->next==NULL)?"!!!NULL!!!":((listnode)l->data)->next->data,((l->attr==LABELDEF)?"defined":"undefined"));
				j++;break;

		default:  printf("(this argument is a part of operator)\n");j++;break;
			};
		l=l->next;
		i++;
		if (j>14)
			{
			puts("->->-> Press any key for more ... <-<-<-");
			getchar();
			j=0;
			};
		};
	};
return j;
};



int spec_lnd_count(listnode l,enum lnd_attr attr)
{
int i=0;

if (l==NULL) return 0;

while((l!=NULL))
	{
	if (l->attr==attr) i++;
	if ((l->attr==TWOLISTS)||(l->attr==FUNCAVAR))
		i+=spec_lnd_count((listnode) l->data, attr);
	l=l->next;
	};
return i;
};
