/********************************************************************
This file is part of the abs 0.907 distribution.  abs is a spreadsheet
with graphical user interface.

Copyright (C) 1998-2001  André Bertin (Andre.Bertin@ping.be) 

This program 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 2 of the License, or
(at your option) any later version if in the same spirit as version 2.

This program 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 this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

Concact: abs@pi.be
         http://home.pi.be/bertin/abs.shtml

*********************************************************************/


























#include "cell.h"
#include "worksheet.h"
#include "workbook.h"
#include "style.h"
#include "y.tab.h"
#include "memory.h"
#include "date.h"
#include "cell_vb.h"
#include "gram_ext.h"
#include "application.h"

#include <string.h>


static int updating = 0;
static int parsing = 0;
static int setting_formula = 0;
static int ncell = 0;
static int parsingmacro;

static Cell **toredraw = NULL;
static int ntoredraw = 0;





static char tmpbuf[256];

Cell *ActiveCell;

Cell *
cell_activate (Cell * cell)
{
  ActiveCell = cell;
  if (ActiveWorksheet != NULL)
    {
      ActiveWorksheet->activecell = cell;
      if (ActiveWorksheet->cur_r != cell->r && ActiveWorksheet->cur_c != cell->c)
	worksheet_setcursor (ActiveWorksheet, cell->r, cell->c);
    }
  return ActiveCell;
}

Cell *
newcell (r, c)
     int r, c;
{
  Cell *nc;
  nc = (Cell *) absmalloc (sizeof (Cell), "newcell:Cell ");
  if (nc == NULL)
    {
      fprintf (stderr, "Cell: not allocated!");
      return NULL;
    }

  nc->val.rec.d = 0.0;
  nc->val.type = DOUBLE;
  nc->formula = NULL;

  nc->style = NULL;
  nc->r = r;
  nc->c = c;

  nc->familly = NULL;
  nc->worksheet = ActiveWorksheet;
  nc->tree = NULL;


  nc->type = undef;
  
  nc->objnum = ncell++;
  
  return nc;
}

int
clear_cell (Cell * cell)
{
  if (cell == NULL)
    return 1;
  
  
  
  
  if (cell->val.type == STRING_CONSTANT && cell->val.rec.s != cell->formula + 1)
    if (cell->val.rec.s != NULL)
      absfree (cell->val.rec.s, "freecell:cell->val.rec.s ");

  if (cell->formula != NULL)
    absfree (cell->formula, "freecell:cell->formula ");
  if (cell->tree != NULL)
    {
      freenode (cell->tree);
      cell->tree = NULL;
    }
  if (cell->style != NULL)
    {
      freestyle (cell->style);
      cell->style = NULL;
    }
  cell->val.rec.d = 0.0;
  cell->val.type = DOUBLE;
  cell->formula = NULL;

  cell_isnew (cell);
  nupdate2 (cell, 1);		

  cell->type = undef;
  return 0;
}
int
freecell (cell)
     Cell *cell;
{
  if (cell == NULL)
    return 1;
  
  
  
  
  if (cell->val.type == STRING_CONSTANT && cell->val.rec.s != cell->formula + 1)
    if (cell->val.rec.s != NULL)
      absfree (cell->val.rec.s, "freecell:cell->val.rec.s ");

  if (cell->formula != NULL)
    absfree (cell->formula, "freecell:cell->formula ");
  if (cell->tree != NULL)
    {
      freenode (cell->tree);
      cell->tree = NULL;
    }
  if (cell->style != NULL)
    {
      freestyle (cell->style);
      cell->style = NULL;
    }
  absfree (cell, "freecell:cell ");

  return 0;
}


