/*	Copyright (C) 1990 Free Software Foundation, Inc.

This file is part of Oleo, the GNU Spreadsheet.

Oleo is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.

Oleo is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Oleo; see the file COPYING.  If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */

#include "funcdef.h"

#include <stdio.h>
#include <ctype.h>
#include "sysdef.h"

#include "global.h"
#include "cell.h"

extern long astol EXT1(char **);

extern void set_width EXT2(CELLREF, unsigned short);
extern unsigned short next_widths EXT2(CELLREF *,CELLREF *);

extern char *cell_name EXT2(CELLREF, CELLREF);
extern char *range_name EXT1(struct rng *);

extern CELLREF highest_row EXT0();
extern CELLREF highest_col EXT0();

extern void read_usr_fmt EXT1(char *);
extern void write_usr_fmt EXT1(FILE *);

extern void read_options EXT1(char *);
extern void write_options EXT1(FILE *);

extern void clear_spreadsheet EXT0();

extern char *new_var_value EXT3(char *, int, char *);

extern char *read_new_value EXT4(CELLREF, CELLREF, char *, char *);

extern void push_cell EXT2(CELLREF, CELLREF);

extern char *bname[];
extern default_jst;
extern default_fmt;
extern default_lock;
extern unsigned short default_width;

extern struct rng all_rng;

/* This reads/writes a subset of the SC public-domain spreadsheet's
   file-format.  Note that since SC has no way of encoding some information
   about a cell, writing a spread out in SC format, then reading it back in
   will result in the loss of some information (most important:  cell formats)
 */

static int
get_range FUN2(char **,pp, struct rng *,rp)
{
	int byte;
	char *p;
	struct var *v;
	extern struct var *find_var();
	extern unsigned char parse_cell_or_range EXT2(char **,struct rng *);

	while(isspace(**pp))
		(*pp)++;
	byte=parse_cell_or_range(pp,rp);
	if(byte)
		return 0;
	for(p= *pp;*p && !isspace(*p);p++)
		;
	v=find_var(*pp,p-*pp);
	if(!v)
		return 1;
	*pp=p;
	*rp=v->v_rng;
	return 0;
}

void
sc_read_file FUN2(FILE *,fp, int,ismerge)
{
	char buf[2048];
	int lineno;
	char *ptr;
	int n;
	struct rng rng;

	lineno=0;
	if(!ismerge)
		clear_spreadsheet();
	while(fgets(buf,sizeof(buf),fp)) {
		lineno++;
		if(lineno%50==0)
			info_msg("Line %d",lineno);
		if(buf[0]=='#' || buf[0]=='\n')
			continue;
		if(!strncmp(buf,"set ",4)) {
			/* ... */
		} else if(!strncmp(buf,"format ",7)) {
			ptr=buf+7;
			if(get_range(&ptr,&rng))
				continue;
			n=astol(&ptr);
			set_width(rng.lc,n);
		} else if(!strncmp(buf,"hide ",5)) {
			ptr=buf+5;
			if(get_range(&ptr,&rng))
				continue;
			set_width(rng.lc,0);
		} else if(!strncmp(buf,"mdir ",5)) {
			/* ... */
		} else if(!strncmp(buf,"define ",7)) {
			char *eptr;

			ptr=buf+7;
			while(isspace(*ptr))
				ptr++;
			if(*ptr!='"') {
				error_msg("Line %d: No starting \" in define",lineno);
				continue;
			}
			ptr++;
			for(eptr=ptr; *eptr && *eptr!='"';eptr++)
				;
			if(!*eptr) {
				error_msg("Line %d: No starting \" in define",lineno);
				continue;
			}
			ptr=new_var_value(ptr,eptr-ptr,eptr+1);
			if(ptr)
				error_msg("Line %d: %s",ptr);
		} else if(!strncmp(buf,"leftstring ",11) ||
			  !strncmp(buf,"rightstring ",12)) {
			CELL *cp;

			ptr=buf+11;
			if(get_range(&ptr,&rng))
				continue;
			while(isspace(*ptr))
				ptr++;
			if(*ptr=='=')
				ptr++;
			new_value(rng.lr,rng.lc,ptr);
			cp=find_cell(rng.lr,rng.lc);
			if(buf[0]=='l')
				SET_JST(cp,JST_LFT);
			else
				SET_JST(cp,JST_RGT);

		} else if(!strncmp(buf,"let ",4)) {
			ptr=buf+4;
			if(get_range(&ptr,&rng))
				continue;
			while(isspace(*ptr))
				ptr++;
			if(*ptr=='=')
				ptr++;
			new_value(rng.lr,rng.lc,ptr);
		} else
			error_msg("Line %d: Can't parse %s",lineno,buf);
	}
	recenter_all_win();
}

