#!/usr/bin/env ruby

# These tests require a postgresql database called autotest that
# has PostGIS installed.  Please see ogr_pg.py for more info.

require 'test/unit'
require 'gdal/ogr'
require 'ogrtest'


class TestOgrPg < Test::Unit::TestCase
  def setup
 		driver = Gdal::Ogr.get_driver_by_name( 'PostgreSQL' )
		@pg_ds = driver.open( 'PG:dbname=autotest user=postgres', 1 )
	end   
		
	def teardown
    @pg_ds.execute_sql( 'DELLAYER:tpoly' )
	  @pg_ds = nil
	end 

 	## Write more features with a bunch of different geometries.
	def create_features_from_file
    pg_lyr = @pg_ds.get_layer(0)
    dst_feat = Gdal::Ogr::Feature.new( feature_def = pg_lyr.get_layer_defn() )
    
		wkt_list = [ '10', '2', '1', '3d_1', '4', '5', '6' ]
    wkt = nil
    
    wkt_list.each do |item|
      file_name = File.join('..', '..','ogr','data','wkb_wkt',item + '.wkt')
			File.open(file_name, 'rb') do |file|
			  wkt = file.read
			end
		
			geom = Gdal::Ogr.create_geometry_from_wkt( wkt )
        
			## Write geometry as a new Postgis feature.
			dst_feat.set_geometry_directly( geom )
			dst_feat.set_field( 'PRFEDEA', item )
			pg_lyr.create_feature( dst_feat )
		end
	end

  def create_crazy_key
		pg_lyr = @pg_ds.get_layer(0)
		dst_feat = Gdal::Ogr::Feature.new( feature_def = pg_lyr.get_layer_defn() )

    dst_feat.set_field( 'PRFEDEA', 'CrazyKey' )
    dst_feat.set_field( 'SHORTNAME', 'Crazy"\'Long' )
    pg_lyr.create_feature( dst_feat )
  end

	# Open database
	def test_open_database()
	  assert_not_nil(@pg_ds, "Could not open Postgis database.")
 		pg_lyr = create_poly_layer(@pg_ds)
	end

	# Verify that stuff we just wrote is still OK.
	def test_features()
 		pg_lyr = create_poly_layer(@pg_ds)
 		feat = populate_poly_layer(pg_lyr)
 		check_poly_layer(pg_lyr, feat)
	end								 

	# Write more features with a bunch of different geometries, and verify the
	# geometries are still OK.
	def test_create_features
	  pg_lyr = create_poly_layer(@pg_ds)
	  create_features_from_file
 		
    wkt_list = [ '10', '2', '1', '3d_1', '4', '5', '6' ]
    
   	wkt_list.each do |item|
      pg_lyr.set_attribute_filter( "PRFEDEA='#{item}'")
      assert_equal(1, pg_lyr.get_feature_count, 
                   "Incorrect number of features returned.")
      
      pg_lyr.set_attribute_filter( "")
      feat_read = pg_lyr.get_next_feature()
      assert_not_nil(feat_read)
      
			geom_read = feat_read.get_geometry_ref()
			
			assert(check_feature_geometry( feat_read, geom_read ))
		end
	end
    
	# Test ExecuteSQL() results layers with geometry.
	def test_release_resultset()
 		pg_lyr = create_poly_layer(@pg_ds)
 		populate_poly_layer(pg_lyr)
	  
	  sql_lyr = @pg_ds.execute_sql( "select * from tpoly" )
	  assert_equal(10, sql_lyr.get_feature_count)

	  feat = sql_lyr.get_next_feature
	  assert_not_nil(feat, "Feature should not be nil")

	  # Must free the feature before the layer
	  feat = nil
	  GC.start
	  
    @pg_ds.release_result_set( sql_lyr )
  end
  
  def test_release_resultset2()
    # This test just runs test_release_resultset again. The reason
    # is that running the tests twice reveals segmentation faults.
    test_release_resultset
  end
  
	# Test ExecuteSQL() results layers without geometry.
	def test_execute_sql_no_geom()
	  pg_lyr = create_poly_layer(@pg_ds)
		populate_poly_layer(pg_lyr)

  	driver = Gdal::Ogr.get_driver_by_name( 'PostgreSQL' )
		pg_ds = driver.open( 'PG:dbname=autotest user=postgres', 1 )

		expect = [ 179, 173, 172, 171, 170, 169, 168, 166, 165, 158 ]
   	sql_lyr = pg_ds.execute_sql( 'select distinct eas_id from tpoly order by eas_id desc' )

   	assert(check_features_against_list( sql_lyr, 'eas_id', expect ))

	  # Release the resultset  
    pg_ds.release_result_set( sql_lyr )
	end

	# Test ExecuteSQL() results layers with geometry.
	def test_execute_sql_with_geom()
	  pg_lyr = create_poly_layer(@pg_ds)
	  create_features_from_file
	  
		sql_lyr = @pg_ds.execute_sql( "select * from tpoly where prfedea = '2'" )
		assert_equal(1, sql_lyr.get_feature_count, "Wrong number of features returned.")

		assert(check_features_against_list( sql_lyr, 'prfedea', [ '2' ] ))
		sql_lyr.reset_reading

		sql_lyr.each do |feat|
		  assert(check_feature_geometry( feat, 'MULTILINESTRING ((5.00121349 2.99853132,5.00121349 1.99853133),(5.00121349 1.99853133,5.00121349 0.99853133),(3.00121351 1.99853127,5.00121349 1.99853133),(5.00121349 1.99853133,6.00121348 1.99853135))' ))
		end
		
    ## Must do a gc to get rid of features created in check_features_against_list
    ## Otherwise, we'll get a segmentation fault when we call release_result_set.
    GC.start
		@pg_ds.release_result_set( sql_lyr )
	end
	
	# Test spatial filtering. 
	def test_spatial_filtering()
	  pg_lyr = create_poly_layer(@pg_ds)
	  populate_poly_layer(pg_lyr)
	  
		pg_lyr.set_attribute_filter( "" )
    
    geom = Gdal::Ogr.create_geometry_from_wkt('LINESTRING(479505 4763195,480526 4762819)')
    pg_lyr.set_spatial_filter( geom )
    
		assert(check_features_against_list(pg_lyr, 'eas_id', [ 158 ] ))
		

    pg_lyr.set_spatial_filter( nil )
	end
	  

	# Write a feature with too long a text value for a fixed length text field.
	# The driver should now truncate this (but with a debug message).  Also,
	# put some crazy stuff in the value to verify that quoting and escaping
	# is working smoothly.
	# No geometry in this test.

	def test_long_text()
	  pg_lyr = create_poly_layer(@pg_ds)
		create_crazy_key
    
 		pg_lyr.set_attribute_filter( "PRFEDEA = 'CrazyKey'" )
    feat_read = pg_lyr.get_next_feature()

    assert_not_nil(feat_read, 'creating crazy feature failed!' )

    short_name = feat_read.get_field('shortname') 
    assert_equal('Crazy"\'L', short_name,
							   "Value not properly escaped or truncated: #{short_name}")
	end
    
	## Verify inplace update of a feature with SetFeature().
	def test_verify_inplace_edit
	  pg_lyr = create_poly_layer(@pg_ds)
	  create_crazy_key
	  
		pg_lyr.set_attribute_filter( "PRFEDEA = 'CrazyKey'" )
    feat = pg_lyr.get_next_feature()
    pg_lyr.set_attribute_filter( "" )

    feat.set_field( 'SHORTNAME', 'Reset' )

    point = Gdal::Ogr::Geometry.new(Gdal::Ogr::WkbPoint25D)
    point.set_point( 0, 5, 6, 7 )
    feat.set_geometry_directly( point )

    assert(pg_lyr.set_feature( feat ),
					 'SetFeature() method failed.' )

    fid = feat.get_fid()
		feat = pg_lyr.get_feature(fid)
    assert_not_nil(feat, "GetFeature(#{fid}) failed.")

    shortname = feat.get_field( 'SHORTNAME' )
    shortname = shortname[0..4]
    assert_equal('Reset', shortname, 
                 "SetFeature() did not update SHORTNAME, got #{shortname}")

    assert(check_feature_geometry( feat, 'POINT(5 6 7)' ))
  end

	# Verify that DeleteFeature() works properly.
	def test_delete_feature()
	  pg_lyr = create_poly_layer(@pg_ds)
	  create_crazy_key
	  
		pg_lyr.set_attribute_filter( "PRFEDEA = 'CrazyKey'" )

	  feat = pg_lyr.get_next_feature()
		assert_not_nil(feat, "Could not find feature")
 	  pg_lyr.set_attribute_filter( "" )
 	  fid = feat.get_fid()

    assert(pg_lyr.delete_feature( fid ),
          'DeleteFeature() method failed.' )

		pg_lyr.set_attribute_filter( "PRFEDEA = 'CrazyKey'" )
    feat = pg_lyr.get_next_feature()
    assert_nil(feat, 'DeleteFeature() seems to have had no effect.' )
    pg_lyr.set_attribute_filter("")
  end
end
