[mapguide-commits] r5374 - in sandbox/maestro-3.0: MaestroAPITests OSGeo.MapGuide.MaestroAPI OSGeo.MapGuide.MaestroAPI/Mapping OSGeo.MapGuide.MaestroAPI/ObjectModels OSGeo.MapGuide.MaestroAPI/Serialization OSGeo.MapGuide.MaestroAPI/Services OSGeo.MapGuide.MaestroAPI.Http OSGeo.MapGuide.MaestroAPI.Native

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Fri Nov 5 06:17:38 EDT 2010


Author: jng
Date: 2010-11-05 03:17:38 -0700 (Fri, 05 Nov 2010)
New Revision: 5374

Added:
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Mapping/MapObservable.cs
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Mapping/MapSelection.cs
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Mapping/RuntimeMap.cs
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Mapping/RuntimeMapGroup.cs
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Mapping/RuntimeMapLayer.cs
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/Geometries.cs
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Serialization/IBinarySerializable.cs
Removed:
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Mapping/MapSelectionBase.cs
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Mapping/RuntimeLayerBase.cs
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Mapping/RuntimeMapBase.cs
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Serialization/IBinarySerializeable.cs
Modified:
   sandbox/maestro-3.0/MaestroAPITests/ExpressionTests.cs
   sandbox/maestro-3.0/MaestroAPITests/MaestroAPITests.csproj
   sandbox/maestro-3.0/MaestroAPITests/RuntimeMapTests.cs
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI.Http/HttpServerConnection.cs
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI.Http/RequestBuilder.cs
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI.Native/LocalNativeConnection.cs
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ConnectionProviderRegistry.cs
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/MgServerConnectionBase.cs
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/OSGeo.MapGuide.MaestroAPI.csproj
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/Envelope.cs
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/MapDefinition.cs
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/MapDefinitionInterfaces.cs
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/ObjectFactory.cs
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/WebLayout.cs
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/PlatformConnectionBase.cs
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Serialization/MgBinaryDeserializer.cs
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Serialization/MgBinarySerializer.cs
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Services/IMappingService.cs
Log:
3.0 sandbox changes:
 - First phase of porting runtime map API from 2.x w/ unit tests. These tests currently fail (in the sense that the rendered image result is not what is intended)


Modified: sandbox/maestro-3.0/MaestroAPITests/ExpressionTests.cs
===================================================================
--- sandbox/maestro-3.0/MaestroAPITests/ExpressionTests.cs	2010-11-05 08:34:47 UTC (rev 5373)
+++ sandbox/maestro-3.0/MaestroAPITests/ExpressionTests.cs	2010-11-05 10:17:38 UTC (rev 5374)
@@ -79,6 +79,8 @@
 
             Assert.IsTrue(exprReader.Read());
 
+            Thread.Sleep(50);
+
             var dt1 = exprReader.Evaluate("CurrentDate()");
             Assert.NotNull(dt1);
             Trace.WriteLine("dt1: " + dt1.ToString());

Modified: sandbox/maestro-3.0/MaestroAPITests/MaestroAPITests.csproj
===================================================================
--- sandbox/maestro-3.0/MaestroAPITests/MaestroAPITests.csproj	2010-11-05 08:34:47 UTC (rev 5373)
+++ sandbox/maestro-3.0/MaestroAPITests/MaestroAPITests.csproj	2010-11-05 10:17:38 UTC (rev 5374)
@@ -12,6 +12,21 @@
     <AssemblyName>MaestroAPITests</AssemblyName>
     <TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
     <FileAlignment>512</FileAlignment>
+    <PublishUrl>publish\</PublishUrl>
+    <Install>true</Install>
+    <InstallFrom>Disk</InstallFrom>
+    <UpdateEnabled>false</UpdateEnabled>
+    <UpdateMode>Foreground</UpdateMode>
+    <UpdateInterval>7</UpdateInterval>
+    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+    <UpdatePeriodically>false</UpdatePeriodically>
+    <UpdateRequired>false</UpdateRequired>
+    <MapFileExtensions>true</MapFileExtensions>
+    <ApplicationRevision>0</ApplicationRevision>
+    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+    <IsWebBootstrapper>false</IsWebBootstrapper>
+    <UseApplicationTrust>false</UseApplicationTrust>
+    <BootstrapperEnabled>true</BootstrapperEnabled>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <DebugSymbols>true</DebugSymbols>
@@ -41,6 +56,7 @@
     </Reference>
     <Reference Include="System" />
     <Reference Include="System.Data" />
+    <Reference Include="System.Drawing" />
     <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
@@ -75,8 +91,219 @@
   </ItemGroup>
   <ItemGroup>
     <None Include="Resources\SelectSqlSample.xml" />
+    <None Include="TestData\DrawingService\CorruptedDwf.dwf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\DrawingService\DrawingServiceTest.dump">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\DrawingService\SpaceShip.dwf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\DrawingService\test.dwf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\FeatureService\FeatureServiceTest.dump">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\FeatureService\SDF\Empty.FeatureSource">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\FeatureService\SDF\Sheboygan_BuildingOutlines.FeatureSource">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\FeatureService\SDF\Sheboygan_Parcels.FeatureSource">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\FeatureService\SDF\Sheboygan_VotingDistricts.FeatureSource">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\FeatureService\SDF\TEST.FeatureSource">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\FeatureService\SDF\TESTChainedInner1ToManyJoin.FeatureSource">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\FeatureService\SHP\Redding_Parcels.dbf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\FeatureService\SHP\Redding_Parcels.FeatureSource">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\FeatureService\SHP\Redding_Parcels.shp">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\FeatureService\SHP\Redding_Parcels.shx">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\MapLayer\Cities.LayerDefinition">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\MapLayer\MapLayerTest.dump">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\MapLayer\World countries.LayerDefinition">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\MapLayer\World.MapDefinition">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\MappingService\MappingServiceTest.dump">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\MappingService\UT_AllElements.pl">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\MappingService\UT_HydrographicPolygons.fs">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\MappingService\UT_NoLegend.pl">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\MappingService\UT_PoweredByMapGuide.wdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\MappingService\UT_Rail.fs">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\MappingService\UT_SymbolMart.sl">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\MappingService\UT_Symbols.dwf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\MdfModel\MdfTestCompoundSymbol.sd">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\MdfModel\MdfTestSimpleSymbol.sd">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\ResourceService\d1.DrawingSource">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\ResourceService\d2.DrawingSource">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\ResourceService\r1.FeatureSource">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\ResourceService\ResourceServiceTest.dump">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\ResourceService\Shuttle.zip">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\ResourceService\Shuttle_Corrupted.zip">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\ResourceService\TEST.LayerDefinition">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\ResourceService\WesternEuropean.FeatureSource">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\ResourceService\Westernéuropèàn.FeatureSource">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\ServerAdmin\1.1.1.mgd">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\ServerAdmin\ServerAdminTest.dump">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\SiteService\SiteServiceTest.dump">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\Symbology\areasymbol.sd">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\Symbology\linesymbol.sd">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\Symbology\MTYP1500a.sd">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\Symbology\symbol.sd">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\Symbology\symbolp.sd">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\Symbology\UT_SymbologyLines.fs">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\Symbology\UT_SymbologyPoints.fs">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\Symbology\UT_SymbologyRoads.fs">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\TileService\UT_Parcels.fs">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\TileService\UT_RoadCenterLines.fs">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\TileService\UT_VotingDistricts.fs">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\Unicode\Sample_World_Unicode.FeatureSource">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\Unicode\Sample_World_Unicode.LayerDefinition">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\Unicode\Sample_World_Unicode.MapDefinition">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\Unicode\Sample_World_Unicode.WebLayout">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\Unicode\UnicodeTest.dump">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\WebLayout\Test.WebLayout">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\WebLayout\WebLayoutTest.dump">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\Wfs\WfsTest.dump">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="TestData\Wms\WmsTest.dump">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
   </ItemGroup>
   <ItemGroup>
+    <ProjectReference Include="..\ExtendedModels\LayerDefinition-1.1.0\OSGeo.MapGuide.ObjectModels.LayerDefinition-1.1.0.csproj">
+      <Project>{B5EA049C-6AB7-4686-A2F4-4BA2EAC0E585}</Project>
+      <Name>OSGeo.MapGuide.ObjectModels.LayerDefinition-1.1.0</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\ExtendedModels\LayerDefinition-1.2.0\OSGeo.MapGuide.ObjectModels.LayerDefinition-1.2.0.csproj">
+      <Project>{EDDB0F74-6FE7-4969-80B0-817A629722CD}</Project>
+      <Name>OSGeo.MapGuide.ObjectModels.LayerDefinition-1.2.0</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\ExtendedModels\LayerDefinition-1.3.0\OSGeo.MapGuide.ObjectModels.LayerDefinition-1.3.0.csproj">
+      <Project>{AC5068F6-CFBE-4BCD-B68B-062725E424D4}</Project>
+      <Name>OSGeo.MapGuide.ObjectModels.LayerDefinition-1.3.0</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\ExtendedModels\LoadProcedure-1.1.0\OSGeo.MapGuide.ObjectModels.LoadProcedure-1.1.0.csproj">
+      <Project>{B2A1F69E-52AA-42A2-8DED-89ADB9B14A38}</Project>
+      <Name>OSGeo.MapGuide.ObjectModels.LoadProcedure-1.1.0</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\ExtendedModels\LoadProcedure-2.2.0\OSGeo.MapGuide.ObjectModels.LoadProcedure-2.2.0.csproj">
+      <Project>{D525B343-66D6-4D6B-9A55-78A173D94A51}</Project>
+      <Name>OSGeo.MapGuide.ObjectModels.LoadProcedure-2.2.0</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\ExtendedModels\SymbolDefinition-1.1.0\OSGeo.MapGuide.ObjectModels.SymbolDefinition-1.1.0.csproj">
+      <Project>{BF6E996E-27AF-44CD-B3CF-A40874E15B2E}</Project>
+      <Name>OSGeo.MapGuide.ObjectModels.SymbolDefinition-1.1.0</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\ExtendedModels\WebLayout-1.1.0\OSGeo.MapGuide.ObjectModels.WebLayout-1.1.0.csproj">
+      <Project>{0A93ACA8-5B21-44E6-B0B7-5D1E72D3A6A2}</Project>
+      <Name>OSGeo.MapGuide.ObjectModels.WebLayout-1.1.0</Name>
+    </ProjectReference>
     <ProjectReference Include="..\OSGeo.MapGuide.MaestroAPI.Http\OSGeo.MapGuide.MaestroAPI.Http.csproj">
       <Project>{6EF1E775-444B-4E5F-87FB-D687C43A68D7}</Project>
       <Name>OSGeo.MapGuide.MaestroAPI.Http</Name>
@@ -90,6 +317,281 @@
       <Name>OSGeo.MapGuide.MaestroAPI</Name>
     </ProjectReference>
   </ItemGroup>
+  <ItemGroup>
+    <Content Include="TestData\CoordinateSystems\epsgcodes.txt">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\CoordinateSystems\ogcwkts.txt">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\CoordinateSystems\ogcwkts_original.txt">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\DrawingService\InvalidDrawingSource.xml">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\DrawingService\MapGuideDrawingSource.xml">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\DrawingService\SpaceShipDrawingSource.xml">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\FeatureService\SDF\Empty.sdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\FeatureService\SDF\Sheboygan_BuildingOutlines.sdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\FeatureService\SDF\Sheboygan_CityLimits.sdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\FeatureService\SDF\Sheboygan_Parcels.sdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\FeatureService\SDF\Sheboygan_VotingDistricts.sdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\FeatureService\SDF\TEST.sdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\KmlService\UT_GetFeaturesKMLResult.txt">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\KmlService\UT_GetLayerKMLResult.txt">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\KmlService\UT_GetMapKMLResult.txt">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\MappingService\UT_HydrographicPolygons.ldf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\MappingService\UT_HydrographicPolygons.sdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\MappingService\UT_Rail.ldf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\MappingService\UT_Rail.sdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\MappingService\UT_Rail_Web.ldf">
+      <DependentUpon>UT_Rail_Web.mdf</DependentUpon>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\MappingService\UT_Rail_Web.mdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\MappingService\UT_Sheboygan.mdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\MappingService\UT_SheboyganWithWatermark.mdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\MdfModel\MdfTestMap.mdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\MdfModel\MdfTestTypeStyles.ldf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\PrintLayout\MapViewportSample1.xml">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\ResourceService\AdministratorCredentials.txt">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\ResourceService\Content2.xml">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\ResourceService\EmptyFile.xml">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\ResourceService\LibraryRepositoryContent.xml">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\ResourceService\SampleRepositoryContent.xml">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\ResourceService\SampleRepositoryHeader.xml">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\ResourceService\SampleResourceHeader.xml">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\ResourceService\Westernéuropèàn.sdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\ResourceService\World_Countries.sdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\Symbology\UT_Annotation1.ldf">
+      <DependentUpon>UT_Annotation1.mdf</DependentUpon>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\Symbology\UT_Annotation1.mdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\Symbology\UT_Annotation2.ldf">
+      <DependentUpon>UT_Annotation2.mdf</DependentUpon>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\Symbology\UT_Annotation2.mdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\Symbology\UT_Annotation3.ldf">
+      <DependentUpon>UT_Annotation3.mdf</DependentUpon>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\Symbology\UT_Annotation3.mdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\Symbology\UT_SymbologyLines.ldf">
+      <DependentUpon>UT_SymbologyLines.mdf</DependentUpon>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\Symbology\UT_SymbologyLines.mdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\Symbology\UT_SymbologyLines.sdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\Symbology\UT_SymbologyLinesCrossTick.ldf">
+      <DependentUpon>UT_SymbologyLinesCrossTick.mdf</DependentUpon>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\Symbology\UT_SymbologyLinesCrossTick.mdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\Symbology\UT_SymbologyParcels.ldf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\Symbology\UT_SymbologyPoints.ldf">
+      <DependentUpon>UT_SymbologyPoints.mdf</DependentUpon>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\Symbology\UT_SymbologyPoints.mdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\Symbology\UT_SymbologyPoints.sdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\Symbology\UT_SymbologyPointsParam.ldf">
+      <DependentUpon>UT_SymbologyPointsParam.mdf</DependentUpon>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\Symbology\UT_SymbologyPointsParam.mdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\Symbology\UT_SymbologyPolygons.mdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\Symbology\UT_SymbologyRoads.ldf">
+      <DependentUpon>UT_SymbologyRoads.mdf</DependentUpon>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\Symbology\UT_SymbologyRoads.mdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\Symbology\UT_SymbologyRoads.sdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\TileService\UT_BaseMap.mdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\TileService\UT_Parcels.ldf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\TileService\UT_Parcels.sdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\TileService\UT_RoadCenterLines.ldf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\TileService\UT_RoadCenterLines.sdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\TileService\UT_VotingDistricts.ldf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\TileService\UT_VotingDistricts.sdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\Unicode\Sample_World_Unicode.sdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\Wfs\Sheboygan_CityLimits.sdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\Wfs\Sheboygan_CityLimits_Content.xml">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\Wfs\Sheboygan_CityLimits_Header.xml">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\Wfs\Sheboygan_CityLimits_Layer_Content.xml">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\Wfs\Sheboygan_CityLimits_Layer_Header.xml">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\Wms\Sheboygan_CityLimits.sdf">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\Wms\Sheboygan_CityLimits_Content.xml">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\Wms\Sheboygan_CityLimits_Header.xml">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\Wms\Sheboygan_CityLimits_Layer_Content.xml">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="TestData\Wms\Sheboygan_CityLimits_Layer_Header.xml">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+  <ItemGroup>
+    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework Client Profile</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 2.0 %28x86%29</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.0">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.0 %28x86%29</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.SQL.Server.Compact.3.5">
+      <Visible>False</Visible>
+      <ProductName>SQL Server Compact 3.5</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Sql.Server.Express.9.2">
+      <Visible>False</Visible>
+      <ProductName>SQL Server 2005 Express Edition SP2 %28x86%29</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+      <Visible>False</Visible>
+      <ProductName>Windows Installer 3.1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
        Other similar extension points exist, see Microsoft.Common.targets.

Modified: sandbox/maestro-3.0/MaestroAPITests/RuntimeMapTests.cs
===================================================================
--- sandbox/maestro-3.0/MaestroAPITests/RuntimeMapTests.cs	2010-11-05 08:34:47 UTC (rev 5373)
+++ sandbox/maestro-3.0/MaestroAPITests/RuntimeMapTests.cs	2010-11-05 10:17:38 UTC (rev 5374)
@@ -21,11 +21,545 @@
 using System.Collections.Generic;
 using System.Text;
 using NUnit.Framework;