static FILE *sc_fp;
static struct rng *sc_rng;
static void
sc_write_var FUN2(char *,name, struct var *,var)
{
	if(var->var_flags==VAR_UNDEF && (!var->var_ref_fm || var->var_ref_fm->refs_used==0))
		return;
	switch(var->var_flags) {
	case VAR_UNDEF:
		break;
	case VAR_CELL:
		if(var->v_rng.lr>=sc_rng->lr && var->v_rng.lr<=sc_rng->hr && var->v_rng.lc>=sc_rng->lc && var->v_rng.lc<=sc_rng->hc)
			(void)fprintf(sc_fp,"define \"%s\" %s\n",var->var_name,cell_name(var->v_rng.lr,var->v_rng.lc));
		break;
	case VAR_RANGE:
		if(var->v_rng.lr<sc_rng->lr || var->v_rng.hr>sc_rng->hr || var->v_rng.lc<sc_rng->lc || var->v_rng.hc>sc_rng->hc)
			break;

		(void)fprintf(sc_fp,"define \"%s\" %s\n",var->var_name,range_name(&(var->v_rng)));
		break;
#ifdef TEST
	default:
		panic("Unknown var type %d",var->var_flags);
		break;
#endif
	}
}
	
void
sc_write_file FUN2(FILE *,fp, struct rng *,rng)
{
	unsigned short w;
	CELLREF r,c;
	CELLREF rr;
	/* struct var *var; */
	CELL *cp;
	char *ptr;
	extern void for_all_vars();

	if(!rng)
		rng= &all_rng;

	(void)fprintf(fp,"# This file was created by Oleo, for use by the Spreadsheet Calculator\n");
	(void)fprintf(fp,"# You probably don't want to edit it.\n\n");

	(void)next_widths((CELLREF *)0,(CELLREF *)0);
	while(w=next_widths(&r,&c)) {
		if(c<rng->lc || r>rng->hc)
			continue;
		if(r<rng->lc)
			r=rng->lc;
		if(c>rng->hc)
			c=rng->hc;
		rr=r;
		do
			fprintf(fp,"format %s %d ???\n",cell_name(rr,MIN_ROW),w);
		while (rr++!=c);
	}
	sc_fp=fp;
	sc_rng=rng;
	for_all_vars(sc_write_var);
	find_cells_in_range(rng);
	while(cp=next_row_col_in_range(&r,&c)) {
		switch(GET_TYP(cp)) {
		case TYP_STR:
			if((GET_JST(cp)==JST_DEF && default_jst==JST_RGT) || GET_JST(cp)==JST_RGT)
				ptr="right";
			else ptr="left";
			fprintf(fp,"%sstring %s = %s\n",ptr,cell_name(r,c),decomp(r,c,cp));
			decomp_free();
			break;
		case 0:
			break;
		default:
			fprintf(fp,"let %s = %s\n",cell_name(r,c),decomp(r,c,cp));
			decomp_free();
			break;
		}
	}
}

int
sc_set_options FUN2(int,set_opt, char *,option)
{
	return -1;
}

void
sc_show_options FUN0()
{
	text_line("File format: sc  (Public domain spreadsheet calculator)");
}
