// ~/Desktop/SWIG-1.3.24/swig -I/usr/include -I/u/jsiek/Desktop/SWIG-1.3.24/Lib -g -includeall stdio.i
// ~/SWIG-1.3.24/swig -I/usr/include -I/Users/jsiek/SWIG-1.3.24/Lib -g -includeall stdio.i

#include "swigmod.h"

#ifndef MACSWIG
#include "swigconfig.h"
#endif

#include <string>

static File *out = 0;
static  File         *f_runtime = 0;

void print_type(SwigType* s) {
  SwigType* t = Copy(s);
  if (SwigType_ispointer(t)) {
    SwigType_pop(t);
    print_type(t);
    Printf(out, "*");
  } else if (SwigType_isreference(t)) {
    SwigType_pop(t);
    print_type(t);
    Printf(out, "&");
  } else if (SwigType_isarray(t)) {
    SwigType_pop_arrays(t);
    print_type(t);
    Printf(out, "*");
  } else if (SwigType_isfunction(t)) {
    Printf(out, "fun (");
    ParmList *l = SwigType_function_parms(t);
    Parm      *p;
    for (p=l; p; p = nextSibling(p)) {
        SwigType *pt = Getattr(p,"type");
	print_type(pt);
	if (nextSibling(p) != 0)
	  Printf(out, ", ");
    }
    Delete(l);
    Printf(out, ")");
    SwigType_pop_function(t);
    if (Strcmp(t, "void") != 0) {
      Printf(out, " -> ");
      print_type(t);
      Printf(out, "@");
    }
  } else if (SwigType_isconst(t)) {
    SwigType_pop(t);
    print_type(t);
    Printf(out, " const");
  } else if (SwigType_isqualifier(t)) {
    SwigType_pop(t);
    print_type(t);
  } else if (SwigType_issimple(t)) {
    Printf(out, "%s", t);
  } else if (SwigType_isvarargs(t)) {
    Printf(out, "...");
  } 
}

class G : public Language {
public:

  virtual void main(int argc, char* argv[]) 
  {
    for (int i = 0; i < argc; i++ ) {
      if (strcmp( argv[i], "-g" ) == 0 ) {
	char* extension = 0; 
	if( i + 1 >= argc )
	  continue;
	extension = argv[i+1]+strlen(argv[i+1])-2;
	if (strcmp( extension, ".g" ))
	  continue;
	i++;
	Swig_mark_arg (i);
	String * outfile = NewString( argv[i] );
	out = NewFile(outfile,"w");
	if (!out) {
	  Printf(stderr,"*** Can't open '%s'\n", outfile);
	  SWIG_exit(EXIT_FAILURE);
	}
	continue;
      }
    }
    Preprocessor_define("__ppc__ 1", 0);
  }

  virtual int top(Node *n)
  {
    f_runtime = NewString("");
    Swig_register_filebyname("runtime",f_runtime);


    if (out == 0) {
      String *outfile = Getattr(n,"outfile");
      Replaceall(outfile,".c", ".g");
      out = NewFile(outfile,"w");
      if (!out) {
	Printf(stderr,"*** Can't open '%s'\n", outfile);
	SWIG_exit(EXIT_FAILURE);
      }
    }
    
    Printf(out, "extern \"C\" {\n");
    int r = Language::top(n);
    Printf(out, "}\n");
    return r;
  }


  int constantWrapper(Node*) { return SWIG_OK; }
  int functionWrapper(Node*) { return SWIG_OK; }

  virtual int typedefHandler(Node *n) {
    if (!Getattr(n, "unnamed")) { // skip unnamed enums
      String* t = Getattr(n, "type");
      String* name = Getattr(n, "name");
      Printf(out, "type %s = ", name);
      print_type(t);
      Printf(out, ";\n");
    }
    return SWIG_OK;
  }

  virtual int enumDeclaration(Node *n) {
    // problem is here
    if (Getattr(n, "name")) { // skip unnamed enums
      String* name =  Getattr(n, "name");
      Printf(out, "type %s = int;\n", name);
    }
    return SWIG_OK;
  }

  virtual int globalfunctionHandler(Node *n) {
    String* name =  Getattr(n, "name");
    SwigType  *rt = Getattr(n,"type"); 
    ParmList  *l = Getattr(n,"parms");

    Printf(out, "fun %s(", name);

    Parm      *p;
    for (p=l; p; p = nextSibling(p)) {
        SwigType *pt = Getattr(p,"type");
	print_type(pt);
        Printf(out, "@");
	if (nextSibling(p) != 0)
	  Printf(out, ", ");
    }	
    Printf(out, ")");
    if (Strcmp(rt, "void") != 0) {
      Printf(out, " -> ");
      print_type(rt);
      Printf(out, "@");
    }
    Printf(out, ";\n");
    return SWIG_OK;
  }

  virtual int classDeclaration(Node *n) {
    String* name =  Getattr(n, "name");
    Printf(out, "class %s;\n", name);
    return SWIG_OK;
  }

  virtual int classforwardDeclaration(Node *n) {
    String* name =  Getattr(n, "name");
    Printf(out, "class %s;\n", name);
    return SWIG_OK;
  }

};

extern "C" Language* swig_g() { return new G(); }