+using OSGeo.MapGuide.MaestroAPI;
+using System.IO;
+using OSGeo.MapGuide.ObjectModels.Common;
+using OSGeo.MapGuide.ObjectModels.MapDefinition;
+using OSGeo.MapGuide.MaestroAPI.Mapping;
+using OSGeo.MapGuide.MaestroAPI.Services;
 
 namespace MaestroAPITests
 {
+    using Ldf110 = OSGeo.MapGuide.ObjectModels.LayerDefinition_1_1_0;
+    using Ldf120 = OSGeo.MapGuide.ObjectModels.LayerDefinition_1_2_0;
+    using Ldf130 = OSGeo.MapGuide.ObjectModels.LayerDefinition_1_3_0;
+
+    using Lp110 = OSGeo.MapGuide.ObjectModels.LoadProcedure_1_1_0;
+    using Lp220 = OSGeo.MapGuide.ObjectModels.LoadProcedure_2_2_0;
+    using WL110 = OSGeo.MapGuide.ObjectModels.WebLayout_1_1_0;
+    using OSGeo.MapGuide.ObjectModels;
+    using OSGeo.MapGuide.MaestroAPI.Resource.Validation;
+    using OSGeo.MapGuide.MaestroAPI.Resource;
+    using OSGeo.MapGuide.ObjectModels.LoadProcedure;
+
+    [SetUpFixture]
+    public class TestBootstrap
+    {
+        [SetUp]
+        public void Setup()
+        {
+            //Layer Definition 1.1.0
+            ResourceValidatorSet.RegisterValidator(new Ldf110.LayerDefinitionValidator());
+            ResourceTypeRegistry.RegisterResource(
+                new ResourceTypeDescriptor(ResourceTypes.LayerDefinition, "1.1.0"),
+                new ResourceSerializationCallback(Ldf110.LdfEntryPoint.Serialize),
+                new ResourceDeserializationCallback(Ldf110.LdfEntryPoint.Deserialize));
+            ObjectFactory.RegisterLayerFactoryMethod(new Version(1, 1, 0), new LayerCreatorFunc(Ldf110.LdfEntryPoint.CreateDefault));
+
+            //Layer Definition 1.2.0
+            ResourceValidatorSet.RegisterValidator(new Ldf120.LayerDefinitionValidator());
+            ResourceTypeRegistry.RegisterResource(
+                new ResourceTypeDescriptor(ResourceTypes.LayerDefinition, "1.2.0"),
+                new ResourceSerializationCallback(Ldf120.LdfEntryPoint.Serialize),
+                new ResourceDeserializationCallback(Ldf120.LdfEntryPoint.Deserialize));
+            ObjectFactory.RegisterLayerFactoryMethod(new Version(1, 2, 0), new LayerCreatorFunc(Ldf120.LdfEntryPoint.CreateDefault));
+
+            //Layer Definition 1.3.0
+            ResourceValidatorSet.RegisterValidator(new Ldf130.LayerDefinitionValidator());
+            ResourceTypeRegistry.RegisterResource(
+                new ResourceTypeDescriptor(ResourceTypes.LayerDefinition, "1.3.0"),
+                new ResourceSerializationCallback(Ldf130.LdfEntryPoint.Serialize),
+                new ResourceDeserializationCallback(Ldf130.LdfEntryPoint.Deserialize));
+            ObjectFactory.RegisterLayerFactoryMethod(new Version(1, 3, 0), new LayerCreatorFunc(Ldf130.LdfEntryPoint.CreateDefault));
+
+            //Load Procedure 1.1.0
+            ResourceValidatorSet.RegisterValidator(new Lp110.LoadProcedureValidator());
+            ResourceTypeRegistry.RegisterResource(
+                new ResourceTypeDescriptor(ResourceTypes.LoadProcedure, "1.1.0"),
+                new ResourceSerializationCallback(Lp110.LoadProcEntryPoint.Serialize),
+                new ResourceDeserializationCallback(Lp110.LoadProcEntryPoint.Deserialize));
+
+            //Load Procedure 1.1.0 schema offers nothing new for the ones we want to support, so nothing to register
+            //with the ObjectFactory
+
+            //Load Procedure 2.2.0
+            ResourceValidatorSet.RegisterValidator(new Lp220.LoadProcedureValidator());
+            ResourceTypeRegistry.RegisterResource(
+                new ResourceTypeDescriptor(ResourceTypes.LoadProcedure, "2.2.0"),
+                new ResourceSerializationCallback(Lp220.LoadProcEntryPoint.Serialize),
+                new ResourceDeserializationCallback(Lp220.LoadProcEntryPoint.Deserialize));
+            ObjectFactory.RegisterLoadProcedureFactoryMethod(LoadType.Sqlite, new LoadProcCreatorFunc(Lp220.LoadProcEntryPoint.CreateDefaultSqlite));
+
+            //Web Layout 1.1.0
+            ResourceValidatorSet.RegisterValidator(new WL110.WebLayoutValidator());
+            ResourceTypeRegistry.RegisterResource(
+                new ResourceTypeDescriptor(ResourceTypes.WebLayout, "1.1.0"),
+                new ResourceSerializationCallback(WL110.WebLayoutEntryPoint.Serialize),
+                new ResourceDeserializationCallback(WL110.WebLayoutEntryPoint.Deserialize));
+            ObjectFactory.RegisterWebLayoutFactoryMethod(new Version(1, 1, 0), new WebLayoutCreatorFunc(WL110.WebLayoutEntryPoint.CreateDefault));
+
+        }
+
+        [TearDown]
+        public void Teardown()
+        {
+        }
+    }
+
+    public abstract class RuntimeMapTests
+    {
+        protected IServerConnection _conn;
+
+        [TestFixtureSetUp]
+        public void TestFixtureSetup()
+        {
+            try
+            {
+                _conn = CreateTestConnection();
+                SetupTestData();
+            }
+            catch (Exception ex)
+            {
+                throw;
+            }
+        }
+
+        private void SetupTestData()
+        {
+            var resSvc = _conn.ResourceService;
+
+            resSvc.DeleteResource("Library://UnitTests/");
+
+            resSvc.SetResourceXmlData("Library://UnitTests/Maps/Sheboygan.MapDefinition", File.OpenRead("TestData/MappingService/UT_Sheboygan.mdf"));
+
+            resSvc.SetResourceXmlData("Library://UnitTests/Layers/HydrographicPolygons.LayerDefinition", File.OpenRead("TestData/MappingService/UT_HydrographicPolygons.ldf"));
+            resSvc.SetResourceXmlData("Library://UnitTests/Layers/Rail.LayerDefinition", File.OpenRead("TestData/MappingService/UT_Rail.ldf"));
+            resSvc.SetResourceXmlData("Library://UnitTests/Layers/Parcels.LayerDefinition", File.OpenRead("TestData/TileService/UT_Parcels.ldf"));
+
+            resSvc.SetResourceXmlData("Library://UnitTests/Data/HydrographicPolygons.FeatureSource", File.OpenRead("TestData/MappingService/UT_HydrographicPolygons.fs"));
+            resSvc.SetResourceXmlData("Library://UnitTests/Data/Rail.FeatureSource", File.OpenRead("TestData/MappingService/UT_Rail.fs"));
+            resSvc.SetResourceXmlData("Library://UnitTests/Data/Parcels.FeatureSource", File.OpenRead("TestData/TileService/UT_Parcels.fs"));
+
+            resSvc.SetResourceData("Library://UnitTests/Data/HydrographicPolygons.FeatureSource", "UT_HydrographicPolygons.sdf", ResourceDataType.File, File.OpenRead("TestData/MappingService/UT_HydrographicPolygons.sdf"));
+            resSvc.SetResourceData("Library://UnitTests/Data/Rail.FeatureSource", "UT_Rail.sdf", ResourceDataType.File, File.OpenRead("TestData/MappingService/UT_Rail.sdf"));
+            resSvc.SetResourceData("Library://UnitTests/Data/Parcels.FeatureSource", "UT_Parcels.sdf", ResourceDataType.File, File.OpenRead("TestData/TileService/UT_Parcels.sdf"));
+        }
+
+        [TestFixtureTearDown]
+        public void TestFixtureTearDown()
+        {
+            
+        }
+
+        protected abstract IServerConnection CreateTestConnection();
+
+        public virtual void TestCreate()
+        {
+            //Create a runtime map from its map definition, verify layer/group
+            //structure is the same
+
+            var resSvc = _conn.ResourceService;
+            var mdf = resSvc.GetResource("Library://UnitTests/Maps/Sheboygan.MapDefinition") as IMapDefinition;
+            Assert.NotNull(mdf);
+
+            var mapSvc = _conn.GetService((int)ServiceType.Mapping) as IMappingService;
+            Assert.NotNull(mapSvc);
+
+            var map = mapSvc.CreateMap("Session:" + _conn.SessionID + "//TestCreate1.Map", mdf);
+            var map2 = mapSvc.CreateMap("Session:" + _conn.SessionID + "//TestCreate2.Map", "Library://UnitTests/Maps/Sheboygan.MapDefinition");
+            var map3 = mapSvc.CreateMap("Library://UnitTests/Maps/Sheboygan.MapDefinition");
+
+            Assert.NotNull(map);
+            Assert.NotNull(map2);
+            Assert.NotNull(map3);
+
+            //Check resource ids
+            Assert.IsTrue(!string.IsNullOrEmpty(map3.ResourceID));
+            Assert.AreEqual("Session:" + _conn.SessionID + "//TestCreate1.Map", map.ResourceID);
+            Assert.AreEqual("Session:" + _conn.SessionID + "//TestCreate2.Map", map2.ResourceID);
+
+            //Check layer/group structure
+            Assert.IsTrue(Matches(map, mdf));
+            Assert.IsTrue(Matches(map2, mdf));
+            Assert.IsTrue(Matches(map3, mdf));
+        }
+
+        private bool Matches(RuntimeMap map, IMapDefinition mdf)
+        {
+            if (map.MapDefinition != mdf.ResourceID) return false;
+            if (map.Groups.Length != mdf.GetGroupCount()) return false;
+            if (map.Layers.Length != mdf.GetLayerCount()) return false;
+
+            foreach (var layer in map.Layers)
+            {
+                var ldfr = mdf.GetLayerByName(layer.Name);
+                if (ldfr == null) return false;
+
+                if (layer.LayerDefinitionID != ldfr.ResourceId) return false;
+                if (layer.LegendLabel != ldfr.LegendLabel) return false;
+                if (layer.Visible != ldfr.Visible) return false;
+                if (layer.Selectable != ldfr.Selectable) return false;
+                if (layer.ShowInLegend != ldfr.ShowInLegend) return false;
+                if (layer.ExpandInLegend != ldfr.ExpandInLegend) return false;
+            }
+
+            foreach (var group in map.Groups)
+            {
+                var grp = mdf.GetGroupByName(group.Name);
+                if (grp == null) return false;
+
+                if (group.ExpandInLegend != grp.ExpandInLegend) return false;
+                if (group.Group != grp.Group) return false;
+                if (group.LegendLabel != grp.LegendLabel) return false;
+                if (group.Name != grp.Name) return false;
+                if (group.ShowInLegend != grp.ShowInLegend) return false;
+                if (group.Visible != grp.Visible) return false;
+            }
+
+            return true;
+        }
+
+        public virtual void TestSave()
+        {
+            //Create a runtime map from its map definition, modify some layers
+            //and groups. Save it, open another instance and verify the changes
+            //have stuck
+            var resSvc = _conn.ResourceService;
+            var mapSvc = _conn.GetService((int)ServiceType.Mapping) as IMappingService;
+            Assert.NotNull(mapSvc);
+
+            var mdf = resSvc.GetResource("Library://UnitTests/Maps/Sheboygan.MapDefinition") as IMapDefinition;
+            Assert.NotNull(mdf);
+
+            var mid = "Session:" + _conn.SessionID + "//TestSave.Map";
+            var map = mapSvc.CreateMap(mid, mdf);
+            //Doesn't exist yet because save isn't called
+            Assert.IsTrue(!resSvc.ResourceExists(mid));
+            
+            //Call save
+            Assert.IsTrue(Matches(map, mdf));
+            map.Save();
+            Assert.IsTrue(Matches(map, mdf));
+            Assert.IsTrue(resSvc.ResourceExists(mid));
+
+            //Open second runtime map instance
+            var map2 = mapSvc.OpenMap(mid);
+            Assert.IsFalse(map == map2);
+            Assert.IsTrue(Matches(map2, mdf));
+
+            //Tweak some settings
+            var parcels = map2.GetLayerByName("Parcels");
+            var rail = map2.GetLayerByName("Rail");
+            Assert.NotNull(parcels);
+
+            parcels.Visible = false;
+            parcels.Selectable = false;
+
+            Assert.NotNull(rail);
+
+            rail.Selectable = false;
+
+            //Save
+            Assert.IsFalse(Matches(map2, mdf));
+            map2.Save();
+            Assert.IsFalse(Matches(map2, mdf));
+
+            var map3 = mapSvc.OpenMap(mid);
+            Assert.IsFalse(Matches(map3, mdf));
+
+            parcels = null;
+            rail = null;
+
+            parcels = map3.GetLayerByName("Parcels");
+            rail = map3.GetLayerByName("Rail");
+            Assert.NotNull(parcels);
+
+            Assert.IsFalse(parcels.Visible);
+            Assert.IsFalse(parcels.Selectable);
+
+            Assert.NotNull(rail);
+
+            Assert.IsFalse(rail.Selectable);
+        }
+
+        public virtual void TestRender75k()
+        {
+            //Render a map of sheboygan at 75k
+            //Only programmatically verify the returned stream can be fed to a
+            //System.Drawing.Image object. 
+
+            var resSvc = _conn.ResourceService;
+            var mapSvc = _conn.GetService((int)ServiceType.Mapping) as IMappingService;
+            Assert.NotNull(mapSvc);
+
+            var mdf = resSvc.GetResource("Library://UnitTests/Maps/Sheboygan.MapDefinition") as IMapDefinition;
+            Assert.NotNull(mdf);
+
+            var mid = "Session:" + _conn.SessionID + "//TestRender75k.Map";
+            var map = mapSvc.CreateMap(mid, mdf);
+            map.ViewScale = 75000;
+
+            //Doesn't exist yet because save isn't called
+            Assert.IsTrue(!resSvc.ResourceExists(mid));
+            map.Save();
+
+            //Render default
+            using (var stream = mapSvc.RenderDynamicOverlay(map, null, "PNG")) //mapSvc.RenderRuntimeMap(map.ResourceID, map.ViewCenter.X, map.ViewCenter.Y, map.ViewScale, map.DisplayWidth, map.DisplayHeight, map.DisplayDpi, "PNG"))
+            {
+                using (var ms = new MemoryStream())
+                using (var ms2 = new MemoryStream())
+                using (var fs = new FileStream("TestRender75k.png", FileMode.OpenOrCreate))
+                {
+                    Utility.CopyStream(stream, ms);
+                    Utility.CopyStream(ms, ms2);
+                    Utility.CopyStream(ms, fs);
+                    //See if System.Drawing.Image accepts this
+                    try
+                    {
+                        using (var img = System.Drawing.Image.FromStream(ms))
+                        { }
+                    }
+                    catch (Exception ex)
+                    {
+                        Assert.Fail(ex.Message);
+                    }
+                }
+            }
+
+            //Turn off parcels
+            var rail = map.GetLayerByName("Rail");
+            Assert.NotNull(rail);
+            rail.Visible = false;
+            map.Save();
+
+            //Render again
+            using (var stream = mapSvc.RenderDynamicOverlay(map, null, "PNG")) //mapSvc.RenderRuntimeMap(map.ResourceID, map.ViewCenter.X, map.ViewCenter.Y, map.ViewScale, map.DisplayWidth, map.DisplayHeight, map.DisplayDpi, "PNG"))
+            {
+                using (var ms = new MemoryStream())
+                using (var ms2 = new MemoryStream())
+                using (var fs = new FileStream("TestRender75k_NoRail.png", FileMode.OpenOrCreate))
+                {
+                    Utility.CopyStream(stream, ms);
+                    Utility.CopyStream(ms, ms2);
+                    Utility.CopyStream(ms, fs);
+                    //See if System.Drawing.Image accepts this
+                    try
+                    {
+                        using (var img = System.Drawing.Image.FromStream(ms))
+                        { }
+                    }
+                    catch (Exception ex)
+                    {
+                        Assert.Fail(ex.Message);
+                    }
+                }
+            }
+
+            //Turn parcels back on
+            rail = null;
+            rail = map.GetLayerByName("Rail");
+            Assert.NotNull(rail);
+            rail.Visible = false;
+            map.Save();
+
+            //Render again
+            using (var stream = mapSvc.RenderDynamicOverlay(map, null, "PNG")) //mapSvc.RenderRuntimeMap(map.ResourceID, map.ViewCenter.X, map.ViewCenter.Y, map.ViewScale, map.DisplayWidth, map.DisplayHeight, map.DisplayDpi, "PNG"))
+            {
+                using (var ms = new MemoryStream())
+                using (var ms2 = new MemoryStream())
+                using (var fs = new FileStream("TestRender75k_RailBackOn.png", FileMode.OpenOrCreate))
+                {
+                    Utility.CopyStream(stream, ms);
+                    Utility.CopyStream(ms, ms2);
+                    Utility.CopyStream(ms, fs);
+                    //See if System.Drawing.Image accepts this
+                    try
+                    {
+                        using (var img = System.Drawing.Image.FromStream(ms))
+                        { }
+                    }
+                    catch (Exception ex)
+                    {
+                        Assert.Fail(ex.Message);
+                    }
+                }
+            }
+        }
+
+        public virtual void TestRender12k()
+        { 
+            //Render a map of sheboygan at 12k
+            //Only programmatically verify the returned stream can be fed to a
+            //System.Drawing.Image object. 
+
+            var resSvc = _conn.ResourceService;
+            var mapSvc = _conn.GetService((int)ServiceType.Mapping) as IMappingService;
+            Assert.NotNull(mapSvc);
+
+            var mdf = resSvc.GetResource("Library://UnitTests/Maps/Sheboygan.MapDefinition") as IMapDefinition;
+            Assert.NotNull(mdf);
+
+            var mid = "Session:" + _conn.SessionID + "//TestRender12k.Map";
+            var map = mapSvc.CreateMap(mid, mdf);
+            map.ViewScale = 12000;
+
+            //Doesn't exist yet because save isn't called
+            Assert.IsTrue(!resSvc.ResourceExists(mid));
+            map.Save();
+
+            //Render default
+            using (var stream = mapSvc.RenderDynamicOverlay(map, null, "PNG")) //mapSvc.RenderRuntimeMap(map.ResourceID, map.ViewCenter.X, map.ViewCenter.Y, map.ViewScale, map.DisplayWidth, map.DisplayHeight, map.DisplayDpi, "PNG"))
+            {
+                using (var ms = new MemoryStream())
+                using (var ms2 = new MemoryStream())
+                using (var fs = new FileStream("TestRender12k.png", FileMode.OpenOrCreate))
+                {
+                    Utility.CopyStream(stream, ms);
+                    Utility.CopyStream(ms, ms2);
+                    Utility.CopyStream(ms, fs);
+                    //See if System.Drawing.Image accepts this
+                    try
+                    {
+                        using (var img = System.Drawing.Image.FromStream(ms))
+                        { }
+                    }
+                    catch (Exception ex)
+                    {
+                        Assert.Fail(ex.Message);
+                    }
+                }
+            }
+
+            //Turn off parcels
+            var parcels = map.GetLayerByName("Parcels");
+            Assert.NotNull(parcels);
+            parcels.Visible = false;
+            map.Save();
+            
+            //Render again
+            using (var stream = mapSvc.RenderDynamicOverlay(map, null, "PNG")) //mapSvc.RenderRuntimeMap(map.ResourceID, map.ViewCenter.X, map.ViewCenter.Y, map.ViewScale, map.DisplayWidth, map.DisplayHeight, map.DisplayDpi, "PNG"))
+            {
+                using (var ms = new MemoryStream())
+                using (var ms2 = new MemoryStream())
+                using (var fs = new FileStream("TestRender12k_NoParcels.png", FileMode.OpenOrCreate))
+                {
+                    Utility.CopyStream(stream, ms);
+                    Utility.CopyStream(ms, ms2);
+                    Utility.CopyStream(ms, fs);
+                    //See if System.Drawing.Image accepts this
+                    try
+                    {
+                        using (var img = System.Drawing.Image.FromStream(ms))
+                        { }
+                    }
+                    catch (Exception ex)
+                    {
+                        Assert.Fail(ex.Message);
+                    }
+                }
+            }
+
+            //Turn parcels back on
+            parcels = null;
+            parcels = map.GetLayerByName("Parcels");
+            Assert.NotNull(parcels);
+            parcels.Visible = false;
+            map.Save();
+
+            //Render again
+            using (var stream = mapSvc.RenderDynamicOverlay(map, null, "PNG")) //mapSvc.RenderRuntimeMap(map.ResourceID, map.ViewCenter.X, map.ViewCenter.Y, map.ViewScale, map.DisplayWidth, map.DisplayHeight, map.DisplayDpi, "PNG"))
+            {
+                using (var ms = new MemoryStream())
+                using (var ms2 = new MemoryStream())
+                using (var fs = new FileStream("TestRender12k_ParcelsBackOn.png", FileMode.OpenOrCreate))
+                {
+                    Utility.CopyStream(stream, ms);
+                    Utility.CopyStream(ms, ms2);
+                    Utility.CopyStream(ms, fs);
+                    //See if System.Drawing.Image accepts this
+                    try
+                    {
+                        using (var img = System.Drawing.Image.FromStream(ms))
+                        { }
+                    }
+                    catch (Exception ex)
+                    {
+                        Assert.Fail(ex.Message);
+                    }
+                }
+            }
+        }
+    }
+
     [TestFixture]
-    public class RuntimeMapTests
+    public class HttpRuntimeMapTests : RuntimeMapTests
     {
+        protected override IServerConnection CreateTestConnection()
+        {
+            return ConnectionProviderRegistry.CreateConnection("Maestro.Http",
+                "Url", "http://localhost/mapguide/mapagent/mapagent.fcgi",
+                "Username", "Administrator",
+                "Password", "admin");
+        }
+
+        [Test]
+        public override void TestCreate()
+        {
+            base.TestCreate();
+        }
+
+        [Test]
+        public override void TestSave()
+        {
+            base.TestSave();
+        }
+
+        [Test]
+        public override void TestRender75k()
+        {
+            base.TestRender75k();
+        }
+
+        [Test]
+        public override void TestRender12k()
+        {
+            base.TestRender12k();
+        }
     }
+
+    [TestFixture(Ignore = true)]
+    public class LocalRuntimeMapTests : RuntimeMapTests
+    {
+        protected override IServerConnection CreateTestConnection()
+        {
+            return ConnectionProviderRegistry.CreateConnection("Maestro.LocalNative",
+                "ConfigPath", "webconfig.ini",
+                "Username", "Administrator",
+                "Password", "admin");
+        }
+
+        [Test]
+        public override void TestCreate()
+        {
+            base.TestCreate();
+        }
+
+        [Test]
+        public override void TestSave()
+        {
+            base.TestSave();
+        }
+
+        [Test]
+        public override void TestRender75k()
+        {
+            base.TestRender75k();
+        }
+
+        [Test]
+        public override void TestRender12k()
+        {
+            base.TestRender12k();
+        }
+    }
 }

