// Copyright (C) 1996 DIMACS Center, Rutgers, The State University of New Jersey
// Author(s): Jonathan Berry

// This software is copyrighted by the DIMACS Center at Rutgers, The State
// University of New Jersey.  IT IS PROVIDED AS IS, AND THE AUTHORS, DIMACS, AND
// RUTGERS, THE STATE UNIVERSITY OF NEW JERSEY  DISCLAIM
// ALL LIABILITY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
// DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
// DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

// THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
// IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
// NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
// MODIFICATIONS.

// The authors hereby grant permission to use, copy, modify, distribute,
// and license this software and its documentation for any purpose, provided
// that existing copyright notices are retained in all copies and that this
// notice is included verbatim in any distributions. No written agreement,
// license, or royalty fee is required for any of the authorized uses.
// Modifications to this software may be copyrighted by their authors
// and need not follow the licensing terms described here, provided that
// the new terms are clearly indicated on the first page of each file where
// they apply.

// Last File Update: 31-Jul-1996
// 

#include <iostream.h>
#include <strstream.h>
#include <stk.h>
#include <LINK/stkWrapper/LINK_STk.h>
#include <LINK/stkWrapper/Wrapper.h>

int tc_CXXwrapper;
SCM val_scm;

//************************************************************************
//**Duplicate the Cpointer SCM type in order to handle C++ pointers  *****
//************************************************************************
typedef void (*STk_mark_function)(SCM x);
typedef void (*STk_sweep_function)(SCM x);
typedef void (*STk_disp_function)(SCM, SCM, int);

static void markCXXwrapper(SCM);
static void freeCXXwrapper(SCM);
static void displayCXXwrapper(SCM, SCM, int);
static void CXXwrapper_default_mark(SCM);
static void CXXwrapper_default_sweep(SCM);
static void CXXwrapper_default_display(SCM, SCM, int);

static int CXXwrapper_id                = -1;
static int size                         = 0;
static STk_disp_function *display_array = NULL;
static STk_sweep_function *sweep_array 	= NULL;
static STk_mark_function *mark_array 	= NULL;


static STk_extended_scheme_type CXXwrapper_type = {
        "c++wrapper",           // name
        0,                      // is_procp
        markCXXwrapper,         // gc_mark_fct
        freeCXXwrapper,         // gc_sweep_fct
        NULL,                   // apply_fct
        displayCXXwrapper       // display_fct
};


static void markCXXwrapper(SCM ptr)
{
	(*(mark_array[EXTID(ptr)]))(ptr);
}

static void freeCXXwrapper(SCM ptr)
{
	(*(sweep_array[EXTID(ptr)]))(ptr);
}

static void displayCXXwrapper(SCM obj, SCM port, int mode)
{
	(*(display_array[EXTID(obj)]))(obj, port, mode);
}


static void CXXwrapper_default_mark(SCM ptr)
{
	//cout << "default mark:" << ptr << endl;
}

static void CXXwrapper_default_sweep(SCM s)
{
	//cout << "default sweep" << endl;
	if (!EXTSTATICP(s)) {
		delete EXTDATA(s);			// no destructor called 
	}
}

static void CXXwrapper_default_display(SCM obj, SCM port, int mode)
{
  sprintf(STk_tkbuffer, "#<C++-wrapper %d %lx>", EXTID(obj), EXTDATA(obj));
  Puts(STk_tkbuffer, port->storage_as.port.f);
}


int STk_new_CXXwrapper_id(char *CXXwrapper_name,
			  char *parent_classname,	// "" if no inherit
			  STk_disp_function display_func, 
			  STk_mark_function mark_func,
                          STk_sweep_function sweep_func)
{
  //perror("STk_new_CXXwrapper_id called"); 
  if (++CXXwrapper_id == size) {
    if (display_array == NULL) {
      display_array = new STk_disp_function[10];  
      mark_array    = new STk_mark_function[10];
      sweep_array   = new STk_sweep_function[10];
      size = 10;
    }
    else {
      int i, newsize=size+size/2;
      STk_disp_function *nda = new  STk_disp_function[newsize];
      STk_mark_function *nma = new  STk_mark_function[newsize];
      STk_sweep_function *nsa =new  STk_sweep_function[newsize];
      for (i=0; i<size; i++) {
		nda[i] = display_array[i];
		nma[i] = mark_array[i];
		nsa[i] = sweep_array[i];
      }
      delete display_array;
      delete mark_array;
      delete sweep_array;
      display_array = nda;
      mark_array    = nma;
      sweep_array   = nsa;
      size = newsize;
    }
  }
  mark_array   [CXXwrapper_id]= mark_func?    mark_func : 
					      CXXwrapper_default_mark;
  sweep_array  [CXXwrapper_id]= sweep_func?   sweep_func : 
					      CXXwrapper_default_sweep;
  display_array[CXXwrapper_id]= display_func? display_func : 
					      CXXwrapper_default_display;
  ostrstream oss;
  oss << "(define-class " << CXXwrapper_name;
  oss <<  "(" << parent_classname << ") (val))";
  oss << ends;
  char *buffer = oss.str();
  //cout << "-NEW CLASS-------------------------------------------------" << endl;
  //cout << buffer << endl;
  //cout << "-----------------------------------------------------------" << endl;
  SCM clath = STk_eval_C_string(buffer, NIL);  // this generates a file error
  delete buffer;
  return CXXwrapper_id;
}

