/********************************************************************
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 "object.h"
#include <stdlib.h>
#include <stdio.h>
#include "class.h"
#include "y.tab.h"
#include "libfct.h"		
#include "memory.h"
#include "properties.h"
#include "symboltable.h"


#include "cell.h"		

#include "range.h"		

#include "util.h"

int
str2int (str)
     char *str;
{
  int ret, v;
  int pos = 0;
  int spc = 0;

  if (str == NULL)
    return 0;
  if (strlen (str) < 1)
    return 0;

  while (str[pos] == ' ' && pos < 256)
    {
      pos++;
      spc++;
      if (str[pos] == '\0')
	return 0;
    }

  if (isnumber (str[pos]) >= 0)
    {
      sscanf (str, "%d", &ret);
      return ret;
    }

  ret = 0;
  while (pos < 32 + spc)
    {
      v = isletter (str[pos]);
      if (v)
	{
	  ret = ret * 26 + v;
	  pos++;
	}
      else
	{
	  return ret;
	}
    }

  return 0;
}

obj
obj2oper (o)
     obj o;
{				
  obj o1 = o;





  return o1;
}

obj
id2val (o)
     obj o;
{				
  if (o.type == IDENTIFIER || o.type == CONST)
    {
      obj *idval = &((Idval *) o.rec.s)->val;
      if (idval->type == VARIANT)
	idval = (obj *) idval->rec.s;
      return *idval;
    }
  return o;
}

obj
obj2val (obj o)
{				
  obj o1 = id2val (o);		

  switch (o1.type)
    {
    case INTEGER:
      break;
    case DOUBLE:
      break;
    case STRING_CONSTANT:
      break;
    case STRING:
      o1.type = STRING_CONSTANT;
      break;
    case CELL:
      o1 = cell_getobj ((Cell *) o1.rec.s);
      break;			
    default:
      o1 = class2obj (o1);
      break;
    }

  return o1;
}

int
obj2int (o)
     obj o;
{
  int ret = 0;
  obj o1 = obj2val (o);
  
  
  

  switch (o1.type)
    {
      
    case DOUBLE:
      ret = o1.rec.d;
      break;
    case INTEGER:
      ret = o1.rec.i;
      break;
    case STRING_CONSTANT:
      {
	ret = str2int (o1.rec.s);
      }
    }

  return ret;
}

double
obj2double (o)
     obj o;
{
  double ret = 0.0;
  obj o1 = obj2val (o);		
				

  switch (o1.type)
    {				

    case DOUBLE:
      ret = o1.rec.d;
      break;
    case INTEGER:
      ret = o1.rec.i;
      break;
    case STRING_CONSTANT:
      {
	ret = str2int (o1.rec.s);
      }
    }

  return ret;
}

int 
objisstring (obj o)
{
  obj o1 = obj2val (o);		
				
  if (o1.type == STRING ||
      o1.type == STRING_CONSTANT)
    return 1;
  return 0;
}

char *
obj2string (o)
     obj o;
{
  char *ret = NULL;
  obj o1 = obj2val (o);		
				

  if (o1.type == CELL)
    o1 = cell_getobj ((Cell *) o1.rec.s);

  switch (o1.type)
    {				
    case STRING_CONSTANT:
      ret = o1.rec.s;
      break;
    case STRING:
      ret = o1.rec.s;
      break;
    case RANGE:
      ret = o1.rec.s;
      break;
    }
  return ret;
}

static char retbuf[32];

char *
obj2text (o)
     obj o;
{
  char *ret = NULL;
  obj o1 = obj2val (o);		
				

  switch (o1.type)
    {				
      
    case STRING_CONSTANT:
      ret = o1.rec.s;
      break;
    case STRING:
      ret = o1.rec.s;
      break;
    case INTEGER:
      {
	sprintf (retbuf, "%d", o1.rec.i);
	ret = retbuf;
	break;
      };
    case DOUBLE:
      {
	sprintf (retbuf, "%f", o1.rec.d);
	ret = retbuf;
	break;
      };

    }
  return ret;
}


static obj withobj[20];
static int nwith = -1;

int
withenter (baseobj)
     obj baseobj;
{
  nwith++;
  withobj[nwith] = baseobj;
  return nwith;
}

int
withend ()
{
  nwith--;
  return nwith;
}

obj 
check_with (o2)
     obj o2;
{


  if (nwith >= 0)
    {
      obj o1 = withobj[nwith];
      
      
      
      
      

      
      
      
      

      
      
      

      obj *base;		
      obj *uper, *current;
      int i, class, member;




      if (o1.type == IDENTIFIER)
	{
	  o1 = id2val (o1);
	}

      i = 0;
      class = -1;
      member = -1;		
      while (o1.label != NULL && arrayclass[i].name != NULL && class < 0)
	{
	  if (strcasecmp (o1.label, arrayclass[i].name) == 0)
	    {
	      class = i;
	    }
	  i++;
	}
      if (class >= 0 && member >= 0)
	{			
	  if (arrayclass[class].data[member].type < NUMBER_OF_CLASS)
	    {
	      obj arg[1];
	      arg[0] = o1;
	      
	      o2 = (arrayclass[class].data[member].getfct) (1, arg);

	      return o2;
	    }
	}


      base = (obj *) absmalloc (sizeof (obj), "mkderef:base");
      base->type = o1.type;
      base->label = o1.label;
      base->rec.s = o1.rec.s;
      i = nwith - 1;
      current = base;
      while (i >= 0)
	{
	  uper = (obj *) malloc (sizeof (obj));
	  o1 = withobj[i];
	  if (o1.type == IDENTIFIER)
	    {
	      uper = (obj *) o1.rec.s;	
	      if (uper->type == VARIANT)
		uper = (obj *) uper->rec.s;
	    }
	  else
	    {
	      uper->type = o1.type;
	      uper->label = o1.label;
	      uper->rec.s = o1.rec.s;
	    }
	  current->type = MEMBER;
	  current->rec.s = (char *) uper;
	  current = uper;
	  i--;
	}

      o2.type = MEMBER;
      o2.rec.s = (char *) base;



    }

  return o2;
}

int
freenocstobj (obj o)
{
  o = id2val (o);
  switch (o.type)
    {
    case STRING:
      {				
	if (o.rec.s != NULL)
	  absfree (o.rec.s, "freenocstobj:o.rec.s STRING");
	o.rec.s = NULL;
	break;
      }
    case RANGEN:
      {
	Range *ran = (Range *) o.rec.s;


	freerange (ran);
	break;
      }
    case MEMBER:
      {
	if (o.rec.s != NULL)
	  {
	    freenocstobj (*((obj *) o.rec.s));
	    absfree (o.rec.s, "freenocstobj:o.rec.s MEMBER");
	    o.rec.s = NULL;
	  }
      }
    }
  return 0;
}


int
freeobj (obj o)
{
  switch (o.type)
    {
    case STRING_CONSTANT:
      {
	if (o.rec.s != NULL)
	  absfree (o.rec.s, "freeobj:o.rec.s STRING_CONSTANT");
	o.rec.s = NULL;
	break;
      }
    case MEMBER:
      {
	if (o.rec.s != NULL)
	  {
	    freeobj (*((obj *) o.rec.s));
	    absfree (o.rec.s, "freeobj:o.rec.s MEMBER");
	    o.rec.s = NULL;
	  }
      }






    }
  return 0;
}

obj 
mkderef (o1, o2)
     obj o1, o2;
{				
  
  
  
  

  
  
  
  
  
  
  
  
  

  
  
  

  obj *base;
  obj *uper;
  int i, class, member;









  if (o1.type == IDENTIFIER)
    {
      o1 = id2val (o1);
      
    }

  i = 0;
  class = -1;
  while (o1.label != NULL && arrayclass[i].name != NULL && class < 0)
    {
      if (strcasecmp (o1.label, arrayclass[i].name) == 0)
	{
	  class = i;
	}
      i++;
    }

  if (class >= 0)
    {
      i = 0;
      member = -1;
      while (o2.label != NULL && arrayclass[class].data[i].name != NULL && member < 0)
	{
	  if (strcasecmp (o2.label, arrayclass[class].data[i].name) == 0)
	    {
	      member = i;
	    }
	  i++;
	}
    }

  if (class >= 0 && member >= 0)
    {

      if (arrayclass[class].data[member].type < NUMBER_OF_CLASS)
	{
	  obj arg[1];
	  arg[0] = o1;
	  
	  o2 = (arrayclass[class].data[member].getfct) (1, arg);

	  return o2;
	}
    }

  base = (obj *) absmalloc (sizeof (obj), "mkderef:base");
  base->type = o1.type;
  base->label = o1.label;
  base->rec.s = o1.rec.s;

  
  
  uper = &o2;
  while ((uper->type == MEMBER) && uper->rec.s != NULL)
    {
      uper = (obj *) uper->rec.s;
    }

  uper->rec.s = (char *) base;



  return o2;

}

int
o1eqo2 (obj * o1, obj o2)
{
  Idval *idval;
  obj *val;






  idval = (Idval *) o1->rec.s;
  val = &(idval->val);


  if (idval->protect)
    return -1;

  switch (val->type)
    {
    case VARIANT:
      {
	val = (obj *) val->rec.s;
	val->rec = o2.rec;
	val->type = o2.type;
	break;
      }
    case INTEGER:
      val->rec.i = obj2int (o2);
      break;
    case DOUBLE:
      val->rec.d = obj2double (o2);
      break;
    default:
      {
	if (o2.type == STRING)
	  {
	    val->rec.s = absmalloc (sizeof (char) * (1 + strlen (o2.rec.s)), "mkassign::o->rec.s");
	    strcpy (o1->rec.s, o2.rec.s);
	    val->type = STRING;
	  }
	else
	  {
	    val->rec.s = o2.rec.s;
	    val->type = o2.type;
	    val->label = o2.label;
	  }
	break;
      }
    }









  return 0;
}

int
o1plusplus (obj * o1)
{
  Idval *idval = (Idval *) o1->rec.s;
  obj *val = &(idval->val);



  if (idval->protect)
    return -1;

  if (val->type == VARIANT)
    val = (obj *) val->rec.s;

  switch (val->type)
    {
    case INTEGER:
      val->rec.i += 1;
      break;
    case DOUBLE:
      val->rec.d += 1.0;
      break;
    default:
      {
	break;
      }
    }

  return 0;
}

int
o1moinsmoins (obj * o1)
{
  Idval *idval = (Idval *) o1->rec.s;
  obj *val = &(idval->val);



  if (idval->protect)
    return -1;
  if (val->type == VARIANT)
    val = (obj *) val->rec.s;

  switch (val->type)
    {
    case INTEGER:
      val->rec.i -= 1;
      break;
    case DOUBLE:
      val->rec.d -= 1.0;
      break;
    default:
      {
	break;
      }
    }

  return 0;
}







int
printobj (obj o)
{
  if (o.type == IDENTIFIER || o.type == CONST || o.type == CONSTCONST)
    {
      fprintf (stderr, "IDENTIFIER %s : ", o.label);
      if (o.rec.s == NULL)
	{
	  fprintf (stderr, "not allocated\n");
	  return 0;
	}
      else
	o = id2val (o);
    }

  if (o.type == DEREFID)
    {
      fprintf (stderr, "DEREFID    %s : ", o.label);
      o = *((obj *) o.rec.s);
    }

  switch (o.type)
    {
    case STRING_CONSTANT:
      fprintf (stderr, "STRING_CONSTANT val %s\n", o.rec.s);
      break;
    case STRING:
      fprintf (stderr, "STRING          val %s\n", o.rec.s);
      break;
    case INTEGER:
      fprintf (stderr, "INTEGER val %d\n", o.rec.i);
      break;
    case DOUBLE:
      fprintf (stderr, "DOUBLE val %f\n", o.rec.d);
      break;
    case CELL:
      fprintf (stderr, "%s type CELL \n", o.label);
      break;
    case WORKSHEET:
      fprintf (stderr, "%s type WORKSHEET \n", o.label);
      break;
    case MEMBER:
      {
	fprintf (stderr, "%s MEMBER of: ", o.label);
	if (o.rec.s != NULL)
	  printobj (*((obj *) o.rec.s));
	else
	  printf ("\n");
	break;
      }
    case OPERATION:
      fprintf (stderr, "operation %s %d\n", o.label, o.rec.i);
      break;
    default:
      {
	fprintf (stderr, "type %d \n", o.type);
      }
    }
  return 0;
}

int
niceprintobj (o)
     obj o;
{

  if (o.type == IDENTIFIER || o.type == CONST || o.type == CONSTCONST)
    {
      if (o.rec.s == NULL)
	{
	  fprintf (stderr, "not allocated\n");
	  return 0;
	}
      o = id2val (o);
    }

  if (o.type == DEREFID)
    {
      o = *((obj *) o.rec.s);
    }

  switch (o.type)
    {
    case STRING_CONSTANT:
      printf ("%s ", o.rec.s);
      break;
    case STRING:
      printf ("%s ", o.rec.s);
      break;
    case INTEGER:
      printf ("%d ", o.rec.i);
      break;
    case DOUBLE:
      printf ("%f ", o.rec.d);
      break;
    case MEMBER:
      {
	fprintf (stderr, "%s MEMBER of: ", o.label);
	if (o.rec.s != NULL)
	  printobj (*((obj *) o.rec.s));
	break;
      }
    }
  return 0;
}



int
getbaseclass (o2)
     obj o2;
{
  int i = 0;
  obj *o;
  if (o2.type != MEMBER)
    return -1;

  o = (obj *) o2.rec.s;		
  if (o->type != MEMBER)
    {
      return o->type;
    }				
  else
    {
      while (o->label != NULL && arrayclass[i].name != NULL)
	{
	  if (strcasecmp (o->label, arrayclass[i].name) == 0)
	    {
	      return i;
	    }
	  i++;
	}
    }
  

  fprintf (stderr, "objet type %s not found \n", o->label);
  return -1;
}

int
getmemberpos (class, o2)
     int class;
     obj o2;
{
  int i = 0;
  obj *o;
  if (class < NUMBER_OF_CLASS && class > 0)
    while (o2.label != NULL && arrayclass[class].data[i].name != NULL)
      {
	if (strcasecmp (o2.label, arrayclass[class].data[i].name) == 0)
	  return i;
	i++;
      }

  o = (obj *) o2.rec.s;
  fprintf (stderr, "class %d, member %s not found (member of %s) !\n", class, o2.label, o->label);
  return -1;
}

obj
member2val (o2)
     obj o2;
{
  obj oarg[2];
  int member;
  int class = getbaseclass (o2);
  if (class < 0 || class > NUMBER_OF_CLASS)
    return o2;
  member = getmemberpos (class, o2);
  if (member < 0)
    return o2;
  oarg[0] = o2;
  return (arrayclass[class].data[member].getfct) (1, oarg);	
}

obj
class2obj (o2)
     obj o2;
{
  obj oarg[2];
  int member;
  int class = o2.type;
  if (class < 0 || class >= NUMBER_OF_CLASS)
    return o2;
  member = 0;			
  if (member < 0)
    return o2;			
  oarg[0] = o2;
  return (arrayclass[class].data[0].getfct) (1, oarg);	
}

int
classname2classpos (char *name)
{
  int i = 0;

  while (name != NULL && arrayclass[i].name != NULL)
    {
      if (strcasecmp (name, arrayclass[i].name) == 0)
	return i;
      i++;
    }


  return -1;
}

int 
name2type (char *name)
{
  return classname2classpos (name);
}

int
mkclassassign (obj o1, obj o2)
{




  int class = o1.type;
  int i = 0;
  if (class < 0 || class >= NUMBER_OF_CLASS)
    return -1;


  while (arrayclass[class].fct[i].name != NULL)
    {
      if (!strcmp (arrayclass[class].fct[i].name, "="))
	{
	  obj args[2];
	  args[0] = o1;
	  args[1] = o2;
	  arrayclass[class].fct[i].fct (2, args);
	  return 0;
	}
      i++;
    }
  return 0;
}




int
objcmp (obj o1, obj o2)
{
  o1 = obj2val (o1);
  o2 = obj2val (o2);
  if (o1.type == o2.type)
    switch (o1.type)
      {
      case STRING_CONSTANT:
	return !(strcmp (o1.rec.s, o2.rec.s));
      case INTEGER:
	return (o1.rec.i == o2.rec.i);
      case DOUBLE:
	return (o1.rec.d == o2.rec.d);
      }

  return (obj2double (o1) == obj2double (o2));

}