int
cell_write (cell, fp)
     Cell *cell;
     FILE *fp;
{

  int deci, format;
  char *end = NULL;
  char chr[2];
  int len = 0;
  int i;

  if (cell == NULL)
    return -1;

  if (cell->type == constant)
    {
      fprintf (fp, "absnc(%d,%d,\"", cell->r, cell->c);
      fprintf (fp, "%g", cell_getvalue (cell));
      fprintf (fp, "\")\n");
    }
  else if (cell->type == text || cell->type == formula)
    {
      fprintf (fp, "absnc(%d,%d,\"", cell->r, cell->c);
      if (cell->formula != NULL)
	{
	  chr[1] = '\0';
	  end = strchr (cell->formula, '\n');
	  if (end != NULL)
	    end[0] = '\0';
	  len = strlen (cell->formula);
	  
	  

	  if (cell->formula[0] != '\'' && cell->formula[0] != '-'
	      && cell->formula[0] != '=' && cell->formula[0] != '+'
	      && !('0' <= cell->formula[0] && cell->formula[0] <= '9'))
	    fprintf (fp, "=");

	  for (i = 0; i < len; i++)
	    {
	      if (cell->formula[i] == '\"')
		fprintf (fp, "\"");	
	      chr[0] = cell->formula[i];
	      fprintf (fp, "%s", chr);
	    }
	  fprintf (fp, "\")\n");
	}
    }

  if (cell->style != NULL)
    {
      if (getstyle (cell->style, STY_BORDER_TOP) &&
	  getstyle (cell->style, STY_BORDER_BOT) &&
	  getstyle (cell->style, STY_BORDER_RIG) &&
	  getstyle (cell->style, STY_BORDER_LEF)
	)
	{
	  fprintf (fp, "Cells(%d,%d).Borders.LineStyle = xlLineStyleContinuous\n", cell->r, cell->c);
	}
      else
	{			
	  if (getstyle (cell->style, STY_BORDER_TOP))
	    fprintf (fp, "Cells(%d,%d).Borders(xlEdgeTop).LineStyle = xlLineStyleContinuous\n", cell->r, cell->c);
	  if (getstyle (cell->style, STY_BORDER_BOT))
	    fprintf (fp, "Cells(%d,%d).Borders(xlEdgeBottom).LineStyle = xlLineStyleContinuous\n", cell->r, cell->c);
	  if (getstyle (cell->style, STY_BORDER_RIG))
	    fprintf (fp, "Cells(%d,%d).Borders(xlEdgeRight).LineStyle = xlLineStyleContinuous\n", cell->r, cell->c);
	  if (getstyle (cell->style, STY_BORDER_LEF))
	    fprintf (fp, "Cells(%d,%d).Borders(xlEdgeLeft).LineStyle = xlLineStyleContinuous\n", cell->r, cell->c);
	}

      
      if (getstyle (cell->style, STY_FONT) != getstyle (ActiveWorkbook->style, STY_FONT))
	switch (getstyle (cell->style, STY_FONT))
	  {
	  case 0:
	    fprintf (fp, "Cells(%d,%d).Font.Name = \"Fixed\"\n", cell->r, cell->c);
	    break;
	  case 1:
	    fprintf (fp, "Cells(%d,%d).Font.Name = \"Courier\"\n", cell->r, cell->c);
	    break;
	  case 2:
	    fprintf (fp, "Cells(%d,%d).Font.Name = \"Helvetica\"\n", cell->r, cell->c);
	    break;
	  case 3:
	    fprintf (fp, "Cells(%d,%d).Font.Name = \"Times\"\n", cell->r, cell->c);
	    break;
	  case 4:
	    fprintf (fp, "Cells(%d,%d).Font.Name = \"Symbol\"\n", cell->r, cell->c);
	    break;
	  }

      if (getstyle (cell->style, STY_FONTS) != getstyle (ActiveWorkbook->style, STY_FONTS))
	switch (getstyle (cell->style, STY_FONTS))
	  {
	  case 0:
	    fprintf (fp, "Cells(%d,%d).Font.Size = 6\n", cell->r, cell->c);
	    break;
	  case 1:
	    fprintf (fp, "Cells(%d,%d).Font.Size = 8\n", cell->r, cell->c);
	    break;
	  case 2:
	    fprintf (fp, "Cells(%d,%d).Font.Size = 10\n", cell->r, cell->c);
	    break;
	  case 3:
	    fprintf (fp, "Cells(%d,%d).Font.Size = 12\n", cell->r, cell->c);
	    break;
	  case 4:
	    fprintf (fp, "Cells(%d,%d).Font.Size = 14\n", cell->r, cell->c);
	    break;
	  case 5:
	    fprintf (fp, "Cells(%d,%d).Font.Size = 18\n", cell->r, cell->c);
	    break;
	  case 6:
	    fprintf (fp, "Cells(%d,%d).Font.Size = 24\n", cell->r, cell->c);
	    break;
	  }
      if (getstyle (cell->style, STY_FONTW) == 1 || getstyle (cell->style, STY_FONTW) == 3)
	fprintf (fp, "Cells(%d,%d).Font.Bold = True \n", cell->r, cell->c);

      if (getstyle (cell->style, STY_FONTW) == 2 || getstyle (cell->style, STY_FONTW) == 3)
	fprintf (fp, "Cells(%d,%d).Font.Italic = True \n", cell->r, cell->c);

      
      if (getstyle (cell->style, STY_JUSTIF) != getstyle (ActiveWorkbook->style, STY_JUSTIF))
	switch (getstyle (cell->style, STY_JUSTIF))
	  {
	  case 0:
	    fprintf (fp, "Cells(%d,%d).HorizontalAlignment = xlLeft\n",
		     cell->r, cell->c);
	    break;
	  case 1:
	    fprintf (fp, "Cells(%d,%d).HorizontalAlignment = xlCenter\n",
		     cell->r, cell->c);
	    break;
	  case 2:
	    fprintf (fp, "Cells(%d,%d).HorizontalAlignment = xlRight\n",
		     cell->r, cell->c);
	    break;
	  }
      
      if (getstyle (cell->style, STY_BG) != getstyle (ActiveWorkbook->style, STY_BG))
	fprintf (fp, "Cells(%d,%d).Interior.ColorIndex = %d\n",
		 cell->r, cell->c, getstyle (cell->style, STY_BG) - 5);
      if (getstyle (cell->style, STY_FG) != getstyle (ActiveWorkbook->style, STY_FG))
	fprintf (fp, "Cells(%d,%d).Font.ColorIndex = %d\n",
		 cell->r, cell->c, getstyle (cell->style, STY_FG) - 5);

      
      format = getstyle (cell->style, STY_FORMAT);
      deci = getstyle (cell->style, STY_DECIMAL);
      if ((format != getstyle (ActiveWorkbook->style, STY_FORMAT) ||
	   deci != getstyle (ActiveWorkbook->style, STY_DECIMAL)) &&
	  format != 0)
	{
	  if (format >= 2 && format <= 4)
	    {
	      fprintf (fp, "Cells(%d,%d).NumberFormat = \"0", cell->r, cell->c);
	      if (deci)
		fprintf (fp, ".");
	      while (deci > 0)
		{
		  fprintf (fp, "0");
		  deci--;
		};
	    }
	  switch (format)
	    {
	    case 2:
	      fprintf (fp, "\"\n");
	      break;
	    case 3:
	      fprintf (fp, "E+00\"\n");
	      break;
	    case 4:
	      fprintf (fp, "%%\"\n");
	      break;
	    case 5:
	      {
		fprintf (fp, "Cells(%d,%d).NumberFormat = \"", cell->r, cell->c);
		fprintf (fp, "dd/mm/yy\"\n");
		break;
	      }
	    default:
	      fprintf (fp, "\"\n");
	    }
	}


    }
  return 0;
}