Modified: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ConnectionProviderRegistry.cs
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ConnectionProviderRegistry.cs	2010-11-05 08:34:47 UTC (rev 5373)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ConnectionProviderRegistry.cs	2010-11-05 10:17:38 UTC (rev 5374)
@@ -203,25 +203,19 @@
         public static IServerConnection CreateConnection(string provider, params string[] initParameters)
         {
             var initP = new NameValueCollection();
-            string name = null;
-            string value = null;
 
-            foreach (var p in initParameters)
+            for (int i = 0; i < initParameters.Length; i += 2)
             {
-                if (name == null)
-                {
-                    name = p;
-                }
-                else if (value == null)
-                {
-                    value = p;
-                }
-                else
-                {
-                    initP[name] = value;
-                    name = null;
-                    value = null;
-                }
+                string name = null;
+                string value = null;
+
+                if (i < initParameters.Length - 1)
+                    name = initParameters[i];
+                if (i + 1 <= initParameters.Length - 1)
+                    value = initParameters[i + 1];
+
+                if (name != null)
+                    initP[name] = value ?? string.Empty;
             }
 
             return CreateConnection(provider, initP);

Added: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Mapping/MapObservable.cs
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Mapping/MapObservable.cs	                        (rev 0)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Mapping/MapObservable.cs	2010-11-05 10:17:38 UTC (rev 5374)
@@ -0,0 +1,53 @@
+#region Disclaimer / License
+// Copyright (C) 2010, Jackie Ng
+// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at gmail.com
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+// 
+#endregion
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.ComponentModel;
+
+namespace OSGeo.MapGuide.MaestroAPI.Mapping
+{
+    public abstract class MapObservable : INotifyPropertyChanged
+    {
+        protected bool _disableChangeTracking = true;
+
+        protected bool SetField<T>(ref T field, T value, string propertyName)
+        {
+            if (EqualityComparer<T>.Default.Equals(field, value)) 
+                return false;
+            
+            field = value;
+            OnPropertyChanged(propertyName);
+            return true;
+        }
+
+        protected virtual void OnPropertyChanged(string propertyName)
+        {
+            if (_disableChangeTracking)
+                return;
+
+            var handler = this.PropertyChanged;
+            if (handler != null)
+                handler(this, new PropertyChangedEventArgs(propertyName));
+        }
+
+        public event PropertyChangedEventHandler PropertyChanged;
+    }
+}

Added: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Mapping/MapSelection.cs
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Mapping/MapSelection.cs	                        (rev 0)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Mapping/MapSelection.cs	2010-11-05 10:17:38 UTC (rev 5374)
@@ -0,0 +1,669 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using OSGeo.MapGuide.MaestroAPI.Serialization;
+using System.Xml;
+
+namespace OSGeo.MapGuide.MaestroAPI.Mapping
+{
+    public class MapSelection : IBinarySerializable, IList<MapSelection.LayerSelection>
+    {
+        private RuntimeMap _map;
+        private List<LayerSelection> _layers;
+
+        public MapSelection(RuntimeMap map)
+        {
+            _map = map;
+            _layers = new List<LayerSelection>();
+        }
+
+        public MapSelection(RuntimeMap map, string xml)
+            : this(map)
+        {
+            LoadXml(xml);
+        }
+
+        public void LoadXml(string xml)
+        {
+            _layers.Clear();
+
+            System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
+            if (!string.IsNullOrEmpty(xml))
+                doc.LoadXml(xml);
+
+            //There are two variations
+            System.Xml.XmlNodeList lst = doc.SelectNodes("FeatureSet/Layer");
+            if (lst.Count == 0)
+                lst = doc.SelectNodes("FeatureInformation/FeatureSet/Layer");
+
+            foreach (System.Xml.XmlNode n in lst)
+            {
+                if (n.Attributes["id"] != null)
+                {
+                    string guid = n.Attributes["id"].Value;
+                    var l = _map.GetLayerByObjectId(guid);
+                    if (l != null)
+                    {
+                        foreach (System.Xml.XmlNode c in n.SelectNodes("Class"))
+                        {
+                            if (c.Attributes["id"] != null)
+                                if (c.Attributes["id"].Value == l.QualifiedClassName)
+                                    _layers.Add(new LayerSelection(l, c.SelectNodes("ID")));
+                        }
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Returns an xml document that represents the current map selection
+        /// </summary>
+        /// <returns>An xml document that represents the current map selection</returns>
+        public string ToXml()
+        {
+            System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
+            System.Xml.XmlNode root = doc.AppendChild(doc.CreateElement("FeatureSet"));
+
+            foreach (LayerSelection layer in _layers)
+            {
+                System.Xml.XmlNode ln = root.AppendChild(doc.CreateElement("Layer"));
+                ln.Attributes.Append(doc.CreateAttribute("id")).Value = layer.Layer.ObjectId;
+
+                System.Xml.XmlNode cn = ln.AppendChild(doc.CreateElement("Class"));
+                cn.Attributes.Append(doc.CreateAttribute("id")).Value = layer.Layer.QualifiedClassName;
+
+                for (int i = 0; i < layer.Count; i++)
+                    cn.AppendChild(doc.CreateElement("ID")).InnerText = layer.EncodeIDString(layer[i]);
+            }
+
+            return doc.OuterXml;
+        }
+
+        public class LayerSelection : IList<object[]>
+        {
+            private RuntimeMapLayer m_layer;
+            private List<object[]> m_list = new List<object[]>();
+
+            /// <summary>
+            /// Gets the layer that contains the selected objects
+            /// </summary>
+            public RuntimeMapLayer Layer { get { return m_layer; } }
+
+            /// <summary>
+            /// Internal helper to construct a LayerSelection
+            /// </summary>
+            /// <param name="layer">The layer that the selection belongs to</param>
+            /// <param name="ids">A list of xml &lt;ID&gt; nodes</param>
+            internal LayerSelection(RuntimeMapLayer layer, System.Xml.XmlNodeList ids)
+                : this(layer)
+            {
+                foreach (System.Xml.XmlNode n in ids)
+                    Add(ParseIDString(n.InnerXml));
+            }
+
+            /// <summary>
+            /// Encodes the given combined keyset into an ID string for use in the Xml
+            /// </summary>
+            /// <param name="values">The combined key</param>
+            /// <returns>A base64 encoded ID string</returns>
+            public string EncodeIDString(object[] values)
+            {
+                object[] tmp = NormalizeAndValidate(values);
+
+                using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
+                {
+                    for (int i = 0; i < m_layer.IdentityProperties.Length; i++)
+                    {
+                        Type type = m_layer.IdentityProperties[i].Type;
+
+                        if (type == typeof(short))
+                        {
+                            byte[] x = BitConverter.GetBytes((short)tmp[i]);
+                            ms.Write(x, 0, x.Length);
+                        }
+                        else if (type == typeof(int))
+                        {
+                            byte[] x = BitConverter.GetBytes((int)tmp[i]);
+                            ms.Write(x, 0, x.Length);
+                        }
+                        else if (type == typeof(long))
+                        {
+                            byte[] x = BitConverter.GetBytes((long)tmp[i]);
+                            ms.Write(x, 0, x.Length);
+                        }
+                        else if (type == typeof(string))
+                        {
+                            byte[] x = System.Text.Encoding.UTF8.GetBytes((string)tmp[i]);
+                            ms.Write(x, 0, x.Length);
+                            ms.WriteByte(0);
+                        }
+                        else
+                            throw new Exception(string.Format("The type {0} is not supported for primary keys", type.ToString()));
+                    }
+
+                    return Convert.ToBase64String(ms.ToArray());
+                }
+            }
+
+            /// <summary>
+            /// Parses a base64 encoded string with key values
+            /// </summary>
+            /// <param name="id">The base64 encoded ID string</param>
+            /// <returns>The composite value key</returns>
+            public object[] ParseIDString(string id)
+            {
+                int index = 0;
+                byte[] data = Convert.FromBase64String(id);
+                object[] tmp = new object[m_layer.IdentityProperties.Length];
+                for (int i = 0; i < m_layer.IdentityProperties.Length; i++)
+                {
+                    Type type = m_layer.IdentityProperties[i].Type;
+
+                    if (type == typeof(short))
+                    {
+                        tmp[i] = BitConverter.ToInt16(data, index);
+                        index += MgBinarySerializer.UInt16Len;
+                    }
+                    else if (type == typeof(int))
+                    {
+                        tmp[i] = BitConverter.ToInt32(data, index);
+                        index += MgBinarySerializer.UInt32Len;
+                    }
+                    else if (type == typeof(long))
+                    {
+                        tmp[i] = BitConverter.ToInt64(data, index);
+                        index += MgBinarySerializer.UInt64Len;
+                    }
+                    else if (type == typeof(string))
+                    {
+                        int pos = index;
+                        while (pos < data.Length && data[pos] != 0)
+                            pos++;
+
+                        if (pos >= data.Length)
+                            throw new Exception("Bad null encoded string");
+
+                        tmp[i] = System.Text.Encoding.UTF8.GetString(data, index, pos - index);
+                        index = pos + 1;
+                    }
+                    else
+                        throw new Exception(string.Format("The type {0} is not supported for primary keys", type.ToString()));
+                }
+
+                return tmp;
+            }
+
+            /// <summary>
+            /// Constructs a new LayerSelection with a number of selected featured
+            /// </summary>
+            /// <param name="layer">The layer to represent</param>
+            /// <param name="ids">The list of composite IDs that the layer supports</param>
+            public LayerSelection(RuntimeMapLayer layer, IEnumerable<object[]> ids)
+                : this(layer)
+            {
+                AddRange(ids);
+            }
+
+            /// <summary>
+            /// Constructs a new LayerSelection with a number of selected featured
+            /// </summary>
+            /// <param name="layer">The layer to represent</param>
+            public LayerSelection(RuntimeMapLayer layer)
+            {
+                if (layer == null)
+                    throw new ArgumentNullException("layer");
+
+                if (layer.IdentityProperties.Length == 0)
+                    throw new Exception("The layer does not have a primary key, and cannot be used for selection");
+
+                m_layer = layer;
+            }
+
+            /// <summary>
+            /// Adds a composite key to the selection
+            /// </summary>
+            /// <param name="values">The composite key</param>
+            public void Add(object[] values)
+            {
+                object[] tmp = NormalizeAndValidate(values);
+
+                if (!this.Contains(tmp))
+                    m_list.Add(tmp);
+            }
+
+            /// <summary>
+            /// Ensures that the composite key types match the layers ID column types.
+            /// The returned array is a copy of the one passed in
+            /// </summary>
+            /// <param name="values">The composite key</param>
+            /// <returns>A copy of the composite key</returns>
+            private object[] NormalizeAndValidate(object[] values)
+            {
+                if (values == null)
+                    throw new ArgumentNullException("values");
+
+                if (values.Length != m_layer.IdentityProperties.Length)
+                    throw new Exception(string.Format("The layers key consists of {0} columns, but only {1} columns were given", m_layer.IdentityProperties.Length, values.Length));
+
+                object[] tmp = new object[values.Length];
+
+                for (int i = 0; i < values.Length; i++)
+                {
+                    if (values[i] == null)
+                        throw new Exception(string.Format("The value for {0} is null, which is not supported as a key", m_layer.IdentityProperties[i].Name));
+                    if (values[i].GetType() != m_layer.IdentityProperties[i].Type)
+                        try { tmp[i] = Convert.ChangeType(values[i], m_layer.IdentityProperties[i].Type); }
+                        catch (Exception ex) { throw new Exception(string.Format("Failed to convert value for {0} from {1} to {2}", m_layer.IdentityProperties[i].Name, values[i].GetType(), m_layer.IdentityProperties[i].Type), ex); }
+                    else
+                        tmp[i] = values[i];
+                }
+
+                return tmp;
+            }
+
+            /// <summary>
+            /// Adds a number of composite keys
+            /// </summary>
+            /// <param name="lst">A list of composite keys</param>
+            public void AddRange(IEnumerable<object[]> lst)
+            {
+                foreach (object[] x in lst)
+                    Add(x);
+            }
+
+            #region IList<object[]> Members
+
+            /// <summary>
+            /// Returns the index of the given composite key
+            /// </summary>
+            /// <param name="item">The composite key to look for</param>
+            /// <returns>The index of the composite key or -1 if the key is not found</returns>
+            public int IndexOf(object[] item)
+            {
+                object[] tmp = NormalizeAndValidate(item);
+
+                for (int i = 0; i < m_list.Count; i++)
+                {
+                    object[] tmpx = m_list[i];
+
+                    bool matches = true;
+                    for (int j = 0; j < tmpx.Length; j++)
+                        if (tmpx[j] != item[j])
+                        {
+                            matches = false;
+                            break;
+                        }
+
+                    if (matches)
+                        return i;
+                }
+
+                return -1;
+            }
+
+            /// <summary>
+            /// Inserts a key at the specified location
+            /// </summary>
+            /// <param name="index">The index to insert the key at</param>
+            /// <param name="item">The key to insert</param>
+            public void Insert(int index, object[] item)
+            {
+                object[] tmp = NormalizeAndValidate(item);
+
+                int ix = IndexOf(tmp);
+
+                if (ix >= 0)
+                    RemoveAt(ix);
+
+                Insert(index, item);
+            }
+
+            /// <summary>
+            /// Removes the element at the specified location
+            /// </summary>
+            /// <param name="index">The index of the item to remove</param>
+            public void RemoveAt(int index)
+            {
+                m_list.RemoveAt(index);
+            }
+
+            /// <summary>
+            /// Gets or sets the composite key for the specified index
+            /// </summary>
+            /// <param name="index">The index for the composite key</param>
+            /// <returns>The composite key</returns>
+            public object[] this[int index]
+            {
+                get
+                {
+                    object[] tmp = new object[m_layer.IdentityProperties.Length];
+                    Array.Copy(m_list[index], tmp, tmp.Length);
+                    return tmp;
+                }
+                set
+                {
+                    m_list[index] = NormalizeAndValidate(value);
+                }
+            }
+
+            #endregion
+
+            #region ICollection<object[]> Members
+
+            /// <summary>
+            /// Removes all composite keys from the collection
+            /// </summary>
+            public void Clear()
+            {
+                m_list.Clear();
+            }
+
+            /// <summary>
+            /// Returns a value indicating if the composite key is contained in the collection
+            /// </summary>
+            /// <param name="item">The composite key to look for</param>
+            /// <returns>True if the collection contains the composite key, false otherwise</returns>
+            public bool Contains(object[] item)
+            {
+                return IndexOf(item) >= 0;
+            }
+
+            /// <summary>
+            /// Not implemented
+            /// </summary>
+            /// <param name="array"></param>
+            /// <param name="arrayIndex"></param>
+            public void CopyTo(object[][] array, int arrayIndex)
+            {
+                throw new NotImplementedException();
+            }
+
+            /// <summary>
+            /// Returns the number of composite keys (and thus selected objects)
+            /// </summary>
+            public int Count
+            {
+                get { return m_list.Count; }
+            }
+
+            /// <summary>
+            /// Gets a value indicating if the collection is read-only
+            /// </summary>
+            public bool IsReadOnly
+            {
+                get { return false; }
+            }
+
+            /// <summary>
+            /// Removes the given composite key from the collection
+            /// </summary>
+            /// <param name="item">The composite key to remove</param>
+            /// <returns>True if the composite key was found and removed, false otherwise</returns>
+            public bool Remove(object[] item)
+            {
+                int ix = IndexOf(item);
+                if (ix < 0)
+                    return false;
+
+                m_list.RemoveAt(ix);
+                return true;
+            }
+
+            #endregion
+
+            #region IEnumerable<object[]> Members
+
+            /// <summary>
+            /// Returns an enumerator for the collection
+            /// </summary>
+            /// <returns>An enumerator for the collection</returns>
+            public IEnumerator<object[]> GetEnumerator()
+            {
+                return m_list.GetEnumerator();
+            }
+
+            #endregion
+
+            #region IEnumerable Members
+
+            /// <summary>
+            /// Returns an enumerator for the collection
+            /// </summary>
+            /// <returns>An enumerator for the collection</returns>
+            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+            {
+                return ((System.Collections.IEnumerable)m_list).GetEnumerator();
+            }
+
+            #endregion
+        }
+
+        public void Serialize(MgBinarySerializer s)
+        {
+            var m_selection = new XmlDocument();
+            m_selection.LoadXml(ToXml());
+            if (m_selection["FeatureSet"] == null)
+            {
+                s.Write((int)0);
+                return;
+            }
+
+            XmlNodeList lst = m_selection["FeatureSet"].SelectNodes("Layer");
+            s.Write(lst.Count);
+            foreach (XmlNode n in lst)
+            {
+                if (n.Attributes["id"] == null)
+                    throw new Exception("A layer in selection had no id");
+                s.Write(n.Attributes["id"].Value);
+
+                XmlNodeList cls = n.SelectNodes("Class");
+                s.Write(cls.Count);
+
+                foreach (XmlNode c in cls)
+                {
+                    s.Write(c.Attributes["id"].Value);
+                    XmlNodeList ids = c.SelectNodes("ID");
+                    s.Write(ids.Count);
+
+                    foreach (XmlNode id in ids)
+                        s.Write(id.InnerText);
+                }
+            }
+        }
+
+        public void Deserialize(MgBinaryDeserializer d)
+        {
+            XmlDocument doc = new XmlDocument();
+            XmlNode root = doc.AppendChild(doc.CreateElement("FeatureSet"));
+            int layerCount = d.ReadInt32();
+            for (int i = 0; i < layerCount; i++)
+            {
+                XmlNode layer = root.AppendChild(doc.CreateElement("Layer"));
+                layer.Attributes.Append(doc.CreateAttribute("id")).Value = d.ReadString();
+
+                int classCount = d.ReadInt32();
+                for (int j = 0; j < classCount; j++)
+                {
+                    XmlNode @class = layer.AppendChild(doc.CreateElement("Class"));
+                    @class.Attributes.Append(doc.CreateAttribute("id")).Value = d.ReadString();
+
+                    int idCount = d.ReadInt32();
+                    for (int k = 0; k < idCount; k++)
+                        @class.AppendChild(doc.CreateElement("ID")).InnerText = d.ReadString();
+                }
+            }
+            LoadXml(doc.OuterXml);
+        }
+
+        #region IList<MapSelection.LayerSelection> Members
+
+        /// <summary>
+        /// Returns the index of the given layer
+        /// </summary>
+        /// <param name="item">The layer to look for</param>
+        /// <returns>The index of the layer, or -1 if the layer is not in the collection</returns>
+        public int IndexOf(MapSelection.LayerSelection item)
+        {
+            return IndexOf(item.Layer);
+        }
+
+        /// <summary>
+        /// Returns the index of the given layer
+        /// </summary>
+        /// <param name="item">The layer to look for</param>
+        /// <returns>The index of the layer, or -1 if the layer is not in the collection</returns>
+        public int IndexOf(RuntimeMapLayer layer)
+        {
+            for (int i = 0; i < _layers.Count; i++)
+                if (_layers[i].Layer.ObjectId == layer.ObjectId)
+                    return i;
+
+            return 1;
+        }
+
+        /// <summary>
+        /// Inserts a selection layer into the collection
+        /// </summary>
+        /// <param name="index">The index to place the item at</param>
+        /// <param name="item">The item to insert</param>
+        public void Insert(int index, MapSelection.LayerSelection item)
+        {
+            _layers.Insert(index, item);
+        }
+
+        /// <summary>
+        /// Inserts a selection layer into the collection
+        /// </summary>
+        /// <param name="index">The index to place the item at</param>
+        /// <param name="layer">The layer.</param>
+        public void Insert(int index, RuntimeMapLayer layer)
+        {
+            _layers.Insert(index, new LayerSelection(layer));
+        }
+
+        /// <summary>
+        /// Removes the item at the given index
+        /// </summary>
+        /// <param name="index">The index to remove the item at</param>
+        public void RemoveAt(int index)
+        {
+            _layers.RemoveAt(index);
+        }
+
+        /// <summary>
+        /// Gets or sets the selection layer at a given index
+        /// </summary>
+        /// <param name="index">The index to get or set the item for</param>
+        /// <returns>The item at the given index</returns>
+        public MapSelection.LayerSelection this[int index]
+        {
+            get
+            {
+                return _layers[index];
+            }
+            set
+            {
+                if (value == null)
+                    throw new ArgumentNullException();
+                _layers[index] = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the selection layer at a given index
+        /// </summary>
+        /// <param name="index">The index to get or set the item for</param>
+        /// <returns>The item at the given index</returns>
+        public MapSelection.LayerSelection this[RuntimeMapLayer index]
+        {
+            get
+            {
+                return _layers[IndexOf(index)];
+            }
+            set
+            {
+                if (value == null)
+                    throw new ArgumentNullException();
+                _layers[IndexOf(index)] = value;
+            }
+        }
+
+        #endregion
+
+        #region ICollection<MapSelection.LayerSelection> Members
+
+        public void Add(MapSelection.LayerSelection item)
+        {
+            if (item == null)
+                throw new ArgumentNullException();
+
+            _layers.Add(item);
+        }
+
+        public void Add(RuntimeMapLayer layer)
+        {
+            if (!Contains(layer))
+                Add(new LayerSelection(layer));
+        }
+
+        public void Clear()
+        {
+            _layers.Clear();
+        }
+
+        public bool Contains(RuntimeMapLayer item)
+        {
+            return IndexOf(item) >= 0;
+        }
+
+        public bool Contains(MapSelection.LayerSelection item)
+        {
+            return IndexOf(item) >= 0;
+        }
+
+        public void CopyTo(MapSelection.LayerSelection[] array, int arrayIndex)
+        {
+            throw new NotImplementedException();
+        }
+
+        public int Count
+        {
+            get { return _layers.Count; }
+        }
+
+        public bool IsReadOnly
+        {
+            get { return false; }
+        }
+
+        public bool Remove(MapSelection.LayerSelection item)
+        {
+            int ix = IndexOf(item);
+            if (ix < 0)
+                return false;
+
+            _layers.RemoveAt(ix);
+            return true;
+        }
+
+        #endregion
+
+        #region IEnumerable<LayerSelection> Members
+
+        public IEnumerator<MapSelection.LayerSelection> GetEnumerator()
+        {
+            return _layers.GetEnumerator();
+        }
+
+        #endregion
+
+        #region IEnumerable Members
+
+        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+        {
+            return ((System.Collections.IEnumerable)_layers).GetEnumerator();
+        }
+
+        #endregion
+    }
+}

Deleted: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Mapping/MapSelectionBase.cs
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Mapping/MapSelectionBase.cs	2010-11-05 08:34:47 UTC (rev 5373)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Mapping/MapSelectionBase.cs	2010-11-05 10:17:38 UTC (rev 5374)
@@ -1,81 +0,0 @@
-#region Disclaimer / License
-// Copyright (C) 2010, Jackie Ng
-// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at gmail.com
-// 
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-// 
-#endregion
-using System;
-using System.Collections.Generic;
-using System.Text;
-using OSGeo.MapGuide.MaestroAPI.Serialization;
-
-namespace OSGeo.MapGuide.MaestroAPI.Mapping
-{
-    /// <summary>
-    /// 
-    /// </summary>
-    public class MapSelectionBase
-    {
-        /// <summary>
-        /// Initializes a new instance of the <see cref="MapSelectionBase"/> class.
-        /// </summary>
-        public MapSelectionBase() { }
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="MapSelectionBase"/> class.
-        /// </summary>
-        /// <param name="xml">The XML.</param>
-        public MapSelectionBase(string xml)
-        { }
-
-        /// <summary>
-        /// Serializes the specified serializer.
-        /// </summary>
-        /// <param name="serializer">The serializer.</param>
-        public void Serialize(MgBinarySerializer serializer)
-        {
-            throw new NotImplementedException();
-        }
-
-        /// <summary>
-        /// Gets or sets the selection XML.
-        /// </summary>
-        /// <value>The selection XML.</value>
-        public string SelectionXml
-        {
-            get;
-            private set;
-        }
-
-        /// <summary>
-        /// Toes the XML.
-        /// </summary>
-        /// <returns></returns>
-        public string ToXml()
-        {
-            throw new NotImplementedException();
-        }
-
-        /// <summary>
-        /// Deserializes the specified deserializer.
-        /// </summary>
-        /// <param name="deserializer">The deserializer.</param>
-        public void Deserialize(MgBinaryDeserializer deserializer)
-        {
-            throw new NotImplementedException();
-        }
-    }
-}

Deleted: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Mapping/RuntimeLayerBase.cs
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Mapping/RuntimeLayerBase.cs	2010-11-05 08:34:47 UTC (rev 5373)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Mapping/RuntimeLayerBase.cs	2010-11-05 10:17:38 UTC (rev 5374)
@@ -1,32 +0,0 @@
-#region Disclaimer / License
-// Copyright (C) 2010, Jackie Ng
-// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at gmail.com
-// 
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-// 
-#endregion
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace OSGeo.MapGuide.MaestroAPI.Mapping
-{
-    /// <summary>
-    /// 
-    /// </summary>
-    public abstract class RuntimeLayerBase
-    {
-    }
-}

Added: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Mapping/RuntimeMap.cs
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Mapping/RuntimeMap.cs	                        (rev 0)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Mapping/RuntimeMap.cs	2010-11-05 10:17:38 UTC (rev 5374)
@@ -0,0 +1,1109 @@
+#region Disclaimer / License
+// Copyright (C) 2010, Jackie Ng
+// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at gmail.com
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+// 
+#endregion
+using System;
+using System.Collections.Generic;
+using System.Text;
+using OSGeo.MapGuide.MaestroAPI.Services;
+using OSGeo.MapGuide.ObjectModels.Common;
+using OSGeo.MapGuide.ObjectModels.MapDefinition;
+using OSGeo.MapGuide.ObjectModels;
+using OSGeo.MapGuide.MaestroAPI.Serialization;
+using OSGeo.MapGuide.MaestroAPI.Resource;
+using System.ComponentModel;
+using OSGeo.MapGuide.ObjectModels.LayerDefinition;
+
+namespace OSGeo.MapGuide.MaestroAPI.Mapping
+{
+    /// <summary>
+    /// Represents a runtime instance of a Map Definition
+    /// </summary>
+    public class RuntimeMap : MapObservable
+    {
+        internal IFeatureService FeatureService { get; set; }
+
+        internal IResourceService ResourceService { get; set; }
+
+        internal Version SiteVersion { get; private set; }
+
+        /// <summary>
+        /// The layer collection
+        /// </summary>
+        protected List<RuntimeMapLayer> _layers;
+        
+        /// <summary>
+        /// The group collection
+        /// </summary>
+        protected List<RuntimeMapGroup> _groups;
+
+        /// <summary>
+        /// The id to layer lookup dictionary
+        /// </summary>
+        protected Dictionary<string, RuntimeMapLayer> _layerIdMap;
+
+        internal RuntimeMap(IServerConnection conn)
+        {
+            _disableChangeTracking = true;
+
+            this.SiteVersion = conn.SiteVersion;
+            this.SessionId = conn.SessionID;
+            this.ObjectId = Guid.NewGuid().ToString();
+            m_changeList = new Dictionary<string, ChangeList>();
+            _finiteDisplayScales = new double[0];
+            this.ResourceService = conn.ResourceService;
+            this.FeatureService = conn.FeatureService;
+            _layers = new List<RuntimeMapLayer>();
+            _groups = new List<RuntimeMapGroup>();
+            _layerIdMap = new Dictionary<string, RuntimeMapLayer>();
+            this.Selection = new MapSelection(this);
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="RuntimeMap"/> class.
+        /// </summary>
+        /// <param name="mdf">The map definition to create this map from.</param>
+        internal RuntimeMap(IMapDefinition mdf)
+            : this(mdf.CurrentConnection)
+        {
+            this.MapDefinition = mdf.ResourceID;
+            this.MapExtent = mdf.Extents.Clone();
+            this.DataExtent = mdf.Extents.Clone();
+            this.BackgroundColor = mdf.BackgroundColor;
+            this.CoordinateSystem = mdf.CoordinateSystem;
+            this.MetersPerUnit = 1.0;
+            //TODO: infer real mpu from coordinate system
+
+            int dispIndex = 0;
+            //Load map layers
+            foreach (var layer in mdf.MapLayer)
+            {
+                var rtl = new RuntimeMapLayer(this, layer, GetLayerDefinition(layer.ResourceId));
+                rtl.DisplayOrder = (++dispIndex) * 1000;
+                AddLayerInternal(rtl);
+            }
+
+            //Load map groups
+            foreach (var group in mdf.MapLayerGroup)
+            {
+                var grp = new RuntimeMapGroup(this, group);
+                _groups.Add(grp);
+            }
+
+            //If base map specified load layers and groups there
+            if (mdf.BaseMap != null)
+            {
+                var bm = mdf.BaseMap;
+                foreach (var group in bm.BaseMapLayerGroup)
+                {
+                    if (group.HasLayers())
+                    {
+                        foreach (var layer in group.BaseMapLayer)
+                        {
+                            var rtl = new RuntimeMapLayer(this, layer, GetLayerDefinition(layer.ResourceId)) { Visible = true };
+                            rtl.Type = RuntimeMapLayer.kBaseMap;
+                            rtl.DisplayOrder = (++dispIndex) * 1000;
+                            AddLayerInternal(rtl);
+                        }
+                    }
+                    var rtg = new RuntimeMapGroup(this, group);
+                    _groups.Add(rtg);
+                }
+
+                //Init finite display scales
+                if (bm.ScaleCount > 0)
+                {
+                    _finiteDisplayScales = new double[bm.ScaleCount];
+                    for (int i = 0; i < bm.ScaleCount; i++)
+                    {
+                        _finiteDisplayScales[i] = bm.GetScaleAt(i);
+                    }
+                }
+            }
+
+            this.LayerRefreshMode = 1;
+            this.ViewScale = 500; //TODO: Calc from extents and other parameters
+            this.DisplayDpi = 96;
+            this.DisplayWidth = 1024;
+            this.DisplayHeight = 768;
+            this.ViewCenter = this.DataExtent.Center();
+
+            _disableChangeTracking = false;
+        }
+
+        /// <summary>
+        /// Gets or sets the map extents.
+        /// </summary>
+        /// <value>The map extents.</value>
+        public IEnvelope MapExtent
+        {
+            get;
+            private set;
+        }
+        
+        /// <summary>
+        /// The data extent
+        /// </summary>
+        protected IEnvelope _dataExtent;
+
+        /// <summary>
+        /// Gets or sets the data extent.
+        /// </summary>
+        /// <value>The data extent.</value>
+        public IEnvelope DataExtent
+        {
+            get
+            {
+                return _dataExtent;
+            }
+            set
+            {
+                if (value == null)
+                    throw new ArgumentNullException();
+
+                if (_dataExtent == null)
+                {
+                    _dataExtent = value;
+                }
+                else
+                {
+                    _dataExtent.MaxX = value.MaxX;
+                    _dataExtent.MaxY = value.MaxY;
+                    _dataExtent.MinX = value.MinX;
+                    _dataExtent.MinY = value.MinY;
+                }
+            }
+        }
+
+        /// <summary>
+        /// The dpi
+        /// </summary>
+        protected int _dpi;
+
+        /// <summary>
+        /// Gets or sets the display dpi.
+        /// </summary>
+        /// <value>The display dpi.</value>
+        public int DisplayDpi
+        {
+            get
+            {
+                return _dpi;
+            }
+            set
+            {
+                SetField(ref _dpi, value, "DisplayDpi");
+            }
+        }
+
+        /// <summary>
+        /// The display height
+        /// </summary>
+        protected int _dispHeight;
+
+        /// <summary>
+        /// Gets or sets the display height.
+        /// </summary>
+        /// <value>The display height.</value>
+        public int DisplayHeight
+        {
+            get
+            {
+                return _dispHeight;
+            }
+            set
+            {
+                _dispHeight = value;
+            }
+        }
+
+        /// <summary>
+        /// The display width
+        /// </summary>
+        protected int _dispWidth;
+
+        /// <summary>
+        /// Gets or sets the display width.
+        /// </summary>
+        /// <value>The display width.</value>
+        public int DisplayWidth
+        {
+            get
+            {
+                return _dispWidth;
+            }
+            set
+            {
+                _dispWidth = value;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the map definition resource id
+        /// </summary>
+        /// <value>The map definition resource id.</value>
+        public string MapDefinition
+        {
+            get;
+            internal set;
+        }
+
+        /// <summary>
+        /// Gets or sets the object id.
+        /// </summary>
+        /// <value>The object id.</value>
+        public string ObjectId
+        {
+            get;
+            internal set;
+        }
+
+        /// <summary>
+        /// Gets or sets the session id.
+        /// </summary>
+        /// <value>The session id.</value>
+        public string SessionId
+        {
+            get;
+            internal set;
+        }
+
+        /// <summary>
+        /// The view center
+        /// </summary>
+        protected IPoint2D _viewCenter;
+
+        /// <summary>
+        /// Gets or sets the view center.
+        /// </summary>
+        /// <value>The view center.</value>
+        public IPoint2D ViewCenter
+        {
+            get
+            {
+                return _viewCenter;
+            }
+            set
+            {
+                _viewCenter = value;
+            }
+        }
+
+        /// <summary>
+        /// The view scale
+        /// </summary>
+        protected double _viewScale;
+
+        /// <summary>
+        /// Gets or sets the view scale.
+        /// </summary>
+        /// <value>The view scale.</value>
+        public double ViewScale
+        {
+            get
+            {
+                return _viewScale;
+            }
+            set
+            {
+                SetField(ref _viewScale, value, "ViewScale");
+            }
+        }
+
+        protected string _name;
+
+        /// <summary>
+        /// Gets or sets the name.
+        /// </summary>
+        /// <value>The name.</value>
+        public string Name
+        {
+            get { return _name; }
+            set { SetField(ref _name, value, "Name"); }
+        }
+
+        protected string _mapSrs;
+
+        /// <summary>
+        /// Gets or sets the coordinate system in WKT format
+        /// </summary>
+        /// <value>The coordinate system in WKT format.</value>
+        public string CoordinateSystem
+        {
+            get { return _mapSrs; }
+            internal set { SetField(ref _mapSrs, value, "CoordinateSystem"); }
+        }
+
+        protected System.Drawing.Color _bgColor;
+
+        /// <summary>
+        /// Gets or sets the color of the background.
+        /// </summary>
+        /// <value>The color of the background.</value>
+        public System.Drawing.Color BackgroundColor
+        {
+            get
+            {
+                return _bgColor;
+            }
+            set
+            {
+                SetField(ref _bgColor, value, "BackgroundColor");
+            }
+        }
+
+        private string _resId;
+
+        /// <summary>
+        /// Gets or sets the resource ID. When setting, if the name of this map has 
+        /// not been specified already, the name will be set based on this resource id
+        /// </summary>
+        /// <value>The resource ID.</value>
+        public string ResourceID
+        {
+            get { return _resId; }
+            set 
+            { 
+                SetField(ref _resId, value, "ResourceID");
+                if (this.Name == null)
+                    this.Name = ResourceIdentifier.GetName(_resId);
+            }
+        }
+
+        /// <summary>
+        /// Gets the type of the resource.
+        /// </summary>
+        /// <value>The type of the resource.</value>
+        public ResourceTypes ResourceType
+        {
+            get { return ResourceTypes.RuntimeMap; }
+        }
+
+        /// <summary>
+        /// Gets the meters per unit.
+        /// </summary>
+        /// <value>The meters per unit.</value>
+        public double MetersPerUnit
+        {
+            get;
+            private set;
+        }
+
+        /// <summary>
+        /// MapGuide internal value
+        /// </summary>
+        protected const int MgBinaryVersion = 262144; //1;
+
+        /// <summary>
+        /// MapGuide internal class id
+        /// </summary>
+        protected const int ClassId = 11500; //30500;
+
+        /// <summary>
+        /// Gets the layer refresh mode.
+        /// </summary>
+        /// <value>The layer refresh mode.</value>
+        public int LayerRefreshMode
+        {
+            get;
+            private set;
+        }
+
+        private double[] _finiteDisplayScales;
+
+        public void Serialize(MgBinarySerializer s)
+        {
+            if (s.SiteVersion >= SiteVersions.GetVersion(KnownSiteVersions.MapGuideOS1_2))
+            {
+                s.Write(MgBinaryVersion);
+                s.WriteResourceIdentifier(this.ResourceID);
+            }
+
+            s.Write(this.Name);
+            s.Write(this.ObjectId);
+            s.WriteResourceIdentifier(this.MapDefinition);
+            s.Write(this.CoordinateSystem);
+            //base.m_extents.Serialize(s);
+            SerializeExtent(this.MapExtent, s);
+            s.WriteCoordinates(new double[] { this.ViewCenter.X, this.ViewCenter.Y }, 0);
+            s.Write(this.ViewScale);
+            SerializeExtent(this.DataExtent, s);
+            s.Write(this.DisplayDpi);
+            s.Write(this.DisplayWidth);
+            s.Write(this.DisplayHeight);
+            s.Write(Utility.SerializeHTMLColor(this.BackgroundColor, true));
+            s.Write(this.MetersPerUnit);
+
+            if (s.SiteVersion >= SiteVersions.GetVersion(KnownSiteVersions.MapGuideOS1_2))
+                s.Write(this.LayerRefreshMode);
+
+            s.Write(_finiteDisplayScales.Length);
+            foreach (double d in _finiteDisplayScales)
+                s.Write(d);
+
+            if (s.SiteVersion >= SiteVersions.GetVersion(KnownSiteVersions.MapGuideOS1_2))
+            {
+                SerializeChangeMap(s);
+                s.Write((int)0);
+            }
+            else
+            {
+                SerializeLayerData(s);
+                SerializeChangeMap(s);
+            }
+        }
+
+        private static void SerializeExtent(IEnvelope env, MgBinarySerializer s)
+        {
+            if (s.SiteVersion <= SiteVersions.GetVersion(KnownSiteVersions.MapGuideEP1_1))
+                s.WriteClassId(18001);
+            else
+                s.WriteClassId(20001);
+
+            s.Write((int)0);
+
+            s.Write(env.MinX);
+            s.Write(env.MinY);
+            s.Write(env.MaxY);
+            s.Write(env.MaxY);
+        }
+
+        private Dictionary<string, ChangeList> m_changeList;
+
+        internal class Change
+        {
+            public enum ChangeType
+            {
+                removed,
+                added,
+                visibilityChanged,
+                displayInLegendChanged,
+                legendLabelChanged,
+                parentChanged,
+                selectabilityChanged,
+                definitionChanged
+            };
+
+            public ChangeType Type { get; private set; }
+            public string Params { get; private set; }
+
+            public Change()
+            {
+            }
+
+            public Change(ChangeType type, string param)
+            {
+                this.Type = type;
+                this.Params = param;
+            }
+        }
+
+        internal class ChangeList
+        {
+            public string ObjectId { get; private set; }
+            public bool IsLayer { get; private set; }
+            public List<Change> Changes { get; private set; }
+
+            public ChangeList()
+            {
+                this.Changes = new List<Change>();
+            }
+
+            public ChangeList(string objectId, bool isLayer)
+                : this()
+            {
+                this.ObjectId = objectId;
+                this.IsLayer = isLayer;
+            }
+        }
+
+        private void SerializeChangeMap(MgBinarySerializer s)
+        {
+            s.Write(m_changeList.Count);
+            foreach (ChangeList cl in m_changeList.Values)
+            {
+                s.Write(cl.IsLayer);
+                s.Write(cl.ObjectId);
+
+                s.Write(cl.Changes.Count);
+                foreach (Change c in cl.Changes)
+                {
+                    s.Write((int)c.Type);
+                    s.Write(c.Params);
+                }
+            }
+        }
+
+        protected void SerializeLayerData(MgBinarySerializer s)
+        {
+            s.Write((int)_groups.Count);
+            foreach (var g in _groups)
+                g.Serialize(s);
+
+            s.Write(_layers.Count);
+            foreach (var t in _layers)
+                t.Serialize(s);
+        }
+
+        public void Deserialize(MgBinaryDeserializer d)
+        {
+            _disableChangeTracking = true;
+
+            if (d.SiteVersion >= SiteVersions.GetVersion(KnownSiteVersions.MapGuideOS1_2))
+            {
+                if (d.ReadInt32() != MgBinaryVersion)
+                    throw new Exception("Invalid map version");
+                this.ResourceID = d.ReadResourceIdentifier();
+            }
+
+
+            this.Name = d.ReadString();
+            this.ObjectId = d.ReadString();
+
+            this.MapDefinition = d.ReadResourceIdentifier();
+
+            this.CoordinateSystem = d.ReadString();
+            this.MapExtent = DeserializeExtents(d);
+            var cc = d.ReadCoordinates();
+            if (this.ViewCenter != null)
+            {
+                this.ViewCenter.X = cc[0];
+                this.ViewCenter.Y = cc[1];
+            }
+            else
+            {
+                this.ViewCenter = ObjectFactory.CreatePoint2D(cc[0], cc[1]);
+            }
+            this.ViewScale = d.ReadDouble();
+
+            this.DataExtent = DeserializeExtents(d);
+            this.DisplayDpi = d.ReadInt32();
+            this.DisplayWidth = d.ReadInt32();
+            this.DisplayHeight = d.ReadInt32();
+            this.BackgroundColor = Utility.ParseHTMLColor(d.ReadString());
+            this.MetersPerUnit = d.ReadDouble();
+
+            if (d.SiteVersion >= SiteVersions.GetVersion(KnownSiteVersions.MapGuideOS1_2))
+                this.LayerRefreshMode = d.ReadInt32();
+
+            var fds = new List<double>();
+            int finiteScaleCount = d.ReadInt32();
+            while (finiteScaleCount-- > 0)
+                fds.Add(d.ReadDouble());
+
+            _finiteDisplayScales = fds.ToArray();
+
+            m_changeList = new Dictionary<string, ChangeList>();
+            if (d.SiteVersion >= SiteVersions.GetVersion(KnownSiteVersions.MapGuideOS1_2))
+            {
+                m_changeList = DeserializeChangeMap(d);
+
+                int mapLayerCount = d.ReadInt32();
+                if (mapLayerCount != 0)
+                    throw new Exception("On new versions, there should be no layer data in map");
+            }
+            else
+            {
+                //ri.LayerGroupBlob = d.ReadStreamRepeat(d.ReadInt32());
+
+                DeserializeLayerData(d);
+                m_changeList = DeserializeChangeMap(d);
+            }
+
+            _disableChangeTracking = false;
+        }
+
+        private static IEnvelope DeserializeExtents(MgBinaryDeserializer d)
+        {
+            int classid = d.ReadClassId();
+            if (d.SiteVersion <= SiteVersions.GetVersion(KnownSiteVersions.MapGuideEP1_1) && classid != 18001)
+                throw new Exception("Invalid class identifier, expected Box2D");
+            if (d.SiteVersion > SiteVersions.GetVersion(KnownSiteVersions.MapGuideEP1_1) && classid != 20001)
+                throw new Exception("Invalid class identifier, expected Box2D");
+
+            int dimensions = d.ReadInt32();
+            if (dimensions != 2 && dimensions != 0)
+                throw new Exception("Bounding box for map had " + dimensions.ToString() + " dimensions, 2 was expected");
+            double x1 = d.ReadDouble();
+            double y1 = d.ReadDouble();
+
+            double x2 = d.ReadDouble();
+            double y2 = d.ReadDouble();
+
+            double minx = Math.Min(x1, x2);
+            double miny = Math.Min(y1, y2);
+            double maxx = Math.Max(x1, x2);
+            double maxy = Math.Max(y1, y2);
+
+            return ObjectFactory.CreateEnvelope(minx, miny, maxx, maxy);
+        }
+
+        private Dictionary<string, ChangeList> DeserializeChangeMap(MgBinaryDeserializer d)
+        {
+            Dictionary<string, ChangeList> changes = new Dictionary<string, ChangeList>();
+            int changeListCount = d.ReadInt32();
+            while (changeListCount-- > 0)
+            {
+                bool isLayer = d.ReadByte() > 0;
+                string objid = d.ReadString();
+
+                ChangeList c = null;
+                if (!changes.ContainsKey(objid))
+                {
+                    c = new ChangeList(objid, isLayer);
+                    changes.Add(c.ObjectId, c);
+                }
+                else
+                {
+                    c = changes[objid];
+                }
+                
+                int changeCount = d.ReadInt32();
+                while (changeCount-- > 0)
+                {
+                    //Split up to avoid dependency on argument evaluation order
+                    int ctype = d.ReadInt32();
+                    c.Changes.Add(new Change((Change.ChangeType)ctype, d.ReadString()));
+                }
+                
+            }
+            return changes;
+        }
+
+        internal void DeserializeLayerData(MgBinaryDeserializer d)
+        {
+            int groupCount = d.ReadInt32();
+
+            _groups.Clear();
+
+            for (int i = 0; i < groupCount; i++)
+            {
+                RuntimeMapGroup g = new RuntimeMapGroup();
+                g.Deserialize(d);
+                _groups.Add(g);
+            }
+
+            int mapLayerCount = d.ReadInt32();
+
+            _layers.Clear();
+            _layerIdMap.Clear();
+
+            while (mapLayerCount-- > 0)
+            {
+                RuntimeMapLayer t = new RuntimeMapLayer(this);
+                t.Deserialize(d);
+                AddLayerInternal(t);
+            }
+        }
+
+        /// <summary>
+        /// Gets the selection set
+        /// </summary>
+        /// <value>The selection.</value>
+        public MapSelection Selection
+        {
+            get;
+            private set;
+        }
+
+        /// <summary>
+        /// Gets the group by its specified name
+        /// </summary>
+        /// <param name="name">The name.</param>
+        /// <returns></returns>
+        public RuntimeMapGroup GetGroupByName(string name)
+        {
+            Check.NotNull(name, "name");
+            foreach (var group in _groups)
+            {
+                if (name.Equals(group.Name))
+                    return group;
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// Gets the layer by object id.
+        /// </summary>
+        /// <param name="id">The id.</param>
+        /// <returns></returns>
+        public RuntimeMapLayer GetLayerByObjectId(string id)
+        {
+            if (_layerIdMap.ContainsKey(id))
+                return _layerIdMap[id];
+
+            return null;
+        }
+
+        /// <summary>
+        /// Gets an array of all layers in this map
+        /// </summary>
+        /// <value>The layers.</value>
+        public RuntimeMapLayer[] Layers
+        {
+            get { return _layers.ToArray(); }
+        }
+
+        /// <summary>
+        /// Gets an array of all groups in this map
+        /// </summary>
+        /// <value>The groups.</value>
+        public RuntimeMapGroup[] Groups
+        {
+            get { return _groups.ToArray(); }
+        }
+
+        /// <summary>
+        /// A cache of Layer Definition objects. Used to reduce lookup time of the same layer definitions
+        /// </summary>
+        protected Dictionary<string, ILayerDefinition> layerDefinitionCache = new Dictionary<string, ILayerDefinition>();
+
+        /// <summary>
+        /// Creats and adds the layer to the map
+        /// </summary>
+        /// <param name="layerDefinitionId">The layer definition id.</param>
+        /// <param name="group">The group.</param>
+        /// <returns></returns>
+        public RuntimeMapLayer AddLayer(string layerDefinitionId, RuntimeMapGroup group)
+        {
+            ILayerDefinition ldf = GetLayerDefinition(layerDefinitionId);
+
+            var layer = new RuntimeMapLayer(this, ldf);
+
+            AddLayerInternal(layer);
+
+            return layer;
+        }
+
+        private ILayerDefinition GetLayerDefinition(string layerDefinitionId)
+        {
+            ILayerDefinition ldf = null;
+
+            if (layerDefinitionCache.ContainsKey(layerDefinitionId))
+            {
+                ldf = layerDefinitionCache[layerDefinitionId];
+            }
+            else
+            {
+                ResourceIdentifier.Validate(layerDefinitionId, ResourceTypes.LayerDefinition);
+                ldf = (ILayerDefinition)this.ResourceService.GetResource(layerDefinitionId);
+
+                layerDefinitionCache[layerDefinitionId] = ldf;
+            }
+            return ldf;
+        }
+
+        /// <summary>
+        /// Adds the layer.
+        /// </summary>
+        /// <param name="layer">The layer.</param>
+        protected void AddLayerInternal(RuntimeMapLayer layer)
+        {
+            _layers.Add(layer);
+            _layerIdMap[layer.ObjectId] = layer;
+
+            OnLayerAdded(layer);
+        }
+
+        /// <summary>
+        /// Creates the group and adds it to the map
+        /// </summary>
+        /// <param name="name">The name.</param>
+        /// <returns></returns>
+        public RuntimeMapGroup AddGroup(string name)
+        {
+            var group = new RuntimeMapGroup(this, name);
+            AddGroupInternal(group);
+            return group;
+        }
+
+        private void AddGroupInternal(RuntimeMapGroup group)
+        {
+            _groups.Add(group);
+            OnGroupAdded(group);
+        }
+
+        /// <summary>
+        /// Removes the layer
+        /// </summary>
+        /// <param name="layer">The layer.</param>
+        protected void RemoveLayerInternal(RuntimeMapLayer layer)
+        {
+            if (_layers.Remove(layer))
+            {
+                OnLayerRemoved(layer);
+            }
+        }
+
+        /// <summary>
+        /// Removes the specified layer.
+        /// </summary>
+        /// <param name="layer">The layer.</param>
+        public void RemoveLayer(RuntimeMapLayer layer)
+        {
+            Check.NotNull(layer, "layer");
+            RemoveLayerInternal(layer);
+        }
+
+        /// <summary>
+        /// Removes the specified group.
+        /// </summary>
+        /// <param name="group">The group.</param>
+        public void RemoveGroup(RuntimeMapGroup group)
+        {
+            Check.NotNull(group, "group");
+            RemoveGroupInternal(group);
+        }
+
+        private void RemoveGroupInternal(RuntimeMapGroup group)
+        {
+            if (_groups.Remove(group))
+            {
+                OnGroupRemoved(group);
+            }
+        }
+
+        /// <summary>
+        /// Gets the layers of the specified group
+        /// </summary>
+        /// <param name="groupName">Name of the group.</param>
+        /// <returns></returns>
+        public RuntimeMapLayer[] GetLayersOfGroup(string groupName)
+        {
+            Check.NotEmpty(groupName, "groupName");
+            List<RuntimeMapLayer> layers = new List<RuntimeMapLayer>();
+            foreach (var lyr in _layers)
+            {
+                if (groupName.Equals(lyr.Group))
+                    layers.Add(lyr);
+            }
+            return layers.ToArray();
+        }
+
+        /// <summary>
+        /// Saves this instance. The changes are propagated back to the MapGuide Server
+        /// </summary>
+        public virtual void Save()
+        {
+            Save(this.ResourceID);
+        }
+
+        /// <summary>
+        /// A dummy resource, used for the runtime map
+        /// </summary>
+        internal const string RUNTIMEMAP_XML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Map></Map>";
+
+        /// <summary>
+        /// A dummy resource, used for the runtime map
+        /// </summary>
+        internal const string RUNTIMEMAP_SELECTION_XML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Selection></Selection>";
+
+        private void Save(string resourceID)
+        {
+            var map = this;
+
+            string selectionID = resourceID.Substring(0, resourceID.LastIndexOf(".")) + ".Selection";
+            this.ResourceService.SetResourceXmlData(resourceID, new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(RUNTIMEMAP_XML)));
+            this.ResourceService.SetResourceXmlData(selectionID, new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(RUNTIMEMAP_SELECTION_XML)));
+
+            ResourceIdentifier.Validate(resourceID, ResourceTypes.RuntimeMap);
+            if (!resourceID.StartsWith("Session:" + this.SessionId + "//") || !resourceID.EndsWith(".Map"))
+                throw new Exception("Runtime maps must be in the current session repository");
+
+            System.IO.MemoryStream ms = new System.IO.MemoryStream();
+            System.IO.MemoryStream ms2 = null;
+
+            //Apparently the name is used to reconstruct the resourceId rather than pass it around
+            //inside the map server
+            string r = map.Name;
+            string t = map.ResourceID;
+
+            string mapname = resourceID.Substring(resourceID.IndexOf("//") + 2);
+            mapname = mapname.Substring(0, mapname.LastIndexOf("."));
+            map.Name = mapname;
+            map.ResourceID = resourceID;
+
+            try
+            {
+                map.Serialize(new MgBinarySerializer(ms, this.SiteVersion));
+                if (this.SiteVersion >= SiteVersions.GetVersion(KnownSiteVersions.MapGuideOS1_2))
+                {
+                    ms2 = new System.IO.MemoryStream();
+                    map.SerializeLayerData(new MgBinarySerializer(ms2, this.SiteVersion));
+                }
+
+                this.ResourceService.SetResourceData(resourceID, "RuntimeData", ResourceDataType.Stream, ms);
+                if (ms2 != null)
+                    this.ResourceService.SetResourceData(resourceID, "LayerGroupData", ResourceDataType.Stream, ms2);
+
+                SaveSelectionXml(resourceID);
+            }
+            finally
+            {
+                map.Name = r;
+                map.ResourceID = t;
+            }
+        }
+
+        private void SaveSelectionXml(string resourceID)
+        {
+            if (this.Selection == null)
+                return;
+
+            ResourceIdentifier.Validate(resourceID, ResourceTypes.RuntimeMap);
+            string selectionID = resourceID.Substring(0, resourceID.LastIndexOf(".")) + ".Selection";
+            System.IO.MemoryStream ms = new System.IO.MemoryStream();
+            MgBinarySerializer serializer = new MgBinarySerializer(ms, this.SiteVersion);
+            this.Selection.Serialize(serializer);
+            ms.Position = 0;
+            this.ResourceService.SetResourceData(selectionID, "RuntimeData", ResourceDataType.Stream, ms);
+        }
+
+        /// <summary>
+        /// Gets the layer by its specified name
+        /// </summary>
+        /// <param name="name">The name.</param>
+        /// <returns></returns>
+        public RuntimeMapLayer GetLayerByName(string name)
+        {
+            Check.NotEmpty(name, "name");
+            foreach (var layer in _layers)
+            {
+                if (name.Equals(layer.Name))
+                    return layer;
+            }
+            return null;
+        }
+
+        #region change tracking
+
+        //This mirrors the unmanaged implementation of MgMapBase
+        //Turns out the 2.x implementation didn't track these map element changes
+
+        internal void TrackChange(string objectId, bool isLayer, Change.ChangeType type, string param)
+        {
+            if (_disableChangeTracking)
+                return;
+
+            ChangeList changes = null;
+            if (m_changeList.ContainsKey(objectId))
+                changes = m_changeList[objectId];
+            else
+                changes = new ChangeList(objectId, isLayer);
+
+            var change = new Change(type, param);
+            changes.Changes.Add(change);
+        }
+
+        protected void ClearChanges()
+        {
+            m_changeList.Clear();
+        }
+
+        protected void OnGroupRemoved(RuntimeMapGroup group)
+        {
+            //???
+            var layers = GetLayersOfGroup(group.Name);
+            foreach (var lyr in layers)
+            {
+                RemoveLayerInternal(lyr);
+            }
+
+            TrackChange(group.ObjectId, false, Change.ChangeType.removed, string.Empty);
+        }
+
+        protected void OnGroupAdded(RuntimeMapGroup group)
+        {
+            //???
+
+            TrackChange(group.ObjectId, false, Change.ChangeType.added, string.Empty);
+        }
+
+        internal void OnGroupVisibilityChanged(RuntimeMapGroup group, string visbility)
+        {
+            TrackChange(group.ObjectId, false, Change.ChangeType.visibilityChanged, visbility);
+
+            //???
+        }
+
+        internal void OnGroupDisplayInLegendChanged(RuntimeMapGroup group, string displayInLegendState)
+        {
+            TrackChange(group.ObjectId, false, Change.ChangeType.displayInLegendChanged, displayInLegendState);
+        }
+
+        internal void OnGroupLegendLabelChanged(RuntimeMapGroup group, string legendLabel)
+        {
+            TrackChange(group.ObjectId, false, Change.ChangeType.legendLabelChanged, legendLabel);
+        }
+
+        internal void OnGroupParentChanged(RuntimeMapGroup group, string parentId)
+        {
+            TrackChange(group.ObjectId, false, Change.ChangeType.parentChanged, parentId);
+        }
+
+        internal void OnLayerRemoved(RuntimeMapLayer layer)
+        {
+            //???
+            if (_layerIdMap.ContainsKey(layer.ObjectId))
+                _layerIdMap.Remove(layer.ObjectId);
+
+            TrackChange(layer.ObjectId, true, Change.ChangeType.removed, string.Empty);
+        }
+
+        internal void OnLayerAdded(RuntimeMapLayer layer)
+        {
+            //???
+
+            TrackChange(layer.ObjectId, true, Change.ChangeType.added, string.Empty);
+        }
+
+        internal void OnLayerVisibilityChanged(RuntimeMapLayer layer, string visibility)
+        {
+            //???
+
+            TrackChange(layer.ObjectId, true, Change.ChangeType.visibilityChanged, visibility);
+        }
+
+        internal void OnLayerDisplayInLegendChanged(RuntimeMapLayer layer, string displayInLegendState)
+        {
+            TrackChange(layer.ObjectId, true, Change.ChangeType.displayInLegendChanged, displayInLegendState);
+        }
+
+        internal void OnLayerLegendLabelChanged(RuntimeMapLayer layer, string legendLabel)
+        {
+            TrackChange(layer.ObjectId, true, Change.ChangeType.legendLabelChanged, legendLabel);
+        }
+
+        internal void OnLayerParentChanged(RuntimeMapLayer layer, string parentId)
+        {
+            TrackChange(layer.ObjectId, true, Change.ChangeType.parentChanged, parentId);
+        }
+
+        internal void OnLayerSelectabilityChanged(RuntimeMapLayer layer, string selectability)
+        {
+            TrackChange(layer.ObjectId, true, Change.ChangeType.selectabilityChanged, selectability);
+        }
+
+        internal void OnLayerDefinitionChanged(RuntimeMapLayer layer)
+        {
+            TrackChange(layer.ObjectId, true, Change.ChangeType.definitionChanged, string.Empty);
+        }
+
+        #endregion
+    }
+}

Deleted: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Mapping/RuntimeMapBase.cs
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Mapping/RuntimeMapBase.cs	2010-11-05 08:34:47 UTC (rev 5373)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Mapping/RuntimeMapBase.cs	2010-11-05 10:17:38 UTC (rev 5374)
@@ -1,457 +0,0 @@
-#region Disclaimer / License
-// Copyright (C) 2010, Jackie Ng
-// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at gmail.com
-// 
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-// 
-#endregion
-using System;
-using System.Collections.Generic;
-using System.Text;
-using OSGeo.MapGuide.ObjectModels.MapDefinition;
-using OSGeo.MapGuide.MaestroAPI.Serialization;
-
-namespace OSGeo.MapGuide.MaestroAPI.Mapping
-{
-    /// <summary>
-    /// 
-    /// </summary>
-    public class RuntimeMapBase : IMapDefinition
-    {
-        /// <summary>
-        /// A dummy resource, used for the runtime map
-        /// </summary>
-        public const string RUNTIMEMAP_XML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Map></Map>";
-
-        /// <summary>
-        /// A dummy resource, used for the runtime map
-        /// </summary>
-        public const string RUNTIMEMAP_SELECTION_XML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Selection></Selection>";
-
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="RuntimeMapBase"/> class.
-        /// </summary>
-        /// <param name="mapDef">The map def.</param>
-        public RuntimeMapBase(IMapDefinition mapDef) { }
-
-        /// <summary>
-        /// Deserializes the specified mg binary deserializer.
-        /// </summary>
-        /// <param name="mgBinaryDeserializer">The mg binary deserializer.</param>
-        /// <returns></returns>
-        public static RuntimeMapBase Deserialize(MgBinaryDeserializer mgBinaryDeserializer)
-        {
-            throw new NotImplementedException();
-        }
-
-        /// <summary>
-        /// Gets or sets a value indicating whether this instance has loaded selection XML.
-        /// </summary>
-        /// <value>
-        /// 	<c>true</c> if this instance has loaded selection XML; otherwise, <c>false</c>.
-        /// </value>
-        public bool HasLoadedSelectionXml
-        {
-            get;
-            private set;
-        }
-
-        /// <summary>
-        /// Gets or sets the selection.
-        /// </summary>
-        /// <value>The selection.</value>
-        public MapSelectionBase Selection
-        {
-            get;
-            private set;
-        }
-
-        /// <summary>
-        /// Deserializes the layer data.
-        /// </summary>
-        /// <param name="mgBinaryDeserializer">The mg binary deserializer.</param>
-        public void DeserializeLayerData(MgBinaryDeserializer mgBinaryDeserializer)
-        {
-            throw new NotImplementedException();
-        }
-
-        /// <summary>
-        /// Serializes the specified mg binary serializer.
-        /// </summary>
-        /// <param name="mgBinarySerializer">The mg binary serializer.</param>
-        public void Serialize(MgBinarySerializer mgBinarySerializer)
-        {
-            throw new NotImplementedException();
-        }
-
-        /// <summary>
-        /// Serializes the layer data.
-        /// </summary>
-        /// <param name="mgBinarySerializer">The mg binary serializer.</param>
-        public void SerializeLayerData(MgBinarySerializer mgBinarySerializer)
-        {
-            throw new NotImplementedException();
-        }
-
-        /// <summary>
-        /// Gets or sets the name.
-        /// </summary>
-        /// <value>The name.</value>
-        public string Name
-        {
-            get
-            {
-                throw new NotImplementedException();
-            }
-            set
-            {
-                throw new NotImplementedException();
-            }
-        }
-
-        /// <summary>
-        /// Gets or sets the coordinate system.
-        /// </summary>
-        /// <value>The coordinate system.</value>
-        public string CoordinateSystem
-        {
-            get
-            {
-                throw new NotImplementedException();
-            }
-            set
-            {
-                throw new NotImplementedException();
-            }
-        }
-
-        /// <summary>
-        /// Gets or sets the extents.
-        /// </summary>
-        /// <value>The extents.</value>
-        public OSGeo.MapGuide.ObjectModels.Common.IEnvelope Extents
-        {
-            get
-            {
-                throw new NotImplementedException();
-            }
-            set
-            {
-                throw new NotImplementedException();
-            }
-        }
-
-        /// <summary>
-        /// Sets the extents.
-        /// </summary>
-        /// <param name="minx">The minx.</param>
-        /// <param name="miny">The miny.</param>
-        /// <param name="maxx">The maxx.</param>
-        /// <param name="maxy">The maxy.</param>
-        public void SetExtents(double minx, double miny, double maxx, double maxy)
-        {
-            throw new NotImplementedException();
-        }
-
-        /// <summary>
-        /// Gets or sets the color of the background.
-        /// </summary>
-        /// <value>The color of the background.</value>
-        public System.Drawing.Color BackgroundColor
-        {
-            get
-            {
-                throw new NotImplementedException();
-            }
-            set
-            {
-                throw new NotImplementedException();
-            }
-        }
-
-        /// <summary>
-        /// Gets or sets the metadata.
-        /// </summary>
-        /// <value>The metadata.</value>
-        public string Metadata
-        {
-            get
-            {
-                throw new NotImplementedException();
-            }
-            set
-            {
-                throw new NotImplementedException();
-            }
-        }
-
-        /// <summary>
-        /// Returns the base map section of this map definition. Ensure <see cref="InitBaseMap"/>
-        /// is called first before accessing this property
-        /// </summary>
-        /// <value></value>
-        public IBaseMapDefinition BaseMap
-        {
-            get { throw new NotImplementedException(); }
-        }
-
-        /// <summary>
-        /// Initializes the base map section of this map definition. Subsequent calls
-        /// do nothing, unless you have cleared the section via <see cref="RemoveBaseMap"/>
-        /// </summary>
-        public void InitBaseMap()
-        {
-            throw new NotImplementedException();
-        }
-
-        /// <summary>
-        /// Clears the base map section of this map definition. If you want to rebuild
-        /// this section, ensure <see cref="InitBaseMap"/> is called
-        /// </summary>
-        public void RemoveBaseMap()
-        {
-            throw new NotImplementedException();
-        }
-
-        /// <summary>
-        /// Gets the map layer.
-        /// </summary>
-        /// <value>The map layer.</value>
-        public IEnumerable<IMapLayer> MapLayer
-        {
-            get { throw new NotImplementedException(); }
-        }
-
-        /// <summary>
-        /// Adds a layer to this map. If this is the first layer to be added, the coordinate system
-        /// of this map and its extents will be set to the coordinate system and extents of this layer
-        /// if this has not been set already.
-        /// </summary>
-        /// <param name="groupName"></param>
-        /// <param name="layerName"></param>
-        /// <param name="resourceId"></param>
-        /// <returns></returns>
-        public IMapLayer AddLayer(string groupName, string layerName, string resourceId)
-        {
-            throw new NotImplementedException();
-        }
-
-        /// <summary>
-        /// Adds a layer to this map. If this is the first layer to be added, the coordinate system
-        /// of this map and its extents will be set to the coordinate system and extents of this layer
-        /// if this has not been set already.
-        /// </summary>
-        /// <param name="layerToInsertAbove">The layer to insert above in the draw order</param>
-        /// <param name="groupName"></param>
-        /// <param name="layerName"></param>
-        /// <param name="resourceId"></param>
-        /// <returns></returns>
-        public IMapLayer AddLayer(IMapLayer layerToInsertAbove, string groupName, string layerName, string resourceId)
-        {
-            throw new NotImplementedException();
-        }
-
-        /// <summary>
-        /// Removes the layer.
-        /// </summary>
-        /// <param name="layer">The layer.</param>
-        public void RemoveLayer(IMapLayer layer)
-        {
-            throw new NotImplementedException();
-        }
-
-        /// <summary>
-        /// Gets the index.
-        /// </summary>
-        /// <param name="layer">The layer.</param>
-        /// <returns></returns>
-        public int GetIndex(IMapLayer layer)
-        {
-            throw new NotImplementedException();
-        }
-
-        /// <summary>
-        /// Moves up.
-        /// </summary>
-        /// <param name="layer">The layer.</param>
-        /// <returns></returns>
-        public int MoveUp(IMapLayer layer)
-        {
-            throw new NotImplementedException();
-        }
-
-        /// <summary>
-        /// Moves down.
-        /// </summary>
-        /// <param name="layer">The layer.</param>
-        /// <returns></returns>
-        public int MoveDown(IMapLayer layer)
-        {
-            throw new NotImplementedException();
-        }
-
-        /// <summary>
-        /// Gets the map layer group.
-        /// </summary>
-        /// <value>The map layer group.</value>
-        public IEnumerable<IMapLayerGroup> MapLayerGroup
-        {
-            get { throw new NotImplementedException(); }
-        }
-
-        /// <summary>
-        /// Adds the group.
-        /// </summary>
-        /// <param name="groupName">Name of the group.</param>
-        /// <returns></returns>
-        public IMapLayerGroup AddGroup(string groupName)
-        {
-            throw new NotImplementedException();
-        }
-
-        /// <summary>
-        /// Removes the group.
-        /// </summary>
-        /// <param name="group">The group.</param>
-        public void RemoveGroup(IMapLayerGroup group)
-        {
-            throw new NotImplementedException();
-        }
-
-        /// <summary>
-        /// Gets the index.
-        /// </summary>
-        /// <param name="group">The group.</param>
-        /// <returns></returns>
-        public int GetIndex(IMapLayerGroup group)
-        {
-            throw new NotImplementedException();
-        }
-
-        /// <summary>
-        /// Sets the top draw order.
-        /// </summary>
-        /// <param name="layer">The layer.</param>
-        public void SetTopDrawOrder(IMapLayer layer)
-        {
-            throw new NotImplementedException();
-        }
-
-        /// <summary>
-        /// Sets the bottom draw order.
-        /// </summary>
-        /// <param name="layer">The layer.</param>
-        public void SetBottomDrawOrder(IMapLayer layer)
-        {
-            throw new NotImplementedException();
-        }
-
-        /// <summary>
-        /// Gets or sets the current connection.
-        /// </summary>
-        /// <value>The current connection.</value>
-        public IServerConnection CurrentConnection
-        {
-            get
-            {
-                throw new NotImplementedException();
-            }
-            set
-            {
-                throw new NotImplementedException();
-            }
-        }
-
-        /// <summary>
-        /// Gets the validating schema.
-        /// </summary>
-        /// <value>The validating schema.</value>
-        public string ValidatingSchema
-        {
-            get { throw new NotImplementedException(); }
-        }
-
-        /// <summary>
-        /// Gets or sets the resource ID.
-        /// </summary>
-        /// <value>The resource ID.</value>
-        public string ResourceID
-        {
-            get
-            {
-                throw new NotImplementedException();
-            }
-            set
-            {
-                throw new NotImplementedException();
-            }
-        }
-
-        /// <summary>
-        /// Gets the type of the resource.
-        /// </summary>
-        /// <value>The type of the resource.</value>
-        public ResourceTypes ResourceType
-        {
-            get { throw new NotImplementedException(); }
-        }
-
-        /// <summary>
-        /// Serializes this instance.
-        /// </summary>
-        /// <returns></returns>
-        public string Serialize()
-        {
-            throw new NotImplementedException();
-        }
-
-        /// <summary>
-        /// Indicates whether this resource is strongly typed. If false it means the implementer
-        /// is a <see cref="UntypedResource"/> object. This usually means that the matching serializer
-        /// could not be found because the resource version is unrecognised.
-        /// </summary>
-        /// <value></value>
-        public bool IsStronglyTyped
-        {
-            get { throw new NotImplementedException(); }
-        }
-
-        /// <summary>
-        /// Gets the resource version.
-        /// </summary>
-        /// <value>The resource version.</value>
-        public Version ResourceVersion
-        {
-            get { throw new NotImplementedException(); }
-        }
-
-        /// <summary>
-        /// Creates a new object that is a copy of the current instance.
-        /// </summary>
-        /// <returns>
-        /// A new object that is a copy of this instance.
-        /// </returns>
-        public object Clone()
-        {
-            throw new NotImplementedException();
-        }
-
-        /// <summary>
-        /// Occurs when a property value changes.
-        /// </summary>
-        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
-    }
-}

Added: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Mapping/RuntimeMapGroup.cs
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Mapping/RuntimeMapGroup.cs	                        (rev 0)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Mapping/RuntimeMapGroup.cs	2010-11-05 10:17:38 UTC (rev 5374)
@@ -0,0 +1,233 @@
+#region Disclaimer / License
+// Copyright (C) 2010, Jackie Ng
+// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at gmail.com
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+// 
+#endregion
+using System;
+using System.Collections.Generic;
+using System.Text;
+using OSGeo.MapGuide.ObjectModels.MapDefinition;
+using OSGeo.MapGuide.MaestroAPI.Serialization;
+
+namespace OSGeo.MapGuide.MaestroAPI.Mapping
+{
+    public class RuntimeMapGroup : MapObservable
+    {
+        //From MgLayerGroupType
+        internal const int kBaseMap = 2;
+        internal const int kNormal = 1;
+
+        internal RuntimeMapGroup() 
+        {
+            this.Type = kNormal;
+            this.ObjectId = Guid.NewGuid().ToString();
+        }
+
+        internal RuntimeMapGroup(RuntimeMap map, string name) 
+            : this()
+        {
+            this.Parent = map;
+            this.Name = name;
+        }
+
+        internal RuntimeMapGroup(RuntimeMap map, IMapLayerGroup group)
+            : this(map, group.Name)
+        {
+            this.ExpandInLegend = group.ExpandInLegend;
+            this.LegendLabel = group.LegendLabel;
+            this.ShowInLegend = group.ShowInLegend;
+            this.Visible = group.Visible;
+
+            this.Type = kNormal;
+        }
+
+        internal RuntimeMapGroup(RuntimeMap map, IBaseMapGroup group)
+            : this(map, group.Name)
+        {
+            this.ExpandInLegend = group.ExpandInLegend;
+            this.LegendLabel = group.LegendLabel;
+            this.ShowInLegend = group.ShowInLegend;
+            this.Visible = group.Visible;
+
+            this.Type = kBaseMap;
+        }
+
+        private bool _visible;
+
+        public bool Visible
+        {
+            get
+            {
+                return _visible;
+            }
+            set
+            {
+                SetField(ref _visible, value, "Visible");
+            }
+        }
+
+        private string _group;
+
+        public string Group
+        {
+            get
+            {
+                return _group;
+            }
+            set
+            {
+                SetField(ref _group, value, "Group");
+            }
+        }
+
+        public RuntimeMap Parent
+        {
+            get;
+            internal set;
+        }
+
+        private string _name;
+
+        public string Name
+        {
+            get
+            {
+                return _name;
+            }
+            set
+            {
+                SetField(ref _name, value, "Name");
+            }
+        }
+
+        private bool _showInLegend;
+
+        public bool ShowInLegend
+        {
+            get
+            {
+                return _showInLegend;
+            }
+            set
+            {
+                SetField(ref _showInLegend, value, "ShowInLegend");
+            }
+        }
+
+        private string _legendLabel;
+
+        public string LegendLabel
+        {
+            get
+            {
+                return _legendLabel;
+            }
+            set
+            {
+                SetField(ref _legendLabel, value, "LegendLabel");
+            }
+        }
+
+        private bool _expandInLegend;
+
+        public bool ExpandInLegend
+        {
+            get
+            {
+                return _expandInLegend;
+            }
+            set
+            {
+                SetField(ref _expandInLegend, value, "ExpandInLegend");
+            }
+        }
+
+        public int Type
+        {
+            get;
+            private set;
+        }
+
+        public string ObjectId
+        {
+            get;
+            private set;
+        }
+
+        public void Serialize(MgBinarySerializer s)
+        {
+            s.Write(this.Group);
+            if (s.SiteVersion >= SiteVersions.GetVersion(KnownSiteVersions.MapGuideOS1_2))
+                s.WriteClassId(12001);
+            else
+                s.WriteClassId(19001);
+            s.Write(this.Name);
+            s.Write(this.ObjectId);
+            s.Write(this.Type);
+            s.Write(this.Visible);
+            s.Write(this.ShowInLegend);
+            s.Write(this.ExpandInLegend);
+            s.Write(this.LegendLabel);
+        }
+
+        public void Deserialize(MgBinaryDeserializer d)
+        {
+            this.Group = d.ReadString();
+            int objid = d.ReadClassId();
+            if (d.SiteVersion >= SiteVersions.GetVersion(KnownSiteVersions.MapGuideOS1_2))
+            {
+                if (objid != 12001)
+                    throw new Exception("Group must have object id 12001, but had: " + objid);
+            }
+            else if (objid != 19001)
+                throw new Exception("Group must have object id 19001, but had: " + objid);
+
+            this.Name = d.ReadString();
+            this.ObjectId = d.ReadString();
+            this.Type = d.ReadInt32();
+            this.Visible = d.ReadBool();
+            this.ShowInLegend = d.ReadBool();
+            this.ExpandInLegend = d.ReadBool();
+            this.LegendLabel = d.ReadString();
+        }
+
+        protected override void OnPropertyChanged(string propertyName)
+        {
+            if (_disableChangeTracking)
+                return;
+
+            //register change items on map
+            switch (propertyName)
+            {
+                case "Group":
+                    this.Parent.OnGroupParentChanged(this, this.ObjectId);
+                    break;
+                case "Visible":
+                    this.Parent.OnGroupVisibilityChanged(this, this.Visible ? "1" : "0");
+                    break;
+                case "ShowInLegend":
+                    this.Parent.OnGroupDisplayInLegendChanged(this, this.ShowInLegend ? "1" : "0");
+                    break;
+                case "LegendLabel":
+                    this.Parent.OnGroupLegendLabelChanged(this, this.LegendLabel);
+                    break;
+            }
+
+            base.OnPropertyChanged(propertyName);
+        }
+    }
+}

Added: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Mapping/RuntimeMapLayer.cs
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Mapping/RuntimeMapLayer.cs	                        (rev 0)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Mapping/RuntimeMapLayer.cs	2010-11-05 10:17:38 UTC (rev 5374)
@@ -0,0 +1,693 @@
+#region Disclaimer / License
+// Copyright (C) 2010, Jackie Ng
+// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at gmail.com
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+// 
+#endregion
+using System;
+using System.Collections.Generic;
+using System.Text;
+using OSGeo.MapGuide.ObjectModels.MapDefinition;
+using OSGeo.MapGuide.ObjectModels.LayerDefinition;
+using OSGeo.MapGuide.MaestroAPI.Serialization;
+using OSGeo.MapGuide.MaestroAPI.Resource;
+
+namespace OSGeo.MapGuide.MaestroAPI.Mapping
+{
+    /// <summary>
+    /// Describes a FDO property
+    /// </summary>
+    public class PropertyInfo
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="PropertyInfo"/> class.
+        /// </summary>
+        /// <param name="name">The name.</param>
+        /// <param name="type">The type.</param>
+        public PropertyInfo(string name, Type type)
+        {
+            this.Name = name;
+            this.Type = type;
+        }
+
+        /// <summary>
+        /// Gets or sets the name.
+        /// </summary>
+        /// <value>The name.</value>
+        public string Name { get; set; }
+
+        /// <summary>
+        /// Gets or sets the type.
+        /// </summary>
+        /// <value>The type.</value>
+        public Type Type { get; set; }
+    }
+    /// <summary>
+    /// Represents a runtime map layer
+    /// </summary>
+    public class RuntimeMapLayer : MapObservable
+    {
+        //From MgLayerType
+        internal const int kBaseMap = 2;
+        internal const int kDynamic = 1;
+
+        const double InfinityScale = double.MaxValue;
+
+        internal RuntimeMap Parent { get; private set; }
+
+        internal RuntimeMapLayer(RuntimeMap parent) 
+        {
+            _scaleRanges = new double[] { 0.0, InfinityScale };
+            this.Type = kDynamic;
+            this.IdentityProperties = new PropertyInfo[0];
+            this.ObjectId = Guid.NewGuid().ToString();
+            this.Parent = parent;
+        }
+
+        internal RuntimeMapLayer(RuntimeMap parent, ILayerDefinition ldf)
+            : this(parent)
+        {
+            Check.NotNull(ldf, "ldf");
+
+            this.LayerDefinitionID = ldf.ResourceID;
+            this.ExpandInLegend = false;
+            this.Group = null;
+            this.Name = ResourceIdentifier.GetName(ldf.ResourceID);
+            this.Selectable = true;
+            this.ShowInLegend = true;
+            this.Visible = true;
+        }
+
+        internal RuntimeMapLayer(RuntimeMap parent, IMapLayer source, ILayerDefinition ldf)
+            : this(parent, (IBaseMapLayer)source, ldf)
+        {
+            this.Group = source.Group;
+            this.Visible = source.Visible;
+        }
+
+        internal RuntimeMapLayer(RuntimeMap parent, IBaseMapLayer source, ILayerDefinition ldf) 
+            : this(parent, ldf)
+        {
+            Check.NotNull(source, "source");
+            Check.NotNull(ldf, "ldf");
+            Check.Precondition(source.ResourceId == ldf.ResourceID, "source.ResourceId == ldf.ResourceID");
+
+            this.LayerDefinitionID = source.ResourceId;
+            this.ExpandInLegend = source.ExpandInLegend;
+            this.Name = source.Name;
+            this.Selectable = source.Selectable;
+            this.ShowInLegend = source.ShowInLegend;
+            this.LegendLabel = source.LegendLabel;
+
+            this.NeedsRefresh = false;
+            this.DisplayOrder = 0;
+
+            switch (ldf.SubLayer.LayerType)
+            {
+                case LayerType.Drawing:
+                    {
+                    }
+                    break;
+                case LayerType.Raster:
+                    {
+                        IRasterLayerDefinition rdf = (IRasterLayerDefinition)ldf.SubLayer;
+                        this.FeatureSourceID = rdf.ResourceId;
+                        this.GeometryPropertyName = rdf.Geometry;
+                        this.QualifiedClassName = rdf.FeatureName;
+
+                        if (rdf.GridScaleRange.Count > 0)
+                        {
+                            _scaleRanges = new double[rdf.GridScaleRange.Count * 2];
+                            int i = 0;
+                            foreach (var gsr in rdf.GridScaleRange)
+                            {
+                                _scaleRanges[i * 2] = gsr.MinScale.HasValue ? gsr.MinScale.Value : 0;
+                                _scaleRanges[i * 2 + 1] = gsr.MaxScale.HasValue ? gsr.MaxScale.Value : InfinityScale;
+                                i++;
+                            }
+                        }
+                    }
+                    break;
+                case LayerType.Vector:
+                    {
+                        IVectorLayerDefinition vld = (IVectorLayerDefinition)ldf.SubLayer;
+                        this.FeatureSourceID = vld.ResourceId;
+                        this.GeometryPropertyName = vld.Geometry;
+                        this.QualifiedClassName = vld.FeatureName;
+                        this.Filter = vld.Filter;
+
+                        if (vld.HasVectorScaleRanges())
+                        {
+                            int vsrCount = vld.GetScaleRangeCount();
+                            _scaleRanges = new double[vsrCount * 2];
+                            for (int i = 0; i < vsrCount; i++)
+                            {
+                                var vsr = vld.GetScaleRangeAt(i);
+                                _scaleRanges[i * 2] = vsr.MinScale.HasValue ? vsr.MinScale.Value : 0;
+                                _scaleRanges[i * 2 + 1] = vsr.MaxScale.HasValue ? vsr.MaxScale.Value : InfinityScale;
+                            }
+                        }
+                        this.HasTooltips = !string.IsNullOrEmpty(vld.ToolTip);
+                        //get identity property information
+
+                    }
+                    break;
+            }
+        }
+
+        private bool _visible;
+
+        /// <summary>
+        /// Gets or sets a value indicating whether this <see cref="RuntimeMapLayer"/> is visible.
+        /// </summary>
+        /// <value><c>true</c> if visible; otherwise, <c>false</c>.</value>
+        public bool Visible
+        {
+            get
+            {
+                return _visible;
+            }
+            set
+            {
+                SetField(ref _visible, value, "Visible");
+            }
+        }
+
+        private string _group;
+
+        /// <summary>
+        /// Gets or sets the group.
+        /// </summary>
+        /// <value>The group.</value>
+        public string Group
+        {
+            get
+            {
+                return _group;
+            }
+            set
+            {
+                SetField(ref _group, value, "Group");
+            }
+        }
+
+        /// <summary>
+        /// Gets the layer definition ID.
+        /// </summary>
+        /// <value>The layer definition ID.</value>
+        public string LayerDefinitionID
+        {
+            get;
+            private set;
+        }
+
+        private bool _selectable;
+
+        /// <summary>
+        /// Gets or sets a value indicating whether this <see cref="RuntimeMapLayer"/> is selectable.
+        /// </summary>
+        /// <value><c>true</c> if selectable; otherwise, <c>false</c>.</value>
+        public bool Selectable
+        {
+            get
+            {
+                return _selectable;
+            }
+            set
+            {
+                SetField(ref _selectable, value, "Selectable");
+            }
+        }
+
+        private string _name;
+
+        /// <summary>
+        /// Gets or sets the name.
+        /// </summary>
+        /// <value>The name.</value>
+        public string Name
+        {
+            get
+            {
+                return _name;
+            }
+            set
+            {
+                SetField(ref _name, value, "Name");
+            }
+        }
+
+        private bool _showInLegend;
+
+        /// <summary>
+        /// Gets or sets a value indicating whether [show in legend].
+        /// </summary>
+        /// <value><c>true</c> if [show in legend]; otherwise, <c>false</c>.</value>
+        public bool ShowInLegend
+        {
+            get
+            {
+                return _showInLegend;
+            }
+            set
+            {
+                SetField(ref _showInLegend, value, "ShowInLegend");
+            }
+        }
+
+        private string _legendLabel;
+
+        /// <summary>
+        /// Gets or sets the legend label.
+        /// </summary>
+        /// <value>The legend label.</value>
+        public string LegendLabel
+        {
+            get
+            {
+                return _legendLabel;
+            }
+            set
+            {
+                SetField(ref _legendLabel, value, "LegendLabel");
+            }
+        }
+
+        private bool _expandInLegend;
+
+        /// <summary>
+        /// Gets or sets a value indicating whether [expand in legend].
+        /// </summary>
+        /// <value><c>true</c> if [expand in legend]; otherwise, <c>false</c>.</value>
+        public bool ExpandInLegend
+        {
+            get
+            {
+                return _expandInLegend;
+            }
+            set
+            {
+                SetField(ref _expandInLegend, value, "ExpandInLegend");
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the feature source ID.
+        /// </summary>
+        /// <value>The feature source ID.</value>
+        public string FeatureSourceID
+        {
+            get;
+            internal set;
+        }
+
+        /// <summary>
+        /// Gets or sets the name of the qualified class.
+        /// </summary>
+        /// <value>The name of the qualified class.</value>
+        public string QualifiedClassName
+        {
+            get;
+            internal set;
+        }
+
+        /// <summary>
+        /// Gets the identity properties.
+        /// </summary>
+        /// <value>The identity properties.</value>
+        public PropertyInfo[] IdentityProperties
+        {
+            get;
+            private set;
+        }
+
+        /// <summary>
+        /// Gets the object id.
+        /// </summary>
+        /// <value>The object id.</value>
+        public string ObjectId
+        {
+            get;
+            internal set;
+        }
+
+        /// <summary>
+        /// Gets the name of the geometry property.
+        /// </summary>
+        /// <value>The name of the geometry property.</value>
+        public string GeometryPropertyName
+        {
+            get;
+            private set;
+        }
+
+        /// <summary>
+        /// Gets the filter.
+        /// </summary>
+        /// <value>The filter.</value>
+        public string Filter
+        {
+            get;
+            internal set;
+        }
+
+        public int Type
+        {
+            get;
+            internal set;
+        }
+
+        public double DisplayOrder
+        {
+            get;
+            internal set;
+        }
+
+        public bool NeedsRefresh
+        {
+            get;
+            internal set;
+        }
+
+        public bool HasTooltips
+        {
+            get;
+            internal set;
+        }
+
+        public string SchemaName
+        {
+            get
+            {
+                var tokens = this.QualifiedClassName.Split(':');
+                if (tokens.Length == 2)
+                    return tokens[0];
+                return string.Empty;
+            }
+        }
+
+        private double[] _scaleRanges;
+
+        public void Serialize(MgBinarySerializer s)
+        {
+            s.Write(this.Group);
+
+            if (s.SiteVersion <= SiteVersions.GetVersion(KnownSiteVersions.MapGuideEP1_1))
+                s.WriteClassId(19003);
+            else
+                s.WriteClassId(30501);
+
+            s.WriteResourceIdentifier(this.LayerDefinitionID);
+
+            if (s.SiteVersion < SiteVersions.GetVersion(KnownSiteVersions.MapGuideOS1_2))
+            {
+                s.Write(this.Name);
+                s.Write(this.ObjectId);
+
+                s.Write(this.Type);
+
+                s.Write((byte)(this.Visible ? 1 : 0));
+                s.Write((byte)(this.Selectable ? 1 : 0));
+                s.Write((byte)(this.ShowInLegend ? 1 : 0));
+                s.Write((byte)(this.ExpandInLegend ? 1 : 0));
+
+                s.Write(this.LegendLabel);
+                s.Write((byte)(this.NeedsRefresh ? 1 : 0));
+                s.Write(this.DisplayOrder);
+
+                s.Write(_scaleRanges.Length);
+                foreach (double d in _scaleRanges)
+                    s.Write(d);
+
+                s.Write(this.FeatureSourceID);
+                s.Write(this.QualifiedClassName);
+                s.Write(this.GeometryPropertyName);
+
+                s.Write(this.IdentityProperties.Length);
+                foreach (var x in this.IdentityProperties)
+                {
+                    s.Write((short)ConvertNetTypeToMgType(x.Type));
+                    s.Write(x.Name);
+                }
+            }
+            else
+            {
+                s.WriteStringInternal(this.Name);
+                s.WriteStringInternal(this.ObjectId);
+                s.WriteRaw(BitConverter.GetBytes(this.Type));
+                int flags = 0;
+                flags |= this.Visible ? 1 : 0;
+                flags |= this.Selectable ? 2 : 0;
+                flags |= this.ShowInLegend ? 4 : 0;
+                flags |= this.ExpandInLegend ? 8 : 0;
+                flags |= this.NeedsRefresh ? 16 : 0;
+                flags |= this.HasTooltips ? 32 : 0;
+                s.WriteRaw(new byte[] { (byte)flags });
+
+                s.WriteStringInternal(this.LegendLabel);
+                s.WriteRaw(BitConverter.GetBytes(this.DisplayOrder));
+
+                s.WriteRaw(BitConverter.GetBytes(_scaleRanges.Length));
+                foreach (double d in _scaleRanges)
+                    s.WriteRaw(BitConverter.GetBytes(d));
+
+                s.WriteStringInternal(this.FeatureSourceID);
+                s.WriteStringInternal(this.QualifiedClassName);
+                if (s.SiteVersion > SiteVersions.GetVersion(KnownSiteVersions.MapGuideOS2_1))
+                    s.WriteStringInternal(this.Filter);
+                s.WriteStringInternal(this.SchemaName);
+                s.WriteStringInternal(this.GeometryPropertyName);
+
+                s.WriteRaw(BitConverter.GetBytes(this.IdentityProperties.Length));
+                foreach (var x in this.IdentityProperties)
+                {
+                    s.WriteRaw(BitConverter.GetBytes((short)ConvertNetTypeToMgType(x.Type)));
+                    s.WriteStringInternal(x.Name);
+                }
+            }
+        }
+
+        public void Deserialize(MgBinaryDeserializer d)
+        {
+            this.Group = d.ReadString();
+
+            int classid = d.ReadClassId();
+            if (d.SiteVersion <= SiteVersions.GetVersion(KnownSiteVersions.MapGuideEP1_1) && classid != 19003)
+                throw new Exception("Resource Identifier expected, but got: " + classid.ToString());
+            if (d.SiteVersion > SiteVersions.GetVersion(KnownSiteVersions.MapGuideEP1_1) && classid != 30501)
+                throw new Exception("Resource Identifier expected, but got: " + classid.ToString());
+
+            this.LayerDefinitionID = d.ReadResourceIdentifier();
+
+            if (d.SiteVersion < SiteVersions.GetVersion(KnownSiteVersions.MapGuideOS1_2))
+            {
+                this.Name = d.ReadString();
+                this.ObjectId = d.ReadString();
+                this.Type = d.ReadInt32();
+
+                this.Visible = d.ReadByte() > 0;
+                this.Selectable = d.ReadByte() > 0;
+                this.ShowInLegend = d.ReadByte() > 0;
+                this.ExpandInLegend = d.ReadByte() > 0;
+
+                this.LegendLabel = d.ReadString();
+                this.NeedsRefresh = d.ReadByte() > 0;
+                this.DisplayOrder = d.ReadDouble();
+
+                var scaleRanges = new List<double>();
+                int scales = d.ReadInt32();
+                while (scales-- > 0)
+                    scaleRanges.Add(d.ReadDouble());
+
+                _scaleRanges = scaleRanges.ToArray();
+                
+                this.FeatureSourceID = d.ReadString();
+                this.QualifiedClassName = d.ReadString();
+                this.GeometryPropertyName = d.ReadString();
+
+                var ids = new List<PropertyInfo>();
+                int idCount = d.ReadInt32();
+
+                while (idCount-- > 0)
+                {
+                    short idType = d.ReadInt16();
+                    string idName = d.ReadString();
+                    ids.Add(new PropertyInfo(idName, ConvertMgTypeToNetType(idType)));
+                }
+
+                this.IdentityProperties = ids.ToArray();
+            }
+            else
+            {
+                //AAARGH!!! Now they bypass their own header system ....
+                this.Name = d.ReadInternalString();
+                this.ObjectId = d.ReadInternalString();
+                this.Type = BitConverter.ToInt32(d.ReadStreamRepeat(4), 0);
+
+                int flags = d.ReadStreamRepeat(1)[0];
+                this.Visible = (flags & 1) > 0;
+                this.Selectable = (flags & 2) > 0;
+                this.ShowInLegend = (flags & 4) > 0;
+                this.ExpandInLegend = (flags & 8) > 0;
+                this.NeedsRefresh = (flags & 16) > 0;
+                this.HasTooltips = (flags & 32) > 0;
+
+                this.LegendLabel = d.ReadInternalString();
+                this.DisplayOrder = BitConverter.ToDouble(d.ReadStreamRepeat(8), 0);
+
+                var scaleRanges = new List<double>();
+                int scales = BitConverter.ToInt32(d.ReadStreamRepeat(4), 0);
+                while (scales-- > 0)
+                    scaleRanges.Add(BitConverter.ToDouble(d.ReadStreamRepeat(8), 0));
+
+                _scaleRanges = scaleRanges.ToArray();
+                
+                this.FeatureSourceID = d.ReadInternalString();
+                this.QualifiedClassName = d.ReadInternalString();
+                if (d.SiteVersion > SiteVersions.GetVersion(KnownSiteVersions.MapGuideOS2_1))
+                    this.Filter = d.ReadInternalString();
+                //this.SchemaName = d.ReadInternalString();
+                d.ReadInternalString();
+                this.GeometryPropertyName = d.ReadInternalString();
+
+                var ids = new List<PropertyInfo>();
+                int idCount = BitConverter.ToInt32(d.ReadStreamRepeat(4), 0);
+
+                while (idCount-- > 0)
+                {
+                    short idType = BitConverter.ToInt16(d.ReadStreamRepeat(2), 0);
+                    string idName = d.ReadInternalString();
+                    ids.Add(new PropertyInfo(idName, ConvertMgTypeToNetType(idType)));
+                }
+
+                this.IdentityProperties = ids.ToArray();
+            }
+        }
+
+        //from MgPropertyType
+        const int Blob = 10;
+        const int Boolean = 1;
+        const int Byte = 2;
+        const int Clob = 11;
+        const int DateTime = 3;
+        const int Double = 5;
+        const int Feature = 12;
+        const int Geometry = 13;
+        const int Int16 = 6;
+        const int Int32 = 7;
+        const int Int64 = 8;
+        const int Null = 0;
+        const int Raster = 14;
+        const int Single = 4;
+        const int String = 9;
+
+        private static short ConvertNetTypeToMgType(Type type)
+        {
+            if (type == typeof(short))
+                return Int16;
+            else if (type == typeof(byte))
+                return Byte;
+            else if (type == typeof(bool))
+                return Boolean;
+            else if (type == typeof(int))
+                return Int32;
+            else if (type == typeof(long))
+                return Int64;
+            else if (type == typeof(float))
+                return Single;
+            else if (type == typeof(double))
+                return Double;
+            else if (type == Utility.GeometryType)
+                return Geometry;
+            else if (type == typeof(string))
+                return String;
+            else if (type == typeof(DateTime))
+                return DateTime;
+            else if (type == Utility.RasterType)
+                return Raster;
+            else if (type == typeof(byte[]))
+                return Blob;
+
+            throw new Exception("Failed to find type for: " + type.FullName.ToString());
+        }
+
+        private static Type ConvertMgTypeToNetType(short idType)
+        {
+            switch (idType)
+            {
+                case Byte:
+                    return typeof(byte);
+                case Int16:
+                    return typeof(short);
+                case Int32:
+                    return typeof(int);
+                case Int64:
+                    return typeof(long);
+                case Single:
+                    return typeof(float);
+                case Double:
+                    return typeof(double);
+                case Boolean:
+                    return typeof(bool);
+                case Geometry:
+                    return Utility.GeometryType;
+                case String:
+                    return typeof(string);
+                case DateTime:
+                    return typeof(DateTime);
+                case Raster:
+                    return Utility.RasterType;
+                case Blob:
+                    return typeof(byte[]);
+                case Clob:
+                    return typeof(byte[]);
+                default:
+                    throw new Exception("Failed to find type for: " + idType.ToString());
+            }
+        }
+
+        protected override void OnPropertyChanged(string propertyName)
+        {
+            if (_disableChangeTracking)
+                return;
+
+            //register change items on map
+            switch (propertyName)
+            {
+                case "Group":
+                    this.Parent.OnLayerParentChanged(this, this.ObjectId);
+                    break;
+                case "Visible":
+                    this.Parent.OnLayerVisibilityChanged(this, this.Visible ? "1" : "0");
+                    break;
+                case "ShowInLegend":
+                    this.Parent.OnLayerDisplayInLegendChanged(this, this.ShowInLegend ? "1" : "0");
+                    break;
+                case "LegendLabel":
+                    this.Parent.OnLayerLegendLabelChanged(this, this.LegendLabel);
+                    break;
+                case "LayerDefinitionID":
+                    this.Parent.OnLayerDefinitionChanged(this);
+                    break;
+                case "Selectable":
+                    this.Parent.OnLayerSelectabilityChanged(this, this.Selectable ? "1" : "0");
+                    break;
+            }
+
+            base.OnPropertyChanged(propertyName);
+        }
+    }
+}

Modified: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/MgServerConnectionBase.cs
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/MgServerConnectionBase.cs	2010-11-05 08:34:47 UTC (rev 5373)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/MgServerConnectionBase.cs	2010-11-05 10:17:38 UTC (rev 5374)
@@ -30,6 +30,7 @@
 using OSGeo.MapGuide.MaestroAPI.Resource;
 using OSGeo.MapGuide.MaestroAPI.Commands;
 using OSGeo.MapGuide.ObjectModels.LoadProcedure;
+using OSGeo.MapGuide.MaestroAPI.Mapping;
 
 namespace OSGeo.MapGuide.MaestroAPI
 {
@@ -142,70 +143,6 @@
 
         #endregion
 
-        #region Runtime Map
-
-
-        /// <summary>
-        /// Selects features from a runtime map, returning a selection Xml.
-        /// </summary>
-        /// <param name="runtimemap">The map to query. NOT a resourceID, only the map name!</param>
-        /// <param name="wkt">The WKT of the geometry to query with (always uses intersection)</param>
-        /// <param name="persist">True if the selection should be saved in the runtime map, false otherwise.</param>
-        /// <returns>The selection Xml, or an empty string if there were no data.</returns>
-        public string QueryMapFeatures(string runtimemap, string wkt, bool persist)
-        {
-            return QueryMapFeatures(runtimemap, wkt, persist, QueryMapFeaturesLayerAttributes.Default, false);
-        }
-
-        /// <summary>
-        /// Selects features from a runtime map, returning a selection Xml.
-        /// </summary>
-        /// <param name="runtimemap">The map to query. NOT a resourceID, only the map name!</param>
-        /// <param name="wkt">The WKT of the geometry to query with (always uses intersection)</param>
-        /// <param name="persist">True if the selection should be saved in the runtime map, false otherwise.</param>
-        /// <param name="attributes">The type of layer to include in the query</param>
-        /// <param name="raw">True if the result should contain the tooltip and link info</param>
-        /// <returns>The selection Xml, or an empty string if there were no data.</returns>
-        abstract public string QueryMapFeatures(string runtimemap, string wkt, bool persist, QueryMapFeaturesLayerAttributes attributes, bool raw);
-
-        /// <summary>
-        /// Sets the selection of a map
-        /// </summary>
-        /// <param name="runtimeMap">The resourceID of the runtime map</param>
-        /// <param name="selectionXml">The selection xml</param>
-        abstract public void SetSelectionXml(string runtimeMap, string selectionXml);
-
-        /// <summary>
-        /// Gets the selection from a map
-        /// </summary>
-        /// <param name="runtimeMap">The resourceID of the runtime map</param>
-        /// <returns>The selection xml</returns>
-        abstract public string GetSelectionXml(string runtimeMap);
-
-        /// <summary>
-        /// Creates a runtime map on the server. 
-        /// The map name will be the name of the resource, without path information.
-        /// This is equivalent to the way the AJAX viewer creates the runtime map.
-        /// </summary>
-        /// <param name="resourceID">The mapDefinition resource id</param>
-        public virtual void CreateRuntimeMap(string resourceID)
-        {
-            ResourceIdentifier.Validate(resourceID, ResourceTypes.MapDefinition);
-            ResourceIdentifier ri = new ResourceIdentifier(resourceID);
-            ri.Path = ri.Name;
-            ri.Extension = EnumHelper.ResourceName(ResourceTypes.RuntimeMap);
-            CreateRuntimeMap(ri, resourceID);
-        }
-
-        /// <summary>
-        /// Creates a runtime map on the server
-        /// </summary>
-        /// <param name="resourceID">The target resource id for the runtime map</param>
-        /// <param name="mapdefinition">The mapdefinition to base the map on</param>
-        abstract public void CreateRuntimeMap(string resourceID, string mapdefinition);
-
-        #endregion
-
         #region Rendering
 
         /// <summary>
@@ -318,6 +255,10 @@
         /// <returns></returns>
         public abstract System.IO.Stream RenderRuntimeMap(string resourceId, double x1, double y1, double x2, double y2, int width, int height, int dpi, string format, bool clip);
 
+        public abstract System.IO.Stream RenderDynamicOverlay(RuntimeMap map, MapSelection selection, string format);
+
+        public abstract System.IO.Stream RenderDynamicOverlay(RuntimeMap map, MapSelection selection, string format, bool keepSelection);
+
         #endregion
 
         #region Tile

Modified: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/OSGeo.MapGuide.MaestroAPI.csproj
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/OSGeo.MapGuide.MaestroAPI.csproj	2010-11-05 08:34:47 UTC (rev 5373)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/OSGeo.MapGuide.MaestroAPI.csproj	2010-11-05 10:17:38 UTC (rev 5374)
@@ -196,15 +196,18 @@
     <Compile Include="Feature\FeatureSourceDescription.cs" />
     <Compile Include="IO\FileBufferedStreamReader.cs" />
     <Compile Include="CoordinateSystem\ICoordinateSystemCatalog.cs" />
-    <Compile Include="Mapping\MapSelectionBase.cs" />
-    <Compile Include="Mapping\RuntimeLayerBase.cs" />
-    <Compile Include="Mapping\RuntimeMapBase.cs" />
     <Compile Include="CrossConnection\ResourceMigrator.cs" />
+    <Compile Include="Mapping\MapObservable.cs" />
+    <Compile Include="Mapping\MapSelection.cs" />
+    <Compile Include="Mapping\RuntimeMap.cs" />
+    <Compile Include="Mapping\RuntimeMapGroup.cs" />
+    <Compile Include="Mapping\RuntimeMapLayer.cs" />
     <Compile Include="MgServerConnectionBase.cs" />
     <Compile Include="ObjectModels\ApplicationDefinition.cs" />
     <Compile Include="ObjectModels\DrawingSource.cs" />
     <Compile Include="ObjectModels\DrawingSourceInterfaces.cs" />
     <Compile Include="ObjectModels\FeatureSourceInterfaces.cs" />
+    <Compile Include="ObjectModels\Geometries.cs" />
     <Compile Include="ObjectModels\GridLayerDefinitionImpl.cs" />
     <Compile Include="ObjectModels\IDynamicInvokable.cs" />
     <Compile Include="ObjectModels\Envelope.cs" />
@@ -267,7 +270,7 @@
     <Compile Include="Resource\Validation\ValidationResultSet.cs" />
     <Compile Include="Resource\Validation\WebLayoutValidator.cs" />
     <Compile Include="Serialization\Enums.cs" />
-    <Compile Include="Serialization\IBinarySerializeable.cs" />
+    <Compile Include="Serialization\IBinarySerializable.cs" />
     <Compile Include="Serialization\MgBinaryDeserializer.cs" />
     <Compile Include="Serialization\MgBinarySerializer.cs" />
     <Compile Include="Services\IDrawingService.cs" />

Modified: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/Envelope.cs
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/Envelope.cs	2010-11-05 08:34:47 UTC (rev 5373)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/Envelope.cs	2010-11-05 10:17:38 UTC (rev 5374)
@@ -63,6 +63,20 @@
     public static class EnvelopeExtensions
     {
         /// <summary>
+        /// Gets the center of the specified envelope
+        /// </summary>
+        /// <param name="env"></param>
+        /// <returns></returns>
+        public static IPoint2D Center(this IEnvelope env)
+        {
+            Check.NotNull(env, "env");
+
+            return ObjectFactory.CreatePoint2D(
+                (env.MinX + env.MaxX) / 2,
+                (env.MinY + env.MaxY) / 2);
+        }
+
+        /// <summary>
         /// Clones this instance
         /// </summary>
         /// <param name="env">The envelope.</param>

Added: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/Geometries.cs
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/Geometries.cs	                        (rev 0)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/Geometries.cs	2010-11-05 10:17:38 UTC (rev 5374)
@@ -0,0 +1,47 @@
+#region Disclaimer / License
+// Copyright (C) 2010, Jackie Ng
+// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at gmail.com
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+// 
+#endregion
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace OSGeo.MapGuide.ObjectModels.Common
+{
+    public interface IPoint2D
+    {
+        double X { get; set; }
+        double Y { get; set; }
+    }
+
+    public interface IPoint3D : IPoint2D
+    {
+        double Z { get; set; }
+    }
+
+    internal class Point2DImpl : IPoint2D
+    {
+        public double X { get; set; }
+        public double Y { get; set; }
+    }
+
+    internal class Point3DImpl : Point2DImpl, IPoint3D
+    {
+        public double Z { get; set; }
+    }
+}

Modified: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/MapDefinition.cs
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/MapDefinition.cs	2010-11-05 08:34:47 UTC (rev 5373)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/MapDefinition.cs	2010-11-05 10:17:38 UTC (rev 5374)
@@ -88,7 +88,7 @@
         }
 
         [XmlIgnore]
-        public ResourceTypes ResourceType
+        public virtual ResourceTypes ResourceType
         {
             get
             {

Modified: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/MapDefinitionInterfaces.cs
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/MapDefinitionInterfaces.cs	2010-11-05 08:34:47 UTC (rev 5373)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/MapDefinitionInterfaces.cs	2010-11-05 10:17:38 UTC (rev 5374)
@@ -29,9 +29,34 @@
 namespace OSGeo.MapGuide.ObjectModels.MapDefinition
 {
     /// <summary>
+    /// Represents the base interface of map definitions and their runtime forms
+    /// </summary>
+    public interface IMapDefinitionBase
+    {
+        /// <summary>
+        /// Gets the name.
+        /// </summary>
+        /// <value>The name.</value>
+        string Name { get; }
+
+        /// <summary>
+        /// Gets the coordinate system. Layers whose coordinate system does
+        /// not match will be re-projecte to this coordinate system when rendering
+        /// </summary>
+        /// <value>The coordinate system.</value>
+        string CoordinateSystem { get; }
+
+        /// <summary>
+        /// Gets or sets the color of the background.
+        /// </summary>
+        /// <value>The color of the background.</value>
+        Color BackgroundColor { get; set; }
+    }
+
+    /// <summary>
     /// Represents a Map Definition
     /// </summary>
-    public interface IMapDefinition : IResource, INotifyPropertyChanged
+    public interface IMapDefinition : IResource, IMapDefinitionBase, INotifyPropertyChanged
     {
         /// <summary>
         /// Gets or sets the name.
@@ -62,12 +87,6 @@
         void SetExtents(double minx, double miny, double maxx, double maxy);
 
         /// <summary>
-        /// Gets or sets the color of the background.
-        /// </summary>
-        /// <value>The color of the background.</value>
-        Color BackgroundColor { get; set; }
-
-        /// <summary>
         /// Gets or sets the metadata.
         /// </summary>
         /// <value>The metadata.</value>
@@ -159,7 +178,7 @@
         /// <param name="groupName">Name of the group.</param>
         /// <returns></returns>
         IMapLayerGroup AddGroup(string groupName);
-         
+
         /// <summary>
         /// Removes the group
         /// </summary>

Modified: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/ObjectFactory.cs
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/ObjectFactory.cs	2010-11-05 08:34:47 UTC (rev 5373)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/ObjectFactory.cs	2010-11-05 10:17:38 UTC (rev 5374)
@@ -577,5 +577,15 @@
             rel.ForceOneToOne = false;
             return rel;
         }
+
+        public static IPoint2D CreatePoint2D(double x, double y)
+        {
+            return new Point2DImpl() { X = x, Y = y };
+        }
+
+        public static IPoint3D CreatePoint3D(double x, double y, double z)
+        {
+            return new Point3DImpl() { X = x, Y = y, Z = z };
+        }
     }
 }

Modified: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/WebLayout.cs
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/WebLayout.cs	2010-11-05 08:34:47 UTC (rev 5373)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/WebLayout.cs	2010-11-05 10:17:38 UTC (rev 5374)
@@ -820,11 +820,11 @@
         {
             get
             {
-                throw new NotImplementedException();
+                return this.Title;
             }
             set
             {
-                throw new NotImplementedException();
+                this.Title = value;
             }
         }
 

Modified: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/PlatformConnectionBase.cs
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/PlatformConnectionBase.cs	2010-11-05 08:34:47 UTC (rev 5373)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/PlatformConnectionBase.cs	2010-11-05 10:17:38 UTC (rev 5374)
@@ -28,6 +28,10 @@
 using OSGeo.MapGuide.ObjectModels.Capabilities;
 using OSGeo.MapGuide.MaestroAPI.Resource;
 using OSGeo.MapGuide.MaestroAPI.Commands;
+using OSGeo.MapGuide.MaestroAPI.Mapping;
+using OSGeo.MapGuide.ObjectModels.MapDefinition;
+using OSGeo.MapGuide.MaestroAPI.Serialization;
+using OSGeo.MapGuide.ObjectModels.Common;
 
 namespace OSGeo.MapGuide.MaestroAPI
 {
@@ -1611,5 +1615,42 @@
         }
 
         #endregion
+
+        #region runtime map
+        public virtual RuntimeMap CreateMap(string mapDefinitionResourceId)
+        {
+            ResourceIdentifier.Validate(mapDefinitionResourceId);
+            ResourceIdentifier ri = new ResourceIdentifier(mapDefinitionResourceId);
+            ri.Path = ri.Name;
+            ri.Extension = EnumHelper.ResourceName(ResourceTypes.RuntimeMap);
+            return CreateMap(ri, mapDefinitionResourceId);
+        }
+
+        public virtual RuntimeMap CreateMap(string runtimeMapResourceId, string baseMapDefinitionId)
+        {
+            var mdf = (IMapDefinition)GetResource(baseMapDefinitionId);
+            return CreateMap(runtimeMapResourceId, mdf);
+        }
+
+        public virtual RuntimeMap CreateMap(string runtimeMapResourceId, IMapDefinition mdf)
+        {
+            var map = new RuntimeMap(mdf);
+            map.ResourceID = runtimeMapResourceId;
+            return map;
+        }
+
+        public virtual RuntimeMap OpenMap(string runtimeMapResourceId)
+        {
+            if (!runtimeMapResourceId.StartsWith("Session:" + this.SessionID + "//") || !runtimeMapResourceId.EndsWith(".Map"))
+                throw new ArgumentException("Runtime maps must be in the current session repository");
+
+            var map = new RuntimeMap(GetInterface());
+            map.Deserialize(new MgBinaryDeserializer(this.GetResourceData(runtimeMapResourceId, "RuntimeData"), this.SiteVersion));
+            if (this.SiteVersion >= SiteVersions.GetVersion(KnownSiteVersions.MapGuideOS1_2))
+                map.DeserializeLayerData(new MgBinaryDeserializer(this.GetResourceData(runtimeMapResourceId, "LayerGroupData"), this.SiteVersion));
+
+            return map;
+        }
+        #endregion
     }
 }

Copied: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Serialization/IBinarySerializable.cs (from rev 5370, sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Serialization/IBinarySerializeable.cs)
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Serialization/IBinarySerializable.cs	                        (rev 0)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Serialization/IBinarySerializable.cs	2010-11-05 10:17:38 UTC (rev 5374)
@@ -0,0 +1,40 @@
+#region Disclaimer / License
+// Copyright (C) 2009, Kenneth Skovhede
+// http://www.hexad.dk, opensource at hexad.dk
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+// 
+#endregion
+using System;
+
+namespace OSGeo.MapGuide.MaestroAPI.Serialization
+{
+	/// <summary>
+	/// An object that can be serialized, using the internal MapGuide format, must implement this interface
+	/// </summary>
+	public interface IBinarySerializable
+	{
+        /// <summary>
+        /// Serializes using the specified serializer.
+        /// </summary>
+        /// <param name="serializer">The serializer.</param>
+		void Serialize(MgBinarySerializer serializer);
+        /// <summary>
+        /// Deserializes using the specified deserializer.
+        /// </summary>
+        /// <param name="deserializer">The deserializer.</param>
+		void Deserialize(MgBinaryDeserializer deserializer);
+	}
+}

Deleted: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Serialization/IBinarySerializeable.cs
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Serialization/IBinarySerializeable.cs	2010-11-05 08:34:47 UTC (rev 5373)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Serialization/IBinarySerializeable.cs	2010-11-05 10:17:38 UTC (rev 5374)
@@ -1,40 +0,0 @@
-#region Disclaimer / License
-// Copyright (C) 2009, Kenneth Skovhede
-// http://www.hexad.dk, opensource at hexad.dk
-// 
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License, or (at your option) any later version.
-// 
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// Lesser General Public License for more details.
-// 
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-// 
-#endregion
-using System;
-
-namespace OSGeo.MapGuide.MaestroAPI.Serialization
-{
-	/// <summary>
-	/// An object that can be serialized, using the internal MapGuide format, must implement this interface
-	/// </summary>
-	public interface IBinarySerializeable
-	{
-        /// <summary>
-        /// Serializes using the specified serializer.
-        /// </summary>
-        /// <param name="serializer">The serializer.</param>
-		void Serialize(MgBinarySerializer serializer);
-        /// <summary>
-        /// Deserializes using the specified deserializer.
-        /// </summary>
-        /// <param name="deserializer">The deserializer.</param>
-		void Deserialize(MgBinaryDeserializer deserializer);
-	}
-}

Modified: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Serialization/MgBinaryDeserializer.cs
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Serialization/MgBinaryDeserializer.cs	2010-11-05 08:34:47 UTC (rev 5373)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Serialization/MgBinaryDeserializer.cs	2010-11-05 10:17:38 UTC (rev 5374)
@@ -58,16 +58,6 @@
 			return h;
 		}
 
-		/*private MgOperationHeader ReadOperationHeader()
-		{
-			throw new NotImplementedException();
-		}
-
-		private MgOperationResponseHeader ReadOperationResponseHeader()
-		{
-			throw new NotImplementedException();
-		}*/
-
 		private MgArgumentPacket ReadArgumentPacket()
 		{
 			MgArgumentPacket p = new MgArgumentPacket();
@@ -344,13 +334,13 @@
         /// Reads the object.
         /// </summary>
         /// <returns></returns>
-		public IBinarySerializeable ReadObject()
+		public IBinarySerializable ReadObject()
 		{
 			int classId = ReadClassId();
 			if (classId == 0)
 				return null;
 
-			IBinarySerializeable obj = null;
+			IBinarySerializable obj = null;
 			switch(classId)
 			{
 				case 0:

Modified: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Serialization/MgBinarySerializer.cs
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Serialization/MgBinarySerializer.cs	2010-11-05 08:34:47 UTC (rev 5373)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Serialization/MgBinarySerializer.cs	2010-11-05 10:17:38 UTC (rev 5374)
@@ -242,7 +242,7 @@
         /// Writes the specified value.
         /// </summary>
         /// <param name="value">The value.</param>
-		public void Write(IBinarySerializeable value)
+		public void Write(IBinarySerializable value)
 		{
 			if (value == null)
 				WriteClassId(0);

Modified: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Services/IMappingService.cs
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Services/IMappingService.cs	2010-11-05 08:34:47 UTC (rev 5373)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/Services/IMappingService.cs	2010-11-05 10:17:38 UTC (rev 5374)
@@ -31,6 +31,125 @@
     public interface IMappingService : IService
     {
         /// <summary>
+        /// Creates a new runtime map instance from an existing map definition, the resource
+        /// id of the runtime map is derived from the specified resource id
+        /// </summary>
+        /// <param name="mapDefinitionResourceId"></param>
+        /// <returns></returns>
+        RuntimeMap CreateMap(string mapDefinitionResourceId);
+
+        /// <summary>
+        /// Creates a new runtime map instance from an existing map definition
+        /// </summary>
+        /// <param name="runtimeMapResourceId"></param>
+        /// <param name="baseMapDefinitionId"></param>
+        /// <returns></returns>
+        RuntimeMap CreateMap(string runtimeMapResourceId, string baseMapDefinitionId);
+
+        /// <summary>
+        /// Creates a new runtime map instance from an existing map definition
+        /// </summary>
+        /// <param name="runtimeMapResourceId"></param>
+        /// <param name="mdf"></param>
+        /// <returns></returns>
+        RuntimeMap CreateMap(string runtimeMapResourceId, IMapDefinition mdf);
+
+        /// <summary>
+        /// Opens an existing runtime map instance
+        /// </summary>
+        /// <param name="runtimeMapResourceId"></param>
+        /// <returns></returns>
+        RuntimeMap OpenMap(string runtimeMapResourceId);
+
+        System.IO.Stream RenderDynamicOverlay(RuntimeMap map, MapSelection selection, string format);
+
+        System.IO.Stream RenderDynamicOverlay(RuntimeMap map, MapSelection selection, string format, bool keepSelection);
+
+        /// <summary>
+        /// Renders the runtime map.
+        /// </summary>
+        /// <param name="resourceId">The resource id.</param>
+        /// <param name="x">The x.</param>
+        /// <param name="y">The y.</param>
+        /// <param name="scale">The scale.</param>
+        /// <param name="width">The width.</param>
+        /// <param name="height">The height.</param>
+        /// <param name="dpi">The dpi.</param>
+        /// <returns></returns>
+        System.IO.Stream RenderRuntimeMap(string resourceId, double x, double y, double scale, int width, int height, int dpi);
+        /// <summary>
+        /// Renders the runtime map.
+        /// </summary>
+        /// <param name="resourceId">The resource id.</param>
+        /// <param name="x1">The x1.</param>
+        /// <param name="y1">The y1.</param>
+        /// <param name="x2">The x2.</param>
+        /// <param name="y2">The y2.</param>
+        /// <param name="width">The width.</param>
+        /// <param name="height">The height.</param>
+        /// <param name="dpi">The dpi.</param>
+        /// <returns></returns>
+        System.IO.Stream RenderRuntimeMap(string resourceId, double x1, double y1, double x2, double y2, int width, int height, int dpi);
+
+        /// <summary>
+        /// Renders the runtime map.
+        /// </summary>
+        /// <param name="resourceId">The resource id.</param>
+        /// <param name="x">The x.</param>
+        /// <param name="y">The y.</param>
+        /// <param name="scale">The scale.</param>
+        /// <param name="width">The width.</param>
+        /// <param name="height">The height.</param>
+        /// <param name="dpi">The dpi.</param>
+        /// <param name="format">The format.</param>
+        /// <returns></returns>
+        System.IO.Stream RenderRuntimeMap(string resourceId, double x, double y, double scale, int width, int height, int dpi, string format);
+        /// <summary>
+        /// Renders the runtime map.
+        /// </summary>
+        /// <param name="resourceId">The resource id.</param>
+        /// <param name="x1">The x1.</param>
+        /// <param name="y1">The y1.</param>
+        /// <param name="x2">The x2.</param>
+        /// <param name="y2">The y2.</param>
+        /// <param name="width">The width.</param>
+        /// <param name="height">The height.</param>
+        /// <param name="dpi">The dpi.</param>
+        /// <param name="format">The format.</param>
+        /// <returns></returns>
+        System.IO.Stream RenderRuntimeMap(string resourceId, double x1, double y1, double x2, double y2, int width, int height, int dpi, string format);
+
+        /// <summary>
+        /// Renders the runtime map.
+        /// </summary>
+        /// <param name="resourceId">The resource id.</param>
+        /// <param name="x">The x.</param>
+        /// <param name="y">The y.</param>
+        /// <param name="scale">The scale.</param>
+        /// <param name="width">The width.</param>
+        /// <param name="height">The height.</param>
+        /// <param name="dpi">The dpi.</param>
+        /// <param name="format">The format.</param>
+        /// <param name="clip">if set to <c>true</c> [clip].</param>
+        /// <returns></returns>
+        System.IO.Stream RenderRuntimeMap(string resourceId, double x, double y, double scale, int width, int height, int dpi, string format, bool clip);
+        /// <summary>
+        /// Renders the runtime map.
+        /// </summary>
+        /// <param name="resourceId">The resource id.</param>
+        /// <param name="x1">The x1.</param>
+        /// <param name="y1">The y1.</param>
+        /// <param name="x2">The x2.</param>
+        /// <param name="y2">The y2.</param>
+        /// <param name="width">The width.</param>
+        /// <param name="height">The height.</param>
+        /// <param name="dpi">The dpi.</param>
+        /// <param name="format">The format.</param>
+        /// <param name="clip">if set to <c>true</c> [clip].</param>
+        /// <returns></returns>
+        System.IO.Stream RenderRuntimeMap(string resourceId, double x1, double y1, double x2, double y2, int width, int height, int dpi, string format, bool clip);
+        /*
+        /// <summary>
         /// Creates a runtime map on the server. 
         /// The map name will be the name of the resource, without path information.
         /// This is equivalent to the way the AJAX viewer creates the runtime map.
@@ -201,6 +320,6 @@
         /// <param name="type">The geometry type, 1 for point, 2 for line, 3 for area, 4 for composite</param>
         /// <returns>The minature bitmap</returns>
         System.Drawing.Image GetLegendImage(double scale, string layerdefinition, int themeIndex, int type);
-
+        */
     }
 }

Modified: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI.Http/HttpServerConnection.cs
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI.Http/HttpServerConnection.cs	2010-11-05 08:34:47 UTC (rev 5373)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI.Http/HttpServerConnection.cs	2010-11-05 10:17:38 UTC (rev 5374)
@@ -645,104 +645,8 @@
             }
 		}
 
-		/// <summary>
-		/// Creates a runtime map on the server
-		/// </summary>
-		/// <param name="resourceID">The target resource id for the runtime map</param>
-		/// <param name="mapdefinition">The mapdefinition to base the map on</param>
-		public override void CreateRuntimeMap(string resourceID, string mapdefinition)
+        public void DeleteResourceData(string resourceID, string dataname)
 		{
-			ResourceIdentifier.Validate(resourceID, ResourceTypes.RuntimeMap);
-            IMapDefinition map = (IMapDefinition)this.GetResource(mapdefinition);
-			CreateRuntimeMap(resourceID, map);
-		}
-
-		/// <summary>
-		/// Creates a runtime map on the server
-		/// </summary>
-		/// <param name="resourceID">The target resource id for the runtime map</param>
-		/// <param name="map">The mapdefinition to base the map on</param>
-		public void CreateRuntimeMap(string resourceID, IMapDefinition map)
-		{
-            ResourceIdentifier.Validate(resourceID, ResourceTypes.RuntimeMap);
-            RuntimeMapBase m = new RuntimeMapBase(map);
-			CreateRuntimeMap(resourceID, m);
-		}
-
-		/// <summary>
-		/// Creates a runtime map on the server
-		/// </summary>
-		/// <param name="resourceID">The target resource id for the runtime map</param>
-		/// <param name="map">The mapdefinition to base the map on</param>
-		public void CreateRuntimeMap(string resourceID, RuntimeMapBase map)
-		{
-            ResourceIdentifier.Validate(resourceID, ResourceTypes.RuntimeMap);
-			string selectionID = resourceID.Substring(0, resourceID.LastIndexOf(".")) + ".Selection";
-			SetResourceXmlData(resourceID, new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(RuntimeMapBase.RUNTIMEMAP_XML)));
-            SetResourceXmlData(selectionID, new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(RuntimeMapBase.RUNTIMEMAP_SELECTION_XML)));
-
-			System.IO.MemoryStream ms = new System.IO.MemoryStream();
-			MgBinarySerializer serializer = new MgBinarySerializer(ms, this.SiteVersion);
-            MapSelectionBase sel = new MapSelectionBase();
-			sel.Serialize(serializer);
-			ms.Position = 0;
-			SetResourceData(selectionID, "RuntimeData", ResourceDataType.Stream, ms);
-
-			SaveRuntimeMap(resourceID, map);
-		}
-		/// <summary>
-		/// Updates an existing runtime map
-		/// </summary>
-		/// <param name="resourceID">The target resource id for the runtime map</param>
-		/// <param name="map">The runtime map to update with</param>
-		public void SaveRuntimeMap(string resourceID, RuntimeMapBase map)
-		{
-            ResourceIdentifier.Validate(resourceID, ResourceTypes.RuntimeMap);
-			if (!resourceID.StartsWith("Session:" + this.m_reqBuilder.SessionID + "//") || !resourceID.EndsWith(".Map"))
-				throw new Exception("Runtime maps must be in the current session repository");
-
-			if (map == null)
-				throw new ArgumentNullException("map");
-
-			System.IO.MemoryStream ms = new System.IO.MemoryStream();
-			System.IO.MemoryStream ms2 = null;
-
-			//Apparently the name is used to reconstruct the resourceId rather than pass it around
-			//inside the map server
-			string r = map.Name;
-			string t = map.ResourceID;
-
-			string mapname = resourceID.Substring(resourceID.IndexOf("//") + 2);
-			mapname = mapname.Substring(0, mapname.LastIndexOf("."));
-			map.Name = mapname;
-			map.ResourceID = resourceID;
-			
-
-			try
-			{
-				map.Serialize(new MgBinarySerializer(ms, this.SiteVersion));
-				if (this.SiteVersion >= SiteVersions.GetVersion(KnownSiteVersions.MapGuideOS1_2))
-				{
-					ms2 = new System.IO.MemoryStream();
-					map.SerializeLayerData(new MgBinarySerializer(ms2, this.SiteVersion));
-				}
-
-				SetResourceData(resourceID, "RuntimeData", ResourceDataType.Stream, ms);
-				if (ms2 != null)
-					SetResourceData(resourceID, "LayerGroupData", ResourceDataType.Stream, ms2);
-
-                if (map.HasLoadedSelectionXml)
-                    SetSelectionXml(resourceID, map.Selection.ToXml());
-            }
-			finally
-			{
-				map.Name = r;
-				map.ResourceID = t;
-			}
-		}
-
-		public void DeleteResourceData(string resourceID, string dataname)
-		{
 			string req = m_reqBuilder.DeleteResourceData(resourceID, dataname);
 
 			using (System.IO.Stream resp = this.OpenRead(req))
@@ -767,18 +671,7 @@
 				//Do nothing... there is no return value
 		}
 
-		public RuntimeMapBase GetRuntimeMap(string resourceID)
-		{
-			if (!resourceID.StartsWith("Session:" + this.m_reqBuilder.SessionID + "//") || !resourceID.EndsWith(".Map"))
-				throw new Exception("Runtime maps must be in the current session repository");
-
-            RuntimeMapBase m = RuntimeMapBase.Deserialize(new MgBinaryDeserializer(this.GetResourceData(resourceID, "RuntimeData"), this.SiteVersion));
-			if (this.SiteVersion >= SiteVersions.GetVersion(KnownSiteVersions.MapGuideOS1_2))
-				m.DeserializeLayerData(new MgBinaryDeserializer(this.GetResourceData(resourceID, "LayerGroupData"), this.SiteVersion));
 		
-			m.CurrentConnection = this;
-			return m;
-		}
 
         public override Version SiteVersion
         {
@@ -823,24 +716,6 @@
 			return this.OpenRead(m_reqBuilder.BuildRequest(param));
 		}
 
-//		public void CreateFolder(string folderpath)
-//		{
-//			folderpath = FixAndValidateFolderPath(folderpath);
-//			System.IO.MemoryStream outStream = new System.IO.MemoryStream();
-//			System.Net.WebRequest req = m_reqBuilder.SetResource(folderpath, outStream, null, null);
-//			req.Credentials = m_wc.Credentials;
-//			outStream.Position = 0;
-//			using(System.IO.Stream rs = req.GetRequestStream())
-//			{
-//				Utility.CopyStream(outStream, rs);
-//				rs.Flush();
-//			}
-//			using (System.IO.Stream resp = req.GetResponse().GetResponseStream())
-//			{
-//				//Do nothing... there is no return value
-//			}
-//		}
-
 		/// <summary>
 		/// Returns the Uri for the mapagent
 		/// </summary>
@@ -919,8 +794,27 @@
 			//Do nothing... there is no return value
 		}
 
+        public override System.IO.Stream RenderDynamicOverlay(RuntimeMap map, MapSelection selection, string format)
+        {
+            return RenderDynamicOverlay(map, selection, format, false);
+        }
 
+        public override System.IO.Stream RenderDynamicOverlay(RuntimeMap map, MapSelection selection, string format, bool keepSelection)
+        {
+            System.IO.MemoryStream ms = new System.IO.MemoryStream();
+            System.Net.WebRequest req = m_reqBuilder.GetDynamicMapOverlayImage(map.Name, (selection == null ? string.Empty : selection.ToXml()), format, ms);
 
+            //Maksim reported that the rendering times out frequently, so now we wait 5 minutes
+            req.Timeout = 5 * 60 * 1000;
+
+            using (System.IO.Stream rs = req.GetRequestStream())
+            {
+                Utility.CopyStream(ms, rs);
+                rs.Flush();
+                return req.GetResponse().GetResponseStream();
+            }
+        }
+
 		public override System.IO.Stream RenderRuntimeMap(string resourceId, double x, double y, double scale, int width, int height, int dpi, string format, bool clip)
 		{
             ResourceIdentifier.Validate(resourceId, ResourceTypes.RuntimeMap);
@@ -971,70 +865,6 @@
 #endif
         }
 
-/*		/// <summary>
-		/// Selects features from a runtime map, returning a selection Xml.
-		/// </summary>
-		/// <param name="runtimemap">The map to query. NOT a resourceID, only the map name!</param>
-		/// <param name="wkt">The WKT of the geometry to query with (always uses intersection)</param>
-		/// <param name="persist">True if the selection should be saved in the runtime map, false otherwise.</param>
-		/// <returns>The selection Xml, or an empty string if there were no data.</returns>
-		public string QueryMapFeatures(string runtimemap, string wkt, bool persist)
-		{
-			return QueryMapFeatures(runtimemap, wkt, persist, QueryMapFeaturesLayerAttributes.Default, false);
-		}*/
-
-		/// <summary>
-		/// Selects features from a runtime map, returning a selection Xml.
-		/// </summary>
-		/// <param name="runtimemap">The map to query. NOT a resourceID, only the map name!</param>
-		/// <param name="wkt">The WKT of the geometry to query with (always uses intersection)</param>
-		/// <param name="persist">True if the selection should be saved in the runtime map, false otherwise.</param>
-		/// <param name="attributes">The type of layer to include in the query</param>
-		/// <param name="raw">True if the result should contain the tooltip and link info</param>
-		/// <returns>The selection Xml, or an empty string if there were no data.</returns>
-		public override string QueryMapFeatures(string runtimemap, string wkt, bool persist, QueryMapFeaturesLayerAttributes attributes, bool raw)
-		{
-			//The request may execeed the url limit of the server, when large geometries
-			System.IO.MemoryStream ms = new System.IO.MemoryStream();
-			System.Net.WebRequest req = m_reqBuilder.QueryMapFeatures(runtimemap, persist, wkt, ms, attributes);
-			req.Timeout = 200 * 1000;
-			ms.Position = 0;
-
-			using(System.IO.Stream rs = req.GetRequestStream())
-			{
-				Utility.CopyStream(ms, rs);
-				rs.Flush();
-			}
-
-			System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
-#if DEBUG
-			System.IO.MemoryStream xms = new System.IO.MemoryStream();
-			Utility.CopyStream(req.GetResponse().GetResponseStream(), xms);
-			xms.Position = 0;
-			string f = System.Text.Encoding.UTF8.GetString(xms.ToArray());
-			if (raw)
-				return f;
-			xms.Position = 0;
-			doc.Load(xms);
-
-#else
-			
-			if (raw)
-			{
-				System.IO.MemoryStream xms = new System.IO.MemoryStream();
-				Utility.CopyStream(req.GetResponse().GetResponseStream(), xms);
-				return System.Text.Encoding.UTF8.GetString(xms.ToArray());
-			}
-
-			doc.Load(req.GetResponse().GetResponseStream());
-#endif
-			if (doc.SelectSingleNode("FeatureInformation/FeatureSet") != null && doc["FeatureInformation"]["FeatureSet"].ChildNodes.Count > 0)
-				return "<FeatureSet>" + doc["FeatureInformation"]["FeatureSet"].InnerXml + "</FeatureSet>";
-			else 
-				return "";
-		}
-
-
 		public override bool IsSessionExpiredException(Exception ex)
 		{
 			if (ex != null && ex.GetType() == typeof(System.Net.WebException))
@@ -1302,42 +1132,6 @@
 		}
 
 		/// <summary>
-		/// Sets the selection of a map
-		/// </summary>
-		/// <param name="runtimeMap">The resourceID of the runtime map</param>
-		/// <param name="selectionXml">The selection xml</param>
-		public override void SetSelectionXml(string runtimeMap, string selectionXml)
-		{
-            ResourceIdentifier.Validate(runtimeMap, ResourceTypes.RuntimeMap);
-			string selectionID = runtimeMap.Substring(0, runtimeMap.LastIndexOf(".")) + ".Selection";
-			//Assumes the runtime map is created, and has the selection resource
-			//SetResourceXmlData(selectionID, new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(RUNTIMEMAP_SELECTION_XML)));
-
-			System.IO.MemoryStream ms = new System.IO.MemoryStream();
-			MgBinarySerializer serializer = new MgBinarySerializer(ms, this.SiteVersion);
-            MapSelectionBase sel = new MapSelectionBase(selectionXml);
-			sel.Serialize(serializer);
-			ms.Position = 0;
-			SetResourceData(selectionID, "RuntimeData", ResourceDataType.Stream, ms);
-		}
-
-		/// <summary>
-		/// Gets the selection from a map
-		/// </summary>
-		/// <param name="runtimeMap">The resourceID of the runtime map</param>
-		/// <returns>The selection xml</returns>
-		public override string GetSelectionXml(string runtimeMap)
-		{
-            ResourceIdentifier.Validate(runtimeMap, ResourceTypes.RuntimeMap);
-			string selectionID = runtimeMap.Substring(0, runtimeMap.LastIndexOf(".")) + ".Selection";
-			System.IO.MemoryStream ms = GetResourceData(selectionID, "RuntimeData");
-			MgBinaryDeserializer deserializer = new MgBinaryDeserializer(ms, this.SiteVersion);
-            MapSelectionBase sel = new MapSelectionBase();
-			sel.Deserialize(deserializer);
-			return sel.SelectionXml;
-		}
-
-		/// <summary>
 		/// Enumerates all unmanaged folders, meaning alias'ed folders
 		/// </summary>
 		/// <param name="type">The type of data to return</param>

Modified: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI.Http/RequestBuilder.cs
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI.Http/RequestBuilder.cs	2010-11-05 08:34:47 UTC (rev 5373)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI.Http/RequestBuilder.cs	2010-11-05 10:17:38 UTC (rev 5374)
@@ -1500,5 +1500,28 @@
 
             return m_hosturi + "?" + EncodeParameters(param);
         }
+
+        internal System.Net.WebRequest GetDynamicMapOverlayImage(string mapname, string selectionXml, string format, System.IO.Stream outStream)
+        {
+            NameValueCollection param = new NameValueCollection();
+            param.Add("OPERATION", "GETDYNAMICMAPOVERLAYIMAGE");
+            param.Add("VERSION", "1.0.0");
+            param.Add("SESSION", m_sessionID);
+            param.Add("MAPNAME", mapname);
+            param.Add("CLIENTAGENT", m_userAgent);
+
+            if (format != null && format.Length != 0)
+                param.Add("FORMAT", format);
+
+            if (selectionXml != null && selectionXml.Length != 0)
+                param.Add("SELECTION", selectionXml);
+
+            string boundary;
+            System.Net.WebRequest req = PrepareFormContent(outStream, out boundary);
+            EncodeFormParameters(boundary, param, outStream);
+            req.ContentLength = outStream.Length;
+
+            return req;
+        }
     }
 }

Modified: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI.Native/LocalNativeConnection.cs
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI.Native/LocalNativeConnection.cs	2010-11-05 08:34:47 UTC (rev 5373)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI.Native/LocalNativeConnection.cs	2010-11-05 10:17:38 UTC (rev 5374)
@@ -40,7 +40,7 @@
                                          IFeatureService,
                                          IResourceService,
                                          ITileService,
-                                         //IMappingService,
+                                         IMappingService,
                                          IDrawingService,
                                          ISiteService
     {
@@ -294,7 +294,7 @@
 			System.IO.MemoryStream ms = new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(fes.DescribeSchemaAsXml(new MgResourceIdentifier(resourceID), schema)));
 			return new FeatureSourceDescription(ms);
 		}
-
+        /*
 		public override void CreateRuntimeMap(string resourceID, string mapdefinition)
 		{
             string mapname = new ResourceIdentifier(resourceID).Path;
@@ -361,6 +361,17 @@
 			}
 		}
 
+        public RuntimeMapBase GetRuntimeMap(string resourceID)
+        {
+            RuntimeMapBase m = RuntimeMapBase.Deserialize(new MgBinaryDeserializer(this.GetResourceData(resourceID, "RuntimeData"), this.SiteVersion));
+            if (this.SiteVersion >= SiteVersions.GetVersion(KnownSiteVersions.MapGuideOS1_2))
+                m.DeserializeLayerData(new MgBinaryDeserializer(this.GetResourceData(resourceID, "LayerGroupData"), this.SiteVersion));
+
+            m.CurrentConnection = this;
+            return m;
+        }
+         */
+
 		public void DeleteResourceData(string resourceID, string dataname)
 		{
 			MgResourceService res = this.Connection.CreateService(MgServiceType.ResourceService) as MgResourceService;
@@ -380,16 +391,6 @@
 			res.DeleteResource(new MgResourceIdentifier(resourceID));
 		}
 
-		public RuntimeMapBase GetRuntimeMap(string resourceID)
-		{
-			RuntimeMapBase m = RuntimeMapBase.Deserialize(new MgBinaryDeserializer(this.GetResourceData(resourceID, "RuntimeData"), this.SiteVersion));
-			if (this.SiteVersion >= SiteVersions.GetVersion(KnownSiteVersions.MapGuideOS1_2))
-				m.DeserializeLayerData(new MgBinaryDeserializer(this.GetResourceData(resourceID, "LayerGroupData"), this.SiteVersion));
-		
-			m.CurrentConnection = this;
-			return m;
-		}
-
 		public override Version SiteVersion
 		{
 			get
@@ -630,37 +631,6 @@
 		}
 
 		/// <summary>
-		/// Sets the selection of a map
-		/// </summary>
-		/// <param name="runtimeMap">The resourceID of the runtime map</param>
-		/// <param name="selectionXml">The selection xml</param>
-		public override void SetSelectionXml(string runtimeMap, string selectionXml)
-		{
-			ResourceIdentifier.Validate(runtimeMap, ResourceTypes.RuntimeMap);
-			MgResourceService res = this.Connection.CreateService(MgServiceType.ResourceService) as MgResourceService;
-			MgMap map = new MgMap();
-            string mapname = new ResourceIdentifier(runtimeMap).Path;
-			map.Open(res, mapname);
-			MgSelection sel = string.IsNullOrEmpty(selectionXml) ? new MgSelection(map) : new MgSelection(map, selectionXml);
-			sel.Save(res, mapname);
-		}
-
-		/// <summary>
-		/// Gets the selection from a map
-		/// </summary>
-		/// <param name="runtimeMap">The resourceID of the runtime map</param>
-		/// <returns>The selection xml</returns>
-		public override string GetSelectionXml(string runtimeMap)
-		{
-			MgResourceService res = this.Connection.CreateService(MgServiceType.ResourceService) as MgResourceService;
-			MgMap map = new MgMap();
-            string mapname = new ResourceIdentifier(runtimeMap).Path;
-			map.Open(res, mapname);
-			MgSelection sel = new MgSelection(map);
-			return sel.ToXml();
-		}
-
-		/// <summary>
 		/// Enumerates all unmanaged folders, meaning alias'ed folders
 		/// </summary>
 		/// <param name="type">The type of data to return</param>
@@ -673,28 +643,6 @@
 			throw new MissingMethodException();
 		}
 
-        public override string QueryMapFeatures(string runtimemap, string wkt, bool persist, QueryMapFeaturesLayerAttributes attributes, bool raw)
-        {
-            MgRenderingService rs = this.Connection.CreateService(MgServiceType.RenderingService) as MgRenderingService;
-			MgResourceService res = this.Connection.CreateService(MgServiceType.ResourceService) as MgResourceService;
-			MgMap map = new MgMap();
-			string mapname = runtimemap.IndexOf(":") > 0 ? new ResourceIdentifier(runtimemap).Path : runtimemap;
-			map.Open(res, mapname);
-
-            MgWktReaderWriter r = new MgWktReaderWriter();
-            MgFeatureInformation info = rs.QueryFeatures(map, null, r.Read(wkt), (int)MgFeatureSpatialOperations.Intersects, "", -1, (int)attributes);
-
-            string xml = System.Text.Encoding.UTF8.GetString(Utility.MgStreamToNetStream(info, info.GetType().GetMethod("ToXml"), null).ToArray()).Trim();
-
-            if (persist)
-            {
-                MgSelection sel = new MgSelection(map, xml);
-                sel.Save(res, mapname);
-            }
- 
-            return xml;
-        }
-
         public override void UpdateRepository(string resourceId, ResourceFolderHeaderType header)
         {
             MgResourceService res = this.Connection.CreateService(MgServiceType.ResourceService) as MgResourceService;
@@ -1095,5 +1043,15 @@
             var dwSvc = (MgDrawingService)this.Connection.CreateService(MgServiceType.DrawingService);
             return Utility.MgStreamToNetStream(dwSvc, dwSvc.GetType().GetMethod("GetSectionResource"), new object[] { new MgResourceIdentifier(resourceID), resourceName });
         }
+
+        public override Stream RenderDynamicOverlay(RuntimeMap map, MapSelection selection, string format)
+        {
+            throw new NotImplementedException();
+        }
+
+        public override Stream RenderDynamicOverlay(RuntimeMap map, MapSelection selection, string format, bool keepSelection)
+        {
+            throw new NotImplementedException();
+        }
     }
 }



More information about the mapguide-commits mailing list