#ifndef VALUE_H
#define VALUE_H
#pragma interface

#include "List.h"
#include "Errors.h"
#include "Method.h"
#include "User.h"
#include "Structures.h"
#include "Subrange.h"
#include <stream.h>
#include <iostream.h>
#include <fstream.h>
#include <String.h>
extern "C" {
#include <values.h>
#include <sys/types.h>
#include <stdlib.h>
#include "genlib.h"
#include <time.h>
#include <limits.h>  // SysV might have to delete this line
}

typedef enum { UNUSED , STR , NUM , OBJ , ERR , LIST , REAL ,
                 MTHD, EXPR, SYM, RESERVED, SUBR, USER }  Value_Type;

class Value{
  friend class Val_List;
  friend class Value_Stack;
  friend class Object;
  friend class Method;
  friend class Frame;
  friend class Subrange;
  friend class User_Defined;
protected:
  union
    {String *str;
     String *sym;
     Val_List *expr;
     float real;
     long obj;
     long reserved;
     long num;
     long err;
     User_Defined* user;
     Val_List *list;
     Method *mthd;
     Subrange* sub;};
  short use_count;
  void subr_to_list ();
public:
  Value_Type type;
  Value (long inclass, Value* inval);
  Value (Value* inclass, Value* inval);
  Value (String* instring,  Value_Type vtype = STR);
  Value (char* instring,    Value_Type vtype = STR);
  Value (ifstream* infile);
  Value (FILE* infile);
  Value (Val_List *inlist,  Value_Type vtype = LIST);
  Value (Value *inlist,  int begin, int end);
  Value (int number = 0,    Value_Type vtype = NUM);
  Value (float inreal);
  Value (Method*);
  ~Value();
#define FREE_VAL switch(type)  \
                    {case STR:  delete str;  break;   \
		     case LIST: delete list; break;   \
                     case MTHD: delete mthd; break;   \
		     case SYM:  delete sym;  break;   \
		     case SUBR:  delete sub;  break;  \
		     case USER:  delete user; break;  \
                     case EXPR: delete expr; break;}  \
                 type = ERR;  err = E_DEAD_VALUE;
  
  Value* copy ();
  Value* grab ();
  void release ();
  Value* ensure_clean();
  int compare (Value* inval);    /* returns -  if this < inval  */
                                 /* returns 0  if this == inval */
                                 /* returns +  if this > inval  */
                                 /* returns INT_MAX on type mismatch */
  int boolean_val ();
  /** these all change this **/
  void increment ();
  void tonum (String** error_string = NULL);
  void toreal (String** error_string = NULL);
  void toobj (String** error_string = NULL);
  void toerr ();
  void tostr (String** error_string = NULL);
  void format (int tab=0, int columns=79);
  void tolist (Val_List* cdr = NULL);
  void toexpr (Val_List* cdr = NULL);
  void equal (Value*, String** error_string = NULL);
  void less_than (Value*, String** error_string = NULL);
  void greater_than (Value*, String** error_string = NULL);
  void less_than_equal (Value*, String** error_string = NULL);
  void greater_than_equal (Value*, String** error_string = NULL);
  void not (String** error_string = NULL);
  void concat (Val_List*);
  void subtract (Value*, String** error_string = NULL);
  void mod (Value*, String** error_string = NULL);
  void div (Value*, String** error_string = NULL);
  void mul (Value*, String** error_string = NULL);
  void add (Value*, String** error_string = NULL);
  void square_root (String** error_string = NULL);
  Value* nth (int i);                       /** for lists and expressions **/
  Value* index (Value* i, String** error_string = NULL);
  Value* car (String** error_string = NULL);
  void tolength (String** error_string = NULL);
  void insert (Value*, int position, String** error_string = NULL);
  void encryption (String** error_string = NULL);
  char* pack_value (char* buf);
  int obj_val();   /* if Value is type OBJ, returns the number, else -1 */
  int get_length();
  int ok_clause();
  String* command_match (String& pattern);
  String* command_match_BEFORE (String& pattern);
  Value_Type get_type()  {return type;}
  Value* implode (Value* separator, String** error_string = NULL);
  void print_val ();   /* purge later */

  friend Value* reg_split (Value* regstring, Value* bigstring);
  friend Value* unpack_value (char** temp_bufptr);
  friend Value* get_time();
  friend Value* get_random();
};

void concat_num (String& instring, int num);

const int vstack_start_size = 50;
const int vstack_grow_by  = 25;

extern int depth_found_at;

class Value_Stack {
  friend class Value;
 public:
  Value_Stack(int isize = vstack_start_size);
  ~Value_Stack();
  void push_val (Value* someval);
  void push_scope ();
  void pop_scope ();
  Value* peek_scope_bottom ();
  Value** pointer_scope_bottom ();
  Value* pop_val ();
  Value* peek ();
  int depth;
  int scope_depth;
  Value* highest_not_anon (Value* anon);
 protected:
  void grow (int by = vstack_grow_by);
  int allocated;
  Value** vstack;
  int* scope_level;
  int current_scope;
};

#endif   /* VALUE_H */