/*
 *	mainloop.c
 *
 *	2002/09/01	path variable has two default values :
 *				- the current dir
 *				- the install prog dir
 *				thanks to Masao KAWAMURA
 *
 *				do_path function modified to let these two items
 *				unchnged when the path function is called.
 *
 *	2002/06/02	out_matrix, out_cmatrix and out_imatrix now react to a change
 *				in window size.
 *
 */

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <float.h>
#include <stdarg.h>

#include "sysdep.h"
#include "output.h"
#include "input.h"
#include "funcs.h"
#include "graphics.h"
#include "interval.h"
#include "builtin.h"
#include "express.h"
#include "stack.h"
#include "meta.h"
#include "metaps.h"
#include "command.h"
#include "mainloop.h"
#include "udf.h"
#include "edit.h"
#include "scalp.h"
#include "help.h"
#ifdef YACAS
#include "yacas2e.h"
#endif

char *udfline;

/*
 * path for euler file research
 */

int searchglobal=0;

FILE *metafile=0;

double epsilon,changedepsilon;

char titel[]="This is EULER, Version %s.\n\n"
	"Type help(Return) for help.\n"
	"Enter command: (%ld Bytes free.)\n\n";

int error,quit,surpressed,udf=0,errorout,outputing=1,stringon=0,trace=0;
char input_line[1024];


int nosubmref=0;


static header commandheader;


extern commandtyp command_list[];


int commandtype;




/***************** some builtin commands *****************/


int builtin (void)
/***** builtin
	interpret a builtin command, number no.
*****/
{	unsigned long l;
	commandtyp *p;
	int comn;
	if (*next==3)
	{	next++;
#ifdef SPECIAL_ALIGNMENT
		memmove((char *)(&comn),next,sizeof(int));
#else
		comn=*((int *)next);
#endif
		p=command_list+comn;
		l=sizeof(int);
	}
	else if (udfon) return 0;
	else p=preview_command(&l);
	if (p)
	{	next+=l;
		p->f();
		if (*next==';' || *next==',') next++;
		commandtype=p->nr;
		return 1;
	}
	return 0;
}

header *scan_expression (void)
/***** scan_expression
	scans a variable, a value or a builtin command.
*****/
{	if (builtin()) return &commandheader;
	return scan();
}

#define addsize(hd,size) ((header *)((char *)(hd)+size))

static void do_assignment (header *var)
/***** do_assignment
	assign a value to a variable.
*****/
{	header *variable[8],*rightside[8],*rs,*v,*mark;
	int rscount,varcount,i,j;
	unsigned long offset,oldoffset,dif;
	char *oldendlocal;
	scan_space();
	if (*next=='=')
	{	next++;
		nosubmref=1; rs=scan_value(); nosubmref=0;
		if (error) return;
		varcount=0;
		/* count the variables, that get assigned something */
		while (var<rs)
		{	if (var->type!=s_reference && var->type!=s_submatrix
				&& var->type!=s_csubmatrix && var->type!=s_isubmatrix)
			{	output("Cannot assign to value!\n");
				error=210;
			}
			variable[varcount]=var; var=nextof(var); varcount++;
			if (varcount>=8)
			{	output("To many commas!\n"); error=100; return;
			}
		}
		/* count and note the values, that are assigned to the
			variables */
		rscount=0;
		while (rs<(header *)newram)
		{	rightside[rscount]=rs;
			rs=nextof(rs); rscount++;
			if (rscount>=8)
			{	output("To many commas!\n"); error=101; return;
			}
		}
		/* cannot assign 2 values to 3 variables , e.g. */
		if (rscount>1 && rscount<varcount)
		{	output("Illegal multiple assignment!\n"); error=102; return;
		}
		oldendlocal=endlocal;
		offset=0;
		/* do all the assignments */
		if (varcount==1) var=assign(variable[0],rightside[0]);
		else
		for (i=0; i<varcount; i++)
		{	oldoffset=offset;
			/* assign a variable */
			var=assign(addsize(variable[i],offset),
				addsize(rightside[(rscount>1)?i:0],offset));
			if (error) return;
			offset=endlocal-oldendlocal;
			if (oldoffset!=offset) /* size of var. changed */
			{	v=addsize(variable[i],offset);
				if (v->type==s_reference) mark=referenceof(v);
				else mark=submrefof(v);
				/* now shift all references of the var.s */
				if (mark) /* not a new variable */
					for (j=i+1; j<varcount; j++)
					{	v=addsize(variable[j],offset);
						dif=offset-oldoffset;
						if (v->type==s_reference && referenceof(v)>mark)
							referenceof(v)=addsize(referenceof(v),dif);
						else if (submrefof(v)>mark)
							submrefof(v)=addsize(submrefof(v),dif);
					}
			}
		}
	}
	else /* just an expression which is a variable */
	{	var=getvalue(var);
	}
	if (error) return;
	if (*next!=';') give_out(var);
	if (*next==',' || *next==';') next++;
}