SCM STk_make_CXXwrapper(int CXXwrapper_id, char *CXXwrapper_name, 
			void *ptr, int staticp)
{
  register SCM clath, z;

  NEWCELL(z, tc_CXXwrapper);
  EXTDATA(z)    = ptr;
  EXTID(z)      = CXXwrapper_id;
  EXTSTATICP(z) = staticp;	// protects from gc if LINK_STATIC

  ostrstream oss;
  oss << "(make " << CXXwrapper_name << ")";
  oss << ends;
  char *buffer = oss.str();
  clath = STk_eval_C_string(buffer, NIL);
  delete buffer;

  STk_slot_set(clath, val_scm, z);
  return clath;
}

PRIMITIVE STk_init_CXXwrapper(void)
{
        tc_CXXwrapper = STk_add_new_type(&CXXwrapper_type);
	val_scm = Intern("val");

	// these methods will be overloaded for each type of collection 
	
	defineNewMethod("sorted?");
	defineNewMethod("occurrences");
	defineNewMethod("rank");
	defineNewMethod("size");
	defineNewMethod("ref");
	defineNewMethod("degree");
	defineNewMethod("in-degree");
	defineNewMethod("out-degree");
	defineNewMethod("find-vertex");
	defineNewMethod("find-edge");
	defineNewMethod("clear!");
	defineNewMethod("insert!");
	defineNewMethod("append!");
	defineNewMethod("remove!");
	defineNewMethod("add-edges!");
	defineNewMethod("remove-edges!");
	defineNewMethod("^");
	defineNewMethod("subset");
	defineNewMethod("proper-subset");
	defineNewMethod("vertices");
	defineNewMethod("edges");
	defineNewMethod("cartesian-product");
	defineNewMethod("choose");
	defineNewMethod("power-set");
	defineNewMethod("permutations");
	defineNewMethod("graph");
	defineNewMethod("digraph");
	defineNewMethod("mset");
	defineNewMethod("set");
	defineNewMethod("sequence");

        defineNewMethod("vector-char");
        defineNewMethod("vector-int");
        defineNewMethod("mset-mset-int");
        defineNewMethod("set-mset-int");
        defineNewMethod("sequence-mset-int");
        defineNewMethod("mset-set-char");
        defineNewMethod("set-set-char");
        defineNewMethod("sequence-set-char");
        defineNewMethod("mset-set-int");
        defineNewMethod("set-set-int");
        defineNewMethod("sequence-set-int");
        defineNewMethod("mset-char");
        defineNewMethod("set-char");
        defineNewMethod("sequence-char");
        defineNewMethod("mset-int");
        defineNewMethod("set-int");
        defineNewMethod("sequence-int");
        defineNewMethod("list-mset-int");
        defineNewMethod("list-set-char");
        defineNewMethod("list-set-int");
        defineNewMethod("list-char");
        defineNewMethod("list-int");
        defineNewMethod("list-int");
        defineNewMethod("vector-vertex");
        defineNewMethod("mset-attributebase");
        defineNewMethod("set-attributebase");
        defineNewMethod("sequence-attributebase");
        defineNewMethod("mset-edge");
        defineNewMethod("set-edge");
        defineNewMethod("sequence-edge");
        defineNewMethod("mset-graph");
        defineNewMethod("set-graph");
        defineNewMethod("sequence-graph");
        defineNewMethod("mset-sequence-vertex");
        defineNewMethod("set-sequence-vertex");
        defineNewMethod("sequence-sequence-vertex");
        defineNewMethod("mset-set-vertex");
        defineNewMethod("set-set-vertex");
        defineNewMethod("sequence-set-vertex");
        defineNewMethod("mset-vertex");
        defineNewMethod("set-vertex");
        defineNewMethod("sequence-vertex");
        defineNewMethod("list-attributebase");
        defineNewMethod("list-edge");
        defineNewMethod("list-graph");
        defineNewMethod("list-sequence-vertex");
        defineNewMethod("list-set-vertex");
        defineNewMethod("list-vertex");
        defineNewMethod("vector-testobj");
        defineNewMethod("mset-testobj");
        defineNewMethod("set-testobj");
        defineNewMethod("sequence-testobj");
        defineNewMethod("list-testobj");


	initListTable();
}