int
cell_setnumberformat (cell, buf)
     Cell *cell;
     char *buf;
{

  
  int deci = 0;
  char *dot;			
  char *token;

  if (strstr (buf, "General"))
    return 0;

  token = strchr (buf, ';');
  if (token != NULL)
    {
      token[0] = '\0';
      token++;
    }

  if (buf == NULL)
    return 1;

  if (strchr (buf, '/'))
    {
      cell_setformat (cell, 5, 0);
      return 0;
    }

  dot = strchr (buf, '.');

  if (dot != NULL)
    while (dot[deci + 1] == '0' && deci < strlen (dot))
      {
	deci++;
      }

  if (strchr (buf, 'E') || strchr (buf, 'e'))
    {
      cell_setformat (cell, 3, deci);
    }
  else if (strchr (buf, '%'))
    {
      cell_setformat (cell, 4, deci);
    }
  else
    {
      cell_setformat (cell, 2, deci);
    }

  return 0;
}


int
cell_setformula (cell, str)
     Cell *cell;
     char *str;
{
  int format, deci, date;

  int ret;
  int len;
  int second = 0;		
  char *buf = NULL;


  if (cell == NULL)
    {
      return 1;
    }

  if (cell->formula != NULL)
    {
      if (str != NULL)
	if (strcmp (cell->formula, str) == 0)
	  return 1;

      if (cell->val.type == STRING_CONSTANT &&
	  cell->val.rec.s == cell->formula + 1)
	cell->val.rec.s = NULL;

      absfree (cell->formula, "cell_setformula:cell->formula ");
      cell->formula = NULL;
    }

  if (cell->tree != NULL)
    {
      freenode (cell->tree);
      cell->tree = NULL;
    };

  cell_isnew (cell);

  if (str == NULL)
    {
      cell->formula = NULL;
      cell->val.rec.d = 0.0;
      cell->val.type = DOUBLE;
      
      cell->type = undef;
      return -1;
    };

  while (str[0] == ' ' && str[0] != '\0' && str[0] != '\n')
    str++;
  len = strlen (str);
  if (len < 1)
    {
      cell->formula = NULL;
      cell->val.rec.d = 0.0;
      cell->val.type = DOUBLE;
      
      cell->type = undef;
      return -1;
    };

  {
    buf = (char *) absmalloc (sizeof (char) * (len + 3), "cell_setformula:buf");

    if (len > 1)
      if ('0' <= str[1] && str[1] <= '9')
	{
	  second = 1;
	}

    if (str[0] == '=' ||
	str[0] == '+' ||
	str[0] == '-' ||
	str[0] == '\'' ||
	('0' <= str[0] && str[0] <= '9') ||
	(len > 1 && str[0] == '.' && second == 1)
      )
      {
	strcpy (buf, str);
      }
    else
      {
	buf[0] = '\'';
	strcpy (buf + 1, str);
      }

    

    cell->formula = (char *) absmalloc (sizeof (char) * (strlen (buf) + 5), "cell_setformula:cell->formula ");
    if (cell->formula == NULL)
      {
	fprintf (stderr, "formula not allocated\n");
	absfree (buf, "cell_setformula:buf");
	return -2;
      }

    
    cell_getformat (cell, &format, &deci);
    if (format == 5)
      {
	date = scandate (buf);
	if (date)
	  sprintf (buf, "%d\n", date);
      };

    len = strlen (buf);
    strcpy (cell->formula, buf);	
    cell->formula[len] = '\0';

    if (strncmp (cell->formula, "'", 1) == 0)
      {				
	
	
	
	
	
	cell->val.type = STRING_CONSTANT;
	cell->val.rec.s = cell->formula + 1;

	cell->type = text;
	nupdate2 (cell, 1);
	absfree (buf, "cell_setformula:buf");
	return 1;
      }
    cell->type = constant;


    ActiveCell = cell;
    setting_formula = 1;
    

    ret = parsecell (cell);


    if (ret)
      {
	cell->val.type = STRING_CONSTANT;
	cell->val.rec.s = "ERR!";
	
	cell->type = text;
      }
    else
      {
	if (cell_is_constant (cell))
	  {
	    freenode (cell->tree);
	    cell->tree = NULL;
	    absfree (cell->formula, "cell_setformula:cell->formula ");
	    cell->formula = NULL;

	  }
	else
	  {
	    execcelltree (cell);
	    cell->type = formula;
	  }
      }

    setting_formula = 0;
    nupdate2 (cell, 1);
    absfree (buf, "cell_setformula:buf");
    return 0;
  }
  cell->formula = NULL;
  cell->val.type = STRING_CONSTANT;
  cell->val.rec.s = NULL;

  cell->type = text;
  absfree (buf, "cell_setformula:buf");
  return 0;
}

int
cell_settext (cell, buf)
     Cell *cell;
     char *buf;
{
  char *end;
  char *first;




  if (cell == NULL)
    {
      return 1;
    }
  if (cell->val.type == STRING_CONSTANT)
    if (cell->val.rec.s != NULL)
      {
	absfree (cell->val.rec.s, "cell_settext:cell->val.rec.s ");
	cell->val.rec.s = NULL;
      }


  if (strlen (buf) > 0)
    {
      
      end = strchr (buf, '\n');
      if (end != NULL)
	end = '\0';

      cell->val.rec.s = (char *) absmalloc (sizeof (char) * (strlen (buf) + 5), "cell_settext:cell->formula ");
      if (cell->val.rec.s == NULL)
	fprintf (stderr, "val.rec.s not allocated\n");


      first = buf;
      while (*first == ' ' && first < buf + strlen (buf))
	first++;
      if (*first == '\'')
	{
	  strcpy (cell->val.rec.s, "'");
	  strcat (cell->val.rec.s, first + 1);
	  cell->formula = cell->val.rec.s;
	  cell->val.rec.s = cell->formula + 1;
	}
      else
	strcpy (cell->val.rec.s, buf);

    }
  else
    cell->val.rec.s = NULL;

  cell->val.type = STRING_CONSTANT;

  cell->type = text;

  return 0;
}


