#!/usr/bin/perl
##
##	KML Driver Test, using Perl and OGR
##  written for GDAL/OGR v1.5
##
##	09Dec07  -bh
##

## -- If you want to use development libraries, add the path here
#use lib '/Users/Shared/srcs/gdal_trunk/swig/perl/blib/lib';
#use lib '/Users/Shared/srcs/gdal_trunk/swig/perl/blib/arch';
use Geo::Ogr;

##==========================================================
## main program

my $dstFilename = 'tmp/tKML' . rand(100) . '.kml';

my $driver = Geo::OGR::GetDriverByName( 'KML' )
	or die( "Cant open driver KML $! $@" );
my $datasource = $driver->CreateDataSource( "/Users/Shared/srcs/ogrTutorial/$dstFilename" ) 
	or die( "Cant open file $! $@" );

##---------------------------
## Now, make a few new layers
	newGeom_Point();
	newGeom_Polygon();
	newGeom_Point25D();
	newGeom_LineString();
	newGeom_Unknown();


exit(0);

##==========================================================
##-- Supported Layer Types --
	#Point
	#Polygon
	#LineString
	#Unknown
	
## -- Unsupported Layer Types --
	#MultiPoint		MultiPolygon		MultiLineString
	#Point25D		Polygon25D			LineString25D
	#MultiPoint25D	MultiPolygon25D		MultiLineString25D
	
