#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#include <stdio.h>
#include <string.h>
#include <errno.h>

#include "escheme.h"

struct stat buf;

#include "generated-choose.i"

static Scheme_Object *ext_stat(int argc, Scheme_Object **argv) {
	int is_path = SCHEME_PATHP(argv[0]);
	int i;
	if (!is_path && !(
		SCHEME_INPUT_PORTP(argv[0]) ||
		SCHEME_OUTPUT_PORTP(argv[0])))
		scheme_wrong_type(
				"stat",
				"path or port",
				0,
				argc,
				argv);

	if (!SCHEME_VECTORP(argv[1])) {
		scheme_wrong_type(
				"stat",
				"vector",
				1,
				argc,
				argv);
	}
	
	Scheme_Object** flags = SCHEME_VEC_ELS(argv[1]);
	ssize_t len = SCHEME_VEC_SIZE(argv[1]);

	for(i=0;i<len;++i) {
		if (!SCHEME_INTP(flags[i])) {
			scheme_wrong_type(
					"stat",
					"vector of integers",
					1,
					argc,
					argv);
		}	
	}

	if (is_path) {
		char* name;
		name = SCHEME_PATH_VAL(argv[0]);
		if(0!=lstat(name,&buf)) 
			scheme_signal_error("stat failed on '%s': %s",name,strerror(errno));
	} else {
		long fd;
		if(scheme_get_port_file_descriptor(argv[0],&fd)==0)
			scheme_wrong_type(
				"stat",
				"port has no file descriptor",
				0,
				argc,
				argv);

		if(0!=fstat(fd,&buf)) 
			scheme_signal_error("fstat failed %s",strerror(errno));
		
	}

	Scheme_Object** values = alloca(len*sizeof(Scheme_Object*));

    MZ_GC_DECL_REG(0);
	MZ_GC_REG();
  
	for(i=0;i<len;++i) {
		short val = SCHEME_INT_VAL(flags[i]);
		values[i] = scheme_make_integer_value_from_unsigned(choose(val));
	}

	Scheme_Object* result = scheme_values(len,values);

	MZ_GC_UNREG();

	return result;

}


Scheme_Object *scheme_reload(Scheme_Env *env)
{
  Scheme_Object *proc;

  proc = scheme_make_prim_w_arity(ext_stat, "stat", 1, 2);

  return proc;
}

Scheme_Object *scheme_initialize(Scheme_Env *env)
{
  return scheme_reload(env);
}

Scheme_Object *scheme_module_name()
{
  return scheme_false;
}