char *
cell_getformula (cell)
     Cell *cell;
{
  if (cell != NULL)
    switch (cell->type)
      {
      case constant:
	{
	  double val = cell_getvalue (cell);
	  if (val != 0.0)
	    {
	      sprintf (tmpbuf, "%g", cell_getvalue (cell));
	      return tmpbuf;
	    }
	  break;
	}
      case text:
	return cell->formula;
      case formula:
	return cell->formula;
      case undef:
	return NULL;
      }
  return NULL;
}

char *
cell_getnumberformat (cell)
     Cell *cell;
{


  return NULL;
}

double
cell_setvalue (cell, val)
     Cell *cell;
     double val;
{
  if (cell != NULL)
    {
      obj o;
      o.rec.d = val;
      o.type = DOUBLE;
      cell_setobj (cell, o);
    }
  return 0.0;
}

obj
cell_setobj (cell, o)
     Cell *cell;
     obj o;
{










  char tmp[64];
  char *buf;

  if (o.type == STRING)
    o.type = STRING_CONSTANT;

  if (cell != NULL)
    {
      switch (o.type)
	{
	case STRING_CONSTANT:
	  {
	    if (o.rec.s == NULL)
	      {
		clear_cell (cell);
		return o;
	      }
	    buf = absmalloc (sizeof (char) * (strlen (o.rec.s) + 2), "cell_setobj:buf");
	    if (o.rec.s[0] == '\'')
	      strcpy (buf, o.rec.s);
	    else
	      sprintf (buf, "'%s", o.rec.s);
	    cell_setformula (cell, buf);
	    absfree (buf, "cell_setobj:buf");
	    break;
	  };
	case DOUBLE:
	  sprintf (tmp, "%f", o.rec.d);
	  cell_setformula (cell, tmp);
	  break;
	case INTEGER:
	  sprintf (tmp, "%d", o.rec.i);
	  cell_setformula (cell, tmp);
	  break;
	}
    }
  return o;
}

obj
cell_setresval (cell, o)
     Cell *cell;
     obj o;
{





  int len = 0;

  if (o.type == STRING)
    o.type = STRING_CONSTANT;


  if (cell != NULL)
    {

      if (o.type == STRING_CONSTANT && o.rec.s != NULL)
	{
	  len = strlen (o.rec.s);
	}

      
      if (o.type == STRING_CONSTANT && len == 0)
	{
	  if (cell->val.type == STRING_CONSTANT && cell->val.rec.s != NULL)
	    absfree (cell->val.rec.s, "cell->val.rec.s:null_str");
	  cell->val.rec.s = NULL;
	  cell->val.type = STRING_CONSTANT;
	  return o;
	}

      
      if (cell->val.type == STRING_CONSTANT)
	{
	  if (o.type == STRING_CONSTANT)
	    {			
	      cell->val.rec.s = (char *) absrealloc (cell->val.rec.s, (len + 1) * sizeof (char),
					       "cell_setresobj::val.rec.s");
	      strcpy (cell->val.rec.s, o.rec.s);
	      return cell->val;
	    }
	  else
	    {
	      if (cell->val.rec.s != NULL)
		absfree (cell->val.rec.s, "cell_setresobj::val.rec.s");
	      cell->val.rec.s = NULL;
	    }
	}

      if (o.type == STRING_CONSTANT)
	{
	  cell->val.type = STRING_CONSTANT;
	  cell->val.rec.s = (char *) absmalloc ((len + 1) * sizeof (char), "cell_setresobj::val.rec.s");
	  strcpy (cell->val.rec.s, o.rec.s);
	  return cell->val;
	};


      cell->val = o;
      return cell->val;
    }
  return o;
}


double
cell_getvalue (cell)
     Cell *cell;
{
  if (cell == NULL)
    {				
      return 0.0;
    }
  
  switch (cell->val.type)
    {
    case DOUBLE:
      return cell->val.rec.d;
    case INTEGER:
      {
	double val = cell->val.rec.i;
	return val;
      }
    }
  return 0.0;
}

obj
cell_getobj (cell)
     Cell *cell;
{
  if (cell == NULL)
    {
      obj o;
      printf ("getvalue for NULL cell\n");
      o.type = INTEGER;
      o.rec.i = 0;
      return o;
    }
  return cell->val;
}

int
cell_istext (cell)
     Cell *cell;
{
  if (cell == NULL)
    return 0;
  if (cell->type == text)
    return 1;
  return 0;

}

char *
cell_gettext (cell)
     Cell *cell;
{
  char form[8];
  int format, deci;
  int dd, mm, yy;
  double value;
  if (cell == NULL)
    {
      return NULL;
    }
  if (cell->type != constant && cell->formula == NULL)
    {
      return NULL;
    }

  
  if (cell->type == text || cell->val.type == STRING_CONSTANT)
    return cell->val.rec.s;

  cell_getformat (cell, &format, &deci);

  value = cell_getvalue (cell);

  switch (format)
    {
    case 1:
      {
	sprintf (form, "%%g");
	sprintf (tmpbuf, form, value);
	break;
      }
    case 2:
      {
	sprintf (form, "%%.%dlf", deci);
	sprintf (tmpbuf, form, value);
	break;
      }
    case 3:
      {
	sprintf (form, "%%.%de", deci);
	sprintf (tmpbuf, form, value);
	break;
      }
    case 4:
      {
	sprintf (form, "%%.%dlf%%%%", deci);
	sprintf (tmpbuf, form, value * 100.);
	break;
      }
    case 5:
      {
	int date = value;
	num2date (date, &dd, &mm, &yy);
	sprintf (tmpbuf, "%2d/%2d/%4d", dd, mm, yy);
	break;
      }

    }

  return tmpbuf;
}






int
cell_setfg (cell, f)
     Cell *cell;
     int f;
{
  if (cell == NULL)
    return -1;
  if (cell->style == NULL)
    cell->style = newstyle (STY_CELL);
  setstyle (cell->style, STY_FG, f + 5);
  return 0;
}
int
cell_getfg (cell)
     Cell *cell;
{
  if (cell == NULL || cell->style == NULL)
    return getstyle (ActiveWorkbook->style, STY_FG);

  return getstyle (cell->style, STY_FG);
}