int command (void)
/***** command
	scan a command and interpret it.
	return, if the user wants to quit.
*****/
{	
	header *expr;
	int ret=c_none;
	quit=0; error=0; errorout=0;
	while(1)
	{	scan_space();
		if (*next) break;
		else next_line();
	}
	if (*next==1) return ret;
#ifdef YACAS
	if (*next=='>')
	{	next+=1; do_yacas();
		return 0;
	}
#endif
	
	expr=scan_expression();
	if (!expr) { newram=endlocal; return ret; }
	if (error)
	{	newram=endlocal;
		print_error(next);
		next=input_line; input_line[0]=0;
		return ret;
	}
	if (expr==&commandheader)
	{	newram=endlocal;
		return commandtype;
	}
	switch (expr->type)
	{	case s_real :
		case s_complex :
		case s_matrix :
		case s_cmatrix :
		case s_imatrix :
		case s_string :
		case s_interval :
			if (*next!=';') give_out(expr);
			if (*next==',' || *next==';') next++;
			break;
		case s_reference :
		case s_submatrix :
		case s_csubmatrix :
		case s_isubmatrix :
			do_assignment(expr);
			break;
		default : break;
	}
	if (error) print_error(next);
	newram=endlocal;
	if (error) { next=input_line; input_line[0]=0; }
	return ret;
}

/******************* main functions ************************/

void clear_fktext (void)
{	int i;
	for (i=0; i<10; i++) fktext[i][0]=0;
}

#include <glib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>


static int is_dir(char *dirname)
{
	struct stat buf;
	
	if (stat(dirname,&buf)==0) {
		if (S_ISDIR(buf.st_mode))
			return 1;
	}
	return 0;
}

static void define_eulercfg()
{
	FILE *file;
	char *filename, *dirname;
	
	dirname = g_strconcat(g_get_home_dir(),"/.euler",NULL);
	if (!is_dir(dirname)) {
		mkdir(dirname,0755);
	}
	g_free(dirname);
	
	filename = g_strconcat(g_get_home_dir(),"/.euler/euler.cfg",NULL);
	file = fopen(filename, "r");
	if (file) {
		fclose(file);
		g_free(filename);
		return;
	}
	file = fopen(filename, "w");
	g_free(filename);

	if (file) {
		fprintf(file,"path(\".;%s/share/euler/progs\");\n",INSTALL_DIR);
		fprintf(file,"cd(\"%s/share/euler/progs\");\n",INSTALL_DIR);
		fprintf(file,"load \"util.e\";\n");
		fprintf(file,"load \"framed.e\";\n");
		fprintf(file,"load \"x.e\";\n");
		fprintf(file,"load \"remez.e\";\n");
		fprintf(file,"load \"steffens.e\";\n");
		fprintf(file,"load \"gauss.e\";\n");
		fprintf(file,"load \"histo.e\";\n");
		fprintf(file,"load \"interval.e\";\n");
		fprintf(file,"load \"broyden.e\";\n");
		fprintf(file,"load \"fminmax.e\";\n");
		fprintf(file,"load \"3dplot.e\";\n");
		fprintf(file,"load \"svd.e\";\n");
		fprintf(file,"load \"splines.e\";\n");
		fprintf(file,"load \"statist.e\";\n");
		fprintf(file,"shortformat();\n");
		fprintf(file,"shrinkwindow();\n");
		fclose(file);
	}
}

void main_loop (int argc, char *argv[])
{	int i;
	char *eulercfg;
	
	define_eulercfg();

#ifndef SPLIT_MEM
	output2(titel,VERSION,(unsigned long)(ramend-ramstart));
#else
	output2(titel,VERSION,(unsigned long)(ramend-varstart));
#endif

#ifndef SPLIT_MEM
	newram=startlocal=endlocal=ramstart;
#else
	newram=startlocal=endlocal=varstart;
#endif
	
	udfend=ramstart;
	changedepsilon=epsilon=10000*DBL_EPSILON;
	
	/*
	 *	setup default paths
	 */
	path[0]=(char *)malloc(2);
	strcpy(path[0],".");
	path[1]=(char *)malloc(strlen(INSTALL_DIR) + strlen("/share/euler/progs") + 1);
	strcpy(path[1], INSTALL_DIR);
	strcat(path[1], "/share/euler/progs");
	npath=2;

	sort_builtin(); sort_command(); make_xors(); clear_fktext();
	accuinit();
#ifdef YACAS
	init_yacas();
#endif
	next=input_line; *next=0;		/* clear input line */
	eulercfg = g_strconcat("load \"",g_get_home_dir(),"/.euler/euler.cfg\";",NULL);
	strcpy(input_line,eulercfg);
	g_free(eulercfg);
	for (i=1; i<argc; i++)
	{	strcat(input_line," load \"");
		strcat(input_line,argv[i]);
		strcat(input_line,"\";");
	}
	while (!quit)
	{   startglobal=startlocal;
		endglobal=endlocal;
		command();	/* interpret until "quit" */
		if (trace<0) trace=0;
	}
#ifdef YACAS
	exit_yacas();
#endif
}