##==========================================================
sub newGeom_Point {
	my ($tPt, $tStr, $type, $feature); 

	## Create a Layer.. 
	##  the first param shows up as the Folder Name in KML
	$type = 'Point';
	my $layer = $datasource->CreateLayer( ($type . '_layer'), undef, $type );
	$feature = new Geo::OGR::Feature( $layer->GetLayerDefn() );
	#my $dRef = $feature->GetDefnRef();
	#print $dRef->GetGeomType();

	##---------------------------------------------------------
	## SetField(0,x) will set the KML Name of this feature
	$feature->SetField( 'Name', "Remarkably Remote Rest Stop" );	
	## SetField(1,x) will set the KML Description of this feature
	## the description will generally accept minimal HTML, 
	##  if escaped with CDATA. XML special chars will be escaped for you
	##  but this seems buggy right now.. see below for another example
	$feature->SetField( 'Description', "top doggy" );
	# this had problems for me
	#$feature->SetField( 1, "top <doggy>" );	
	
	## now create a new geometry from WKT
	$tStr = 'POINT(' . (rand() - 122.0) . ' ' . (rand() + 35.0) . ')';
	$tPt = Geo::OGR::CreateGeometryFromWkt( $tStr );
	#print $tPt->ExportToWkt( );

	# associate the geometry with the Feature
	$feature->SetGeometry( $tPt );
	# add the feature to the layer
	$layer->CreateFeature( $feature);
	#write to disk
	$layer->SyncToDisk;
	
	# done with this Feature now
	$feature->DESTROY();
	
	##---------------------------------------------------------
	# Make another feature
	$feature = new Geo::OGR::Feature( $layer->GetLayerDefn() );
	$feature->SetField( 'Name', "Purposefull Point" );	
	$feature->SetField( 'Description', "how can this be a useful description?" );	
	
	my $tPt2 =  Geo::OGR::Geometry->new( $Geo::OGR::wkbPoint );
	# Make a new Geometry as an object, then AddPoint()
	$tPt2->AddPoint( rand() - 122.0, rand() + 35.0  );
	#write it to the Layer
	writeGeom( $tPt2, $feature, $layer );

	# Now use the same feature, but make a new geometry via create()
	my $tPt3 =  Geo::OGR::Geometry->create( $type );
	# AddPoint again
	$tPt3->AddPoint( rand() - 122.0, rand() + 35.0  );
	#write it to the layer, notice the Name and Decription are repeated
	writeGeom( $tPt3, $feature, $layer );
	
	# done with this Feature now
	$feature->DESTROY();
	
	##---------------------------------------------------------
	# Last feature
	$feature = new Geo::OGR::Feature( $layer->GetLayerDefn() );
	$feature->SetField( 'Name', "Google Summer of Coder" );	

	# a try at complicated HTML content.. needs work
my $descStr = <<END0;
<![CDATA[<b>Name:</b> <i>Erik Pukinskis</i><br />
      <b>Description:</b> <i>Working on... &lt;br /&gt; 
      &lt;i&gt;<a href=http://code.google.com/soc/abisource/about.html>abi</a><br />]]>
END0
	$feature->SetField( 'Description', $descStr );	
	
	my $tPt2 =  Geo::OGR::Geometry->new( $Geo::OGR::wkbPoint );
	# Make a new Geometry as an object, then AddPoint()
	$tPt2->AddPoint( -117.1610543131828, 32.74625975767101  );
	#write it to the Layer
	writeGeom( $tPt2, $feature, $layer );
	
	# Perl interfaces will auto-dispose any object with local scope
	return;

	## other confusing stuff from the Perl interfaces
	#my $tFtrDef = new Geo::OGR::FeatureDefn( "Homer" );
	#$tFtrDef->Schema(
	#	Fields=>[Geo::OGR::FieldDefn->create( Name=>'OneName',Description=>'desc')]);
	# not at all the right call next
	#$tFtrDef->AddFieldDefn( "Name", "fred" );
}

##-------------------------------------------------------------------------
## newGeom_Point25D -  make a 25D point in a POINT layer.. 
##  write out to KML and notice the 25D point is intact. 
##  KML doesnt care about mixing 25D and others.. Other OGR drivers might.
##  NOTE: still finding out new ways to manipulate Geometry, so 
##  suggestions are welcome.. 

sub newGeom_Point25D {
	my ($tPt, $tStr, $type); 

	$type = 'Point';
	my $layer = $datasource->CreateLayer( ($type . '_layer'), undef, $type );
	my $feature = new Geo::OGR::Feature( $layer->GetLayerDefn() );
	
	#my $dRef = $feature->GetDefnRef();
	#print $dRef->GetGeomType();
	
	## This works, 25D with WKT
	$tStr = 'POINT(' . (rand() - 122.0) . ' ' . (rand() + 35.0) . ' ' . 155 . ')';
	$tPt = Geo::OGR::CreateGeometryFromWkt( $tStr );
	#print $tPt->ExportToWkt( );
	writeGeom( $tPt, $feature, $layer );

	# another Geometry object
	my $tPt2 =  Geo::OGR::Geometry->new( $Geo::OGR::wkbPoint );
	$tPt2->AddPoint( rand() - 122.0, rand() + 35.0 );
	##  AddPoint() doesnt like 25D, fails.. 
	#$tPt2->AddPoint( rand() - 120.0, rand() + 35.0, 155 );
	writeGeom( $tPt2, $feature, $layer );

	my $tPt3 =  Geo::OGR::Geometry->create( $type );
	$tPt3->AddPoint( rand() - 122.0, rand() + 35.0 );
	##  AddPoint() doesnt like 25D, fails.. 
	#$tPt3->AddPoint( rand() - 110.0, rand() + 35.0, 155  );
	writeGeom( $tPt3, $feature, $layer );
	
	return;
}

##----------------------
sub newGeom_Unknown {
	my ($tPt, $tStr, $type); 

	$type = 'Unknown';
	my $layer = $datasource->CreateLayer( ($type . '_layer'), undef, $type );
	if ( $@ ) { print $@; }
	my $feature = new Geo::OGR::Feature( $layer->GetLayerDefn() );
	if ( $@ ) { print $@; }

	## try adding a LineString
	my $limit = int(rand(3)) + 1;
	my ($tNewPtX,$tNewPtY);
	$tNewPtX = (rand() - 118.0);
	$tNewPtY = (rand() + 32.0);
	$tStr = 'LINESTRING(' . $tNewPtX . ' ' . $tNewPtY . ', ';
	for ( 0..$limit ) {
		$tStr .=  ($tNewPtX + rand()) . ' ' . ($tNewPtY + rand()) . ',';
	}
	chop $tStr;
	$tStr .= ')';
	$tPt = Geo::OGR::CreateGeometryFromWkt( $tStr );
	#print $tPt->ExportToWkt( );
	writeGeom( $tPt, $feature, $layer );
	
	$feature->DESTROY();

	## and now a Point
	$feature = new Geo::OGR::Feature( $layer->GetLayerDefn() );

	# Set the Name and Description fields
	$feature->SetField( 'Name', "All Mixed Content Point" );	
	$feature->SetField( 'Description', "draw it as I see it" );	
	
	my $tPt2 =  Geo::OGR::Geometry->new( $Geo::OGR::wkbPoint );
	# Make a new Geometry as an object, then AddPoint()
	$tPt2->AddPoint( -118.00, 32.78  );
	#write it to the Layer
	writeGeom( $tPt2, $feature, $layer );
	
	return;
}
	
##----------------------
sub newGeom_LineString {
	my ($tPt, $tStr, $type); 

	$type = 'LineString';
	my $layer = $datasource->CreateLayer( ($type . '_layer'), undef, $type );
	if ( $@ ) { print $@; }
	my $feature = new Geo::OGR::Feature( $layer->GetLayerDefn() );
	if ( $@ ) { print $@; }
	
	#my $dRef = $feature->GetDefnRef();
	#print $dRef->GetGeomType();
	
	## make the feature comments now
	$feature->SetField( 'Name', "Long path to nowhere" );
	## xml escape chars translate correctly in the display
	$feature->SetField( 'Description', "If the &lt;tessellate&gt; tag has a value of 0, the line follows a simple straight-line path from point to point" );	

	my $limit = int(rand(10)) + 1;
	my ($tNewPtX,$tNewPtY);
	$tNewPtX = (rand() - 122.0);
	$tNewPtY = (rand() + 35.0);
	$tStr = 'LINESTRING(' . $tNewPtX . ' ' . $tNewPtY . ', ';
	for ( 0..$limit ) {
		$tStr .=  ($tNewPtX + rand()) . ' ' . ($tNewPtY + rand()) . ',';
	}
	chop $tStr;
	$tStr .= ')';
	$tPt = Geo::OGR::CreateGeometryFromWkt( $tStr );
	#print $tPt->ExportToWkt( );
	writeGeom( $tPt, $feature, $layer );
	
	return;
}

##--------------------------------------------------------------------------
## newGeom_Polygon - make a Polygon Layer and sample geometry
## TODO: figure out how to set the LineStyle and PolyStyle on the Polygon
sub newGeom_Polygon {
	my ($tPt, $tStr, $type); 

	$type = 'Polygon';
	my $layer = $datasource->CreateLayer( ($type . '_layer'), undef, $type );
	my $feature = new Geo::OGR::Feature( $layer->GetLayerDefn() );
	
	#my $dRef = $feature->GetDefnRef();
	#print $dRef->GetGeomType();
	
	$tStr = 'POLYGON((';
	my $tOrigLat = (rand(2) + 35.0);
	my $tOrigLon = (rand(2) - 122.0);
	$tStr .= $tOrigLon . ' ' . $tOrigLat . ', ';
	for (1..3) {
		$tStr .= (rand(2) - 122.0) . ' ' . (rand(2) + 35.0) . ',';
	}
	$tStr .= $tOrigLon . ' ' . $tOrigLat . ' ';
	$tStr .= '))';
	$tPt = Geo::OGR::CreateGeometryFromWkt( $tStr );
	#print $tPt->ExportToWkt( );
	writeGeom( $tPt, $feature, $layer );
}

##=========================================================================
## some misc support subs

sub writeGeom {
	my ($geom,$feature,$layer) = @_;
	
	$feature->SetGeometry( $geom );
	$layer->CreateFeature( $feature);
	$layer->SyncToDisk;
}

##-------------
sub printAllTypes {
	my @types = Geo::OGR::GeometryType();
	
	my @tmp = @types;
	@types = ();
	# filter out a few of the types
	for (@tmp) {
		#next if /25/;
		next if /Ring/;
		next if /None/;
		push @types, $_;
	}
	print @types;
	exit(0);
}