int
cell_setbg (cell, f)
     Cell *cell;
     int f;
{
  if (cell == NULL)
    return -1;
  if (cell->style == NULL)
    cell->style = newstyle (STY_CELL);

  setstyle (cell->style, STY_BG, f + 5);
  return 0;
}

int
cell_getbg (cell)
     Cell *cell;
{
  if (cell == NULL || cell->style == NULL)
    return getstyle (ActiveWorkbook->style, STY_BG);
  return getstyle (cell->style, STY_BG);
}


int
cell_gettop (cell)
     Cell *cell;
{
  if (cell == NULL || cell->style == NULL)
    return getstyle (ActiveWorkbook->style, STY_BORDER_TOP);
  return getstyle (cell->style, STY_BORDER_TOP);
}
int
cell_getbot (cell)
     Cell *cell;
{
  if (cell == NULL || cell->style == NULL)
    return getstyle (ActiveWorkbook->style, STY_BORDER_BOT);
  return getstyle (cell->style, STY_BORDER_BOT);
}
int
cell_getrig (cell)
     Cell *cell;
{
  if (cell == NULL || cell->style == NULL)
    return getstyle (ActiveWorkbook->style, STY_BORDER_RIG);
  return getstyle (cell->style, STY_BORDER_RIG);
}
int
cell_getlef (cell)
     Cell *cell;
{
  if (cell == NULL || cell->style == NULL)
    return getstyle (ActiveWorkbook->style, STY_BORDER_LEF);
  return getstyle (cell->style, STY_BORDER_LEF);
}

int
cell_settop (cell, v)
     Cell *cell;
     int v;
{
  if (cell == NULL)
    return -1;
  if (cell->style == NULL)
    cell->style = newstyle (STY_CELL);
  setstyle (cell->style, STY_BORDER_TOP, v);
  return 0;
}
int
cell_setbot (cell, v)
     Cell *cell;
     int v;
{
  if (cell == NULL)
    return -1;
  if (cell->style == NULL)
    cell->style = newstyle (STY_CELL);
  setstyle (cell->style, STY_BORDER_BOT, v);
  return 0;
}
int
cell_setrig (cell, v)
     Cell *cell;
     int v;
{
  if (cell == NULL)
    return -1;
  if (cell->style == NULL)
    cell->style = newstyle (STY_CELL);
  setstyle (cell->style, STY_BORDER_RIG, v);
  return 0;
}

int
cell_setlef (cell, v)
     Cell *cell;
     int v;
{
  if (cell == NULL)
    return -1;
  if (cell->style == NULL)
    cell->style = newstyle (STY_CELL);
  setstyle (cell->style, STY_BORDER_LEF, v);
  return 0;
}






int
cell_setformat (cell, format, deci)
     Cell *cell;
     int format, deci;
{
  double date;

  if (cell == NULL)
    return -1;
  if (cell->style == NULL)
    cell->style = newstyle (STY_CELL);


  if (format == 5 && getstyle (cell->style, STY_FORMAT) != 5)	
    {
      date = scandate (cell_getformula (cell));
      if (date)
	cell_setvalue (cell, date);
    }

  setstyle (cell->style, STY_FORMAT, format);
  setstyle (cell->style, STY_DECIMAL, deci);
  return 0;

}

int
cell_getformat (cell, format, decimal)
     Cell *cell;
     int *format, *decimal;
{
  if (cell == NULL)
    return -1;
  if (cell->style == NULL)
    {
      *format = getstyle (ActiveWorkbook->style, STY_FORMAT);
      *decimal = getstyle (ActiveWorkbook->style, STY_DECIMAL);
      return 0;
    }
  *format = getstyle (cell->style, STY_FORMAT);
  *decimal = getstyle (cell->style, STY_DECIMAL);
  return 0;
}


int
cell_setjust (cell, just)
     Cell *cell;
     int just;
{
  if (cell == NULL)
    return -1;
  if (cell->style == NULL)
    cell->style = newstyle (STY_CELL);
  setstyle (cell->style, STY_JUSTIF, just);
  return 0;
}

int
cell_getjust (cell)
     Cell *cell;
{
  if (cell == NULL || cell->style == NULL)
    return getstyle (ActiveWorkbook->style, STY_JUSTIF);
  return getstyle (cell->style, STY_JUSTIF);
}



int
cell_setfont (cell, font, weight, size)
     Cell *cell;
     int font;
{
  if (cell == NULL)
    return -1;
  if (cell->style == NULL)
    cell->style = newstyle (STY_CELL);
  if (font >= 0)
    setstyle (cell->style, STY_FONT, font);
  if (weight >= 0)
    setstyle (cell->style, STY_FONTW, weight);
  if (size >= 0)
    setstyle (cell->style, STY_FONTS, size);
  return 0;
}

int
cell_fontname (Cell * cell, char *name)
{

  if (cell->style == NULL)
    cell->style = newstyle (STY_CELL);
  if (!strcasecmp (name, "fixed"))
    setstyle (cell->style, STY_FONT, 0);
  if (!strcasecmp (name, "courier"))
    setstyle (cell->style, STY_FONT, 1);
  if (!strcasecmp (name, "helvetica"))
    setstyle (cell->style, STY_FONT, 2);
  if (!strcasecmp (name, "times"))
    setstyle (cell->style, STY_FONT, 3);
  if (!strcasecmp (name, "symbol"))
    setstyle (cell->style, STY_FONT, 4);
  return 0;
}

int
cell_fontsize (cell, v)
     Cell *cell;
     int v;
{

  if (cell->style == NULL)
    cell->style = newstyle (STY_CELL);
  switch (v)
    {
    case 6:
      setstyle (cell->style, STY_FONTS, 0);
      break;
    case 8:
      setstyle (cell->style, STY_FONTS, 1);
      break;
    case 10:
      setstyle (cell->style, STY_FONTS, 2);
      break;
    case 12:
      setstyle (cell->style, STY_FONTS, 3);
      break;
    case 14:
      setstyle (cell->style, STY_FONTS, 4);
      break;
    case 18:
      setstyle (cell->style, STY_FONTS, 5);
      break;
    case 24:
      setstyle (cell->style, STY_FONTS, 6);
      break;
    }
  return 0;
}

int
cell_fontbold (cell, v)
     Cell *cell;
     int v;
{

  if (cell->style == NULL)
    cell->style = newstyle (STY_CELL);
  if (v == 0)
    {
      if (getstyle (cell->style, STY_FONTW) > 1)
	setstyle (cell->style, STY_FONTW, 2);
      else
	setstyle (cell->style, STY_FONTW, 0);
    }
  else
    {
      if (getstyle (cell->style, STY_FONTW) > 1)
	setstyle (cell->style, STY_FONTW, 3);
      else
	setstyle (cell->style, STY_FONTW, 1);
    }
  return 0;
}

int
cell_fontitalic (cell, v)
     Cell *cell;
     int v;
{
  int w;

  if (cell->style == NULL)
    cell->style = newstyle (STY_CELL);
  w = getstyle (cell->style, STY_FONTW);
  if (v == 0)
    {
      if (w == 1 || w == 3)
	setstyle (cell->style, STY_FONTW, 1);
      else
	setstyle (cell->style, STY_FONTW, 0);
    }
  else
    {
      if (w == 1 || w == 3)
	setstyle (cell->style, STY_FONTW, 3);
      else
	setstyle (cell->style, STY_FONTW, 2);
    }
  return 0;
}

int
cell_getfont (cell)
     Cell *cell;
{
  if (cell == NULL || cell->style == NULL)
    return getstyle (ActiveWorkbook->style, STY_FONT);
  return getstyle (cell->style, STY_FONT);
  return 0;
}

int
cell_getfontw (cell)
     Cell *cell;
{
  if (cell == NULL || cell->style == NULL)
    return getstyle (ActiveWorkbook->style, STY_FONTW);
  return getstyle (cell->style, STY_FONTW);
  return 0;
}
int
cell_getfonts (cell)
     Cell *cell;
{
  if (cell == NULL || cell->style == NULL)
    return getstyle (ActiveWorkbook->style, STY_FONTS);
  return getstyle (cell->style, STY_FONTS);
  return 0;
}


int
cell_setborders (cell, border, type)
     Cell *cell;
     int border;
     int type;
{
  if (cell == NULL)
    return -1;
  if (cell->style == NULL)
    cell->style = newstyle (STY_CELL);

  if (border == 8 || border == 0)
    setstyle (cell->style, STY_BORDER_TOP, type);
  if (border == 7 || border == 0)
    setstyle (cell->style, STY_BORDER_LEF, type);
  if (border == 9 || border == 0)
    setstyle (cell->style, STY_BORDER_BOT, type);
  if (border == 10 || border == 0)
    setstyle (cell->style, STY_BORDER_RIG, type);
  return 0;
}


int
cell_setborder (cell, border)
     Cell *cell;
     int border;
{
  if (cell == NULL)
    return -1;
  if (cell->style == NULL)
    cell->style = newstyle (STY_CELL);

  setstyle (cell->style, STY_BORDER, border);
  return 0;
}

int
cell_getborder (cell)
     Cell *cell;
{
  if (cell == NULL || cell->style == NULL)
    return getstyle (ActiveWorkbook->style, STY_BORDER);
  return getstyle (cell->style, STY_BORDER);
  return 0;
}



int
parsecell (cell)
     Cell *cell;
{
  ActiveCell = cell;
  if (cell == NULL)
    return -1;
  if (cell->formula == NULL)
    return -2;

  cell->tree = parseexpression (cell->formula);

  if (cell->tree == NULL)
    return 1;

  setcelltree (cell->tree);
  return 0;
}

int
copymod (ii, jj, i, j, incr)
     int i, j, ii, jj, incr;
{
  Cell *cell1;
  Cell *cell2;
  cell1 = (Cell *) applicationcell (i, j, 1);
  cell2 = (Cell *) applicationcell (ii, jj, 1);
  return copymod2 (cell1, cell2, i, j, (i - ii) * incr, (j - jj) * incr);
}



int
copymod2 (cell1, cell2, _curi, _curj, _di, _dj)
     Cell *cell1;
     Cell *cell2;
     int _curi, _curj, _di, _dj;
{
  setdi (_di);
  setdj (_dj);
  cell_setformula (cell1, cell_getformula (cell2));
  setdi (0);
  setdj (0);

  return 0;
}

int
copymod3 (cell1, cell2, incr)
     Cell *cell1;
     Cell *cell2;
     int incr;
{
  if (cell1 == NULL || cell2 == NULL)
    return -1;

  setdi ((cell1->r - cell2->r) * incr);
  setdj ((cell1->c - cell2->c) * incr);
  cell_setformula (cell1, cell_getformula (cell2));
  setdi (0);
  setdj (0);

  return 0;
  return 0;
}







char *
tolower (char *s)
{
  int j;
  int len;
  len = strlen (s);
  for (j = 0; j < len; j++)
    if (s[j] >= 'A' && s[j] <= 'Z')
      s[j] = 'a' + s[j] - 'A';
  return s;
}

char *
strcasestr (char *str1, char *str2)
{
  char *s1;
  char *s2;
  char *pos = NULL;
  int l1;
  s1 = strdup (str1);
  if (s1 == NULL)
    return NULL;
  s2 = strdup (str2);
  if (s2 == NULL)
    {
      free (s1);
      return NULL;
    }

  tolower (s1);
  tolower (s2);
  pos = strstr (s1, s2);
  l1 = pos - s1;
  free (s1);
  free (s2);
  if (pos == NULL)
    return NULL;

  return str1 + l1;
}

