/*
 * $Id: ogr_ruby.i 9022 2006-01-17 04:42:16Z cfis $
 *
 * ruby specific code for ogr bindings.
 */

/*
 * $Log$
 * Revision 1.4  2006/01/17 04:42:16  cfis
 * Added some renames that are not covered by -autorename since they start with the text OGR.
 *
 * Revision 1.3  2005/09/26 08:18:21  cfis
 * Moved renames to typemaps_ruby.i.  Now %include typemaps_ruby.i instead of %import (we want to inline the code).
 *
 * Revision 1.2  2005/09/18 07:34:58  cfis
 * Added support for exceptions, removed some outdated code.
 *
 * Revision 1.1  2005/09/02 16:19:23  kruland
 * Major reorganization to accomodate multiple language bindings.
 * Each language binding can define renames and supplemental code without
 * having to have a lot of conditionals in the main interface definition files.
 *
 */

/* Include default Ruby typemaps */
%include typemaps_ruby.i

/* Include exception handling code */
%include cpl_exceptions.i

/* Setup a few renames */
%rename(get_driver_count) OGRGetDriverCount;
%rename(get_open_dscount) OGRGetOpenDSCount;
%rename(set_generate_db2_v72_byte_order) OGRSetGenerate_DB2_V72_BYTE_ORDER;
%rename(register_all) OGRRegisterAll;


%init %{

  if ( OGRGetDriverCount() == 0 ) {
    OGRRegisterAll();
  }

  /* Setup exception handling */
  UseExceptions();
%}

/* Replace GetLayerByIndex and GetLayerByName by GetLayer */
%ignore OGRDataSourceShadow::GetLayerByIndex;
%ignore OGRDataSourceShadow::GetLayerByName;

%extend OGRDataSourceShadow {

	OGRLayerShadow *GetLayer(VALUE whichLayer) {
		// get field index
		switch (TYPE(whichLayer)) {
			case T_STRING: {
				char* name = StringValuePtr(whichLayer);
				return OGR_DS_GetLayerByName(self, name);
				break;
			}
			case T_FIXNUM: {
				int index = NUM2INT(whichLayer);
				return OGR_DS_GetLayer(self, index);
				break;
			}
			default:
				SWIG_exception(SWIG_TypeError, "Value must be a string or integer.");
		}
	}

	/* Override the way that ReleaseResultSet is handled - we
	   want to apply a typemap that unlinks the layer from
		its underlying C++ object since this method destroys
		the C++ object */
//	%typemap(freearg) OGRLayerShadow *layer {
		/* %typemap(freearg) OGRLayerShadow *layer */
//		DATA_PTR(argv[0]) = 0;
//	}
  // void ReleaseResultSet(OGRLayerShadow *layer) {
    // OGR_DS_ReleaseResultSet(self, layer);
//   }
}

/* Extend the layers class by adding support for ruby enumerable mixin. */
%mixin OGRLayerShadow "Enumerable";

/* Replace GetNextFeature by each */
%ignore OGRDataSourceShadow::GetLayerByIndex;

%extend OGRLayerShadow {
	/*~OGRLayerShadow () {
		FreeResultSet();
	}

	%typemap(in) OGRDatasourceShadow *ds {
		SWIG_ConvertPtr($input, (void **) &$1, $1_descriptor, SWIG_POINTER_DISOWN);
	   rb_iv_set($input, "__swigtype__", self);
	}
   void ReleaseResultSet(OGRDatasourceShadow *ds, OGRLayerShadow *layer) {
     OGR_DS_ReleaseResultSet(self, layer);
   }
*/
	%newobject OGRLayerShadow::each;
	void each() {
		OGRFeatureShadow* feature = NULL;

 		while (feature = (OGRFeatureShadow*) OGR_L_GetNextFeature(self))
 		{
			/* Convert the pointer to a Ruby object.  Note we set the flag
		   to one manually to show this is a new object */
			VALUE object = SWIG_NewPointerObj((void *) feature, $descriptor(OGRFeatureShadow *), SWIG_POINTER_OWN);			

			/* Now invoke the block specified for this method. */
			rb_yield(object);
		}
  }
}

%extend OGRFeatureShadow {
	VALUE GetField(VALUE object) {
		VALUE result;

		int index;

		// get field index
		switch (TYPE(object)) {
			case T_STRING:
				index = OGR_F_GetFieldIndex(self, StringValuePtr(object));
				break;
			case T_FIXNUM:
				index = NUM2INT(object);
				break;
			default:
				SWIG_exception(SWIG_TypeError, "Value must be a string or integer.");
		}
		
		int count = OGR_F_GetFieldCount(self);
		
		if (index < 0 || index > count) {
			SWIG_exception(SWIG_IndexError, "Illegal field requested.");
		}

		// is the field unset?
	  if (!OGR_F_IsFieldSet(self, index)) {
	  	result = Qnil;
	  	return result;
	  }
	  
	  // get field type
    OGRFieldType field_type = (OGRFieldType) OGR_Fld_GetType(OGR_F_GetFieldDefnRef( self, index));

		switch (field_type) {
			case OFTInteger: {
				const int value = OGR_F_GetFieldAsInteger(self, index);
				result = INT2NUM(value);
				break;
			}

			case OFTIntegerList: {
				int len = 0;
				const int* list = OGR_F_GetFieldAsIntegerList(self, index, &len);
				
				result = rb_ary_new2(len);
				
		    for ( int i = 0; i < len; ++i, ++list ) {
					VALUE item = INT2NUM(*list);
		      rb_ary_store(result, item, i);
		    }
		    break;
			}

			case OFTReal: {
				const double value = OGR_F_GetFieldAsDouble(self, index);
				return rb_float_new(value);
				break;
			}

			case OFTRealList: {
				int len = 0;
				const double* list = OGR_F_GetFieldAsDoubleList(self, index, &len);
				
				result = rb_ary_new2(len);
				
		    for ( int i = 0; i < len; ++i, ++list ) {
					VALUE item = rb_float_new(*list);
		      rb_ary_store(result, item, i);
		    }
		    break;
			}

			case OFTString: {
				const char* value = (const char *) OGR_F_GetFieldAsString(self, index);
				return rb_str_new2(value);
				break;
			}

			case OFTStringList:
/*				int len3 = 0;
				const char** string_list = OGR_F_GetFieldAsStringList(self, index, &len);
				
				result = rb_ary_new2(len3);
				
		    for ( int i = 0; i < len; ++i, ++string_list ) {
					VALUE item = rb_str_new2(*string_list);
		      rb_ary_store(result, item, i);
		    }*/
		    result = Qnil;
		    break;
			default:
				SWIG_exception(SWIG_TypeError, "Unsupported field type.");
		}
	
		return result;		
	}        
}