int
cell_chgwksname (Cell * cell, char *oldname, char *newname)
{
  int len = 0;
  int i = 0;
  int diffsize;
  char *newformula = NULL;
  char *old, *pos, *end;
  if (cell == NULL)
    return -1;
  if (cell->formula == NULL)
    return 0;
  if (cell->tree == NULL)
    return 0;
  if (oldname == NULL || newname == NULL)
    return -1;
  if (strlen (oldname) < 1 || strlen (newname) < 1)
    return -1;
  if (!strcmp (oldname, newname))
    return 0;
  if (strcasestr (cell->formula, oldname) == NULL)
    return 0;

  
  diffsize = strlen (oldname) - strlen (newname);
  old = absmalloc ((strlen (oldname) + 2) * sizeof (char), "cell_chgwksname:old");
  sprintf (old, "%s!", oldname);

  pos = strcasestr (cell->formula, old);
  while (pos != NULL)
    {
      len = strlen (cell->formula);
      newformula = (char *) absmalloc ((len + 1 + diffsize) * sizeof (char), "cell_chgwksname:newformula");
      end = strchr (pos, '!');
      pos[0] = '\0';
      i = strlen (cell->formula) + strlen (newname) + 1;
      sprintf (newformula, "%s%s%s", cell->formula, newname, end);
      absfree (cell->formula, "cell_chgwksname:cell->formula");
      cell->formula = newformula;
      end = strcasestr (cell->formula, old);
      if (end > cell->formula + i)
	pos = end;
      else
	pos = NULL;
    }


  return 0;
}

int
cell1isfcell2 (cell1, cell2)
     Cell *cell1;
     Cell *cell2;
{
  int numpar1;
  int numchi2;
  int k;
  Cell **tmp;



  


  if (cell1 == cell2)
    return 1;

  if (cell1->familly == NULL)
    {
      cell1->familly = (Familly *) absmalloc (sizeof (Familly), "cell1isfcell2:cell1->familly ");
      if (cell1->familly == NULL)
	fprintf (stderr, "cell1->familly not allocated!\n");
      cell1->familly->numpar = 0;
      cell1->familly->dimparlist = 0;
      cell1->familly->parentlist = NULL;
      cell1->familly->numchi = 0;
      cell1->familly->dimchilist = 0;
      cell1->familly->childlist = NULL;
    }
  if (cell2->familly == NULL)
    {
      cell2->familly = (Familly *) absmalloc (sizeof (Familly), "cell1isfcell2:cell2->familly ");
      if (cell2->familly == NULL)
	fprintf (stderr, "cell2->familly not allocated!\n");
      cell2->familly->numpar = 0;
      cell2->familly->dimparlist = 0;
      cell2->familly->parentlist = NULL;
      cell2->familly->numchi = 0;
      cell2->familly->dimchilist = 0;
      cell2->familly->childlist = NULL;
    }

  numpar1 = cell1->familly->numpar;
  numchi2 = cell2->familly->numchi;
  
  if (cell1->familly->dimparlist < numpar1 + 1)
    {
      tmp = (Cell **) absmalloc (sizeof (Cell *) * (2 * numpar1 + 2), "cell1isfcell2:tmp ");
      if (tmp == NULL)
	fprintf (stderr, "tmp  not allocated!\n");
      for (k = 0; k < numpar1; k++)
	tmp[k] = cell1->familly->parentlist[k];
      if (cell1->familly->parentlist != NULL)
	absfree (cell1->familly->parentlist, "cell1isfcell2:cell1->familly->parentlist ");
      cell1->familly->parentlist = tmp;
      cell1->familly->dimparlist = 2 * numpar1 + 2;
    }
  
  if (cell2->familly->dimchilist < numchi2 + 1)
    {
      tmp = (Cell **) absmalloc (sizeof (Cell *) * (2 * numchi2 + 2), "cell1isfcell2:tmp ");
      if (tmp == NULL)
	fprintf (stderr, "tmp  not allocated!\n");
      for (k = 0; k < numchi2; k++)
	{
	  tmp[k] = cell2->familly->childlist[k];
	  
	}
      if (cell2->familly->dimchilist > 0 && cell2->familly->childlist != NULL)
	absfree (cell2->familly->childlist, "cell1isfcell2:cell2->familly->childlist ");
      cell2->familly->childlist = tmp;
      cell2->familly->dimchilist = 2 * numchi2 + 2;
    }
  
  for (k = 0; k < numpar1; k++)
    {				
				
      if (cell2 == cell1->familly->parentlist[k])
	return 2;
    }
  cell1->familly->parentlist[numpar1] = cell2;
  cell1->familly->numpar++;
  cell2->familly->childlist[numchi2] = cell1;
  cell2->familly->numchi++;




  return 0;
}

int
pfamilly2 (cell)
     Cell *cell;
{
  int k;
  Cell *cell2;
  if (cell == NULL)
    fprintf (stderr, "pfamilly of null cell\n");

  if (cell->familly == NULL)
    return 1;


  printf ("cell %d (r=%d c=%d)\n", cell->objnum, cell->r, cell->c);


  for (k = 0; k < cell->familly->numchi; k++)
    {
      cell2 = cell->familly->childlist[k];
      if (cell2)
	printf ("   - child %d: %d (wks=%s r=%d c=%d)\n", k, cell2->objnum, cell2->worksheet->Name, cell2->r, cell2->c);
      else
	printf ("   - child %d: NULL\n", k);
    }

  for (k = 0; k < cell->familly->numpar; k++)
    {
      cell2 = cell->familly->parentlist[k];
      if (cell2)
	printf ("   - parent %d: %d (wks=%s r=%d c=%d)\n", k, cell2->objnum, cell2->worksheet->Name, cell2->r, cell2->c);
      else
	printf ("   - parent %d: NULL\n", k);

    }

  return 0;
}

void
cell_auditcell (Cell * cell)
{
  pfamilly2 (cell);
}

int
cell_isnew (cell)
     Cell *cell;
{
  int k;
  Cell *i2j2;
  int l, found;

  if (updating || parsing)
    return 1;

  if (cell->familly == NULL)
    return 2;

  for (k = 0; k < cell->familly->numpar; k++)
    {
      i2j2 = cell->familly->parentlist[k];
      
      
      found = 0;
      if (i2j2->familly != NULL)	
	{
	  for (l = 0; l < i2j2->familly->numchi; l++)
	    {
	      if (i2j2->familly->childlist[l] == cell)
		found = 1;
	      if (found)
		{
		  i2j2->familly->childlist[l] = i2j2->familly->childlist[l + 1];
		}
	    }
	  i2j2->familly->numchi--;
	}
    }

  
  if (cell->familly->numpar > 0)
    {
      cell->familly->numpar = 0;
      absfree (cell->familly->parentlist, "cell_isnew:cell->familly->parentlist ");
      cell->familly->parentlist = NULL;
      cell->familly->dimparlist = 0;
    }
  cell->familly->numpar = 0;

  if (cell->familly->numchi == 0)
    {
      if (cell->familly->dimchilist > 0)
	absfree (cell->familly->childlist, "cell_isnew:cell->familly->childlist ");
      absfree (cell->familly, "cell_isnew:cell->familly ");
      cell->familly = NULL;
    }




  return 0;

}

extern int xdrawcell ();
static Cell *iterbase;
int
nupdate2 (Cell * cell, int redraw)
{
  int k;
  Cell *cell2;

  if (parsing)
    return 1;

  if (cell == NULL)
    return 2;

  if (cell->familly == NULL)
    {
      return 3;
    }
  if (updating == 0)
    iterbase = cell;
  else if (cell == iterbase)
    {
      fprintf (stderr, "circular reference in cell %d %d\n", cell->r, cell->c);
      return 0;
    }

  updating++;

  for (k = 0; k < cell->familly->numchi; k++)
    {
      cell2 = cell->familly->childlist[k];
      if (cell2->formula != NULL && cell2->tree != NULL)
	{
	  int exist = 0;
	  int i;
	  execcelltree (cell2);
	  nupdate2 (cell2, redraw);
	  if (redraw)
	    for (i = 0; i < ntoredraw; i++)
	      {
		if (toredraw[i] == cell2)
		  {
		    exist = 1;
		    i = ntoredraw;
		  }
	      }
	  
	  if (!exist)
	    {
	      toredraw = (Cell **) absrealloc (toredraw, sizeof (Cell *) * (ntoredraw + 1), "nupdate2:toredraw ");
	      toredraw[ntoredraw] = cell2;
	      ntoredraw++;
	    }
	}
    }
  updating--;


  if (updating == 0 && ntoredraw > 0)
    {
      for (k = 0; k < ntoredraw; k++)
	xdrawcell (toredraw[k]->r, toredraw[k]->c, 0);
      absfree (toredraw, "nupdate2:toredraw ");
      toredraw = NULL;
      ntoredraw = 0;
    }
  return 0;
}


extern char *obj2string (obj o);
extern obj getidval3 (int i);
extern int findid (char *s);


char *
textparsing (buf)
     char *buf;
{
  Cell *cell;
  Cell *activecell = ActiveCell;
  if (parsingmacro)
    {
      sprintf (tmpbuf, "to update");
      return tmpbuf;
    }
  cell = newcell (0, 1);

  cell_setformula (cell, buf);
  strcpy (tmpbuf, cell_gettext (cell));

  cell_isnew (cell);		
  freecell (cell);
  ActiveCell = activecell;
  return tmpbuf;
}


Cell *
cell_cpy (cell1, cell2)
     Cell *cell1;
     Cell *cell2;
{
  int len;

  if (cell1 == NULL || cell2 == NULL)
    return NULL;

  if (cell2->val.type == DOUBLE)
    {
      cell1->val.rec.d = cell2->val.rec.d;
      cell1->val.type = DOUBLE;
    }

  if (cell2->val.type == INTEGER)
    {
      cell1->val.rec.i = cell2->val.rec.i;
      cell1->val.type = INTEGER;
    }




  if (cell2->formula != NULL)
    {
      len = strlen (cell2->formula);
      if (len > 0)
	{
	  cell1->formula = (char *) absmalloc (sizeof (char) * len, "cell_cpy:cell1->formula ");
	  if (cell1->formula == NULL)
	    fprintf (stderr, "cell1->formula  not allocated!\n");
	  strcpy (cell1->formula, cell2->formula);
	  cell1->formula[len] = '\0';
	}
    }

  cell1->type = cell2->type;

  if (cell2->style != NULL)
    {
      if (cell1->style == NULL)
	cell1->style = newstyle (STY_CELL);
      style_cpy (cell1->style, cell2->style);
    }
  else
    {
      if (cell1->style != NULL)
	{
	  freestyle (cell1->style);
	  cell1->style = NULL;
	}
    }
  return cell1;
}

Cell *
cell_stycpy (cell1, cell2)
     Cell *cell1;
     Cell *cell2;
{

  if (cell1 == NULL || cell2 == NULL)
    return NULL;

  if (cell2->style != NULL)
    {
      if (cell1->style == NULL)
	cell1->style = newstyle (STY_CELL);
      style_cpy (cell1->style, cell2->style);
    }
  else
    {
      if (cell1->style != NULL)
	{
	  freestyle (cell1->style);
	  cell1->style = NULL;
	}
    }
  return cell1;
}

int 
cell_calculate (Cell * cell)
{
  return nupdate2 (cell, 0);
}

int 
cell_print (Cell * cell)
{
  if (cell == NULL)
    fprintf (stderr, "cell is NULL!\n");
  else
    fprintf (stderr, "cell %d %d formula %s\n", cell->r, cell->c, cell_getformula (cell));
  return 0;
}
