Create a custom raster type from the ground up for DMCII data
DMCIIRasterType\DMCIIRasterType.cs
// Copyright 2012 ESRI
// 
// All rights reserved under the copyright laws of the United States
// and applicable international laws, treaties, and conventions.
// 
// You may freely redistribute and use this sample code, with or
// without modification, provided you include the original copyright
// notice and use restrictions.
// 
// See the use restrictions.
// 

using System;
using System.IO;
using System.Xml;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using ESRI.ArcGIS.ADF;
using ESRI.ArcGIS.DataSourcesRaster;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Carto;

/*
 * 
 * This sample shows how to implement a Custom Raster Type to provide support for DMCII data. 
 * Also provided is an optional test application to create a Geodatabase and a mosaic dataset 
 * and add data using the custom type.
 * The main interface to be implemented is the IRasterBuilder interface along with 
 * secondary interfaces such as IRasterBuilderInit (which provides access to the parent MD),
 * IPersistvariant (which implements persistence), IRasterBuilderInit2 and IRasterBuilder2 
 * (new interfaces added at 10.1).
 * A IRasterFactory implementation also needs to be created in order for the Raster type to 
 * show up in the list of Raster Types in the Add Rasters GP Tool. The factory is responsible 
 * for creating the raster type object and setting some properties on it. It also enables the 
 * use of the Raster Product.
 * 
 */


namespace SampleRasterType
{
    [Guid("5DEF8E3C-51E9-49af-A3BE-EF8C68A4BBBE")]
    [ClassInterface(ClassInterfaceType.None)]
    [ProgId("SampleRasterType.CustomRasterTypeFactory")]
    [ComVisible(true)]
    public class DMCIIRasterTypeFactory : IRasterTypeFactory
    {
        #region Private Members
        IStringArray myRasterTypeNames; // List of Raster Types that the factory can create.
        UID myUID; // UID for the DMCII Raster Type.
        #endregion

        #region IRasterTypeFactory Members

        public DMCIIRasterTypeFactory()
        {
            string rasterTypeName = "DMCII Raster Type";
            myRasterTypeNames = new StrArrayClass();
            myRasterTypeNames.Add(rasterTypeName);

            myUID = new UIDClass();
            myUID.Value = "{5DEF8E3C-51E9-49af-A3BE-EF8C68A4BBBE}";
        }

        public UID CLSID
        {
            get { return myUID; }
        }

        /// <summary>
        /// Create a Raster Type object given the name of the raster type (usually 
        /// the same name as the one in the UI list of raster types).
        /// </summary>
        /// <param name="RasterTypeName">Name of the Raster Type object to create.</param>
        /// <returns>The Raster type object.</returns>
        public IRasterType CreateRasterType(string RasterTypeName)
        {
            // Create a new RasterType object and its corresponding name object.
            IRasterType theRasterType = new RasterTypeClass();
            IRasterTypeName theRasterTypeName = new RasterTypeNameClass();
            theRasterTypeName.Name = RasterTypeName;
            theRasterType.FullName = (IName)theRasterTypeName;

            // Set the properties for the raster type object. These are shown in the 
            // 'General' tab of the raster type properties page.
            ((IRasterTypeProperties)theRasterType).Name = "DMCII Raster Type";
            ((IRasterTypeProperties)theRasterType).Description = "Raster Type for DMCII data.";
            ((IRasterTypeProperties)theRasterType).DataSourceFilter = "*.dim";
            ((IRasterTypeProperties)theRasterType).SupportsOrthorectification = true;

            // Create the Custom Raster Builder object
            IRasterBuilder customRasterBuilder = new DMCIIRasterBuilder();
            // Set the Raster Builder of theRasterType to the above created builder.
            theRasterType.RasterBuilder = customRasterBuilder;

            // Enable the use of the Raster Type as a Raster Product.
            ((IRasterTypeProperties2)theRasterType).IsSensorRasterType = true;

            #region Set Product Templates
            // Create a new array of templates if needed.
            if (theRasterType.ItemTemplates == null)
                theRasterType.ItemTemplates = new ItemTemplateArrayClass();

            // Add a 'Raw' template.
            IItemTemplate nullTemplate = new ItemTemplateClass();
            nullTemplate.Enabled = false;
            nullTemplate.Name = "Raw";
            ((IItemTemplate2)nullTemplate).IsSensorTemplate = true;
            ((IItemTemplate2)nullTemplate).SupportsEnhancement = false;
            theRasterType.ItemTemplates.Add(nullTemplate);

            // Add a 'Stretch' template. This is the default template.
            IItemTemplate strTemplate = new ItemTemplateClass();
            strTemplate.Enabled = true;
            strTemplate.Name = "Stretch";
            IRasterFunction stretchFunction = new StretchFunctionClass();
            IStretchFunctionArguments stretchFunctionArgs = new StretchFunctionArgumentsClass();
            stretchFunctionArgs.StretchType = esriRasterStretchType.esriRasterStretchMinimumMaximum;
            IRasterFunctionVariable rasterVar = new RasterFunctionVariableClass();
            rasterVar.IsDataset = true;
            rasterVar.Name = "MS";
            rasterVar.Aliases = new StrArrayClass();
            rasterVar.Aliases.Add("MS");
            rasterVar.Description = "Variable for input raster";
            stretchFunctionArgs.Raster = rasterVar;
            IRasterFunctionTemplate stretchFunctionTemplate = new RasterFunctionTemplateClass();
            stretchFunctionTemplate.Function = stretchFunction;
            stretchFunctionTemplate.Arguments = stretchFunctionArgs;
            strTemplate.RasterFunctionTemplate = stretchFunctionTemplate;
            ((IItemTemplate2)strTemplate).IsSensorTemplate = true;
            ((IItemTemplate2)strTemplate).SupportsEnhancement = true;
            theRasterType.ItemTemplates.Add(strTemplate);
            #endregion

            #region Set Product Types
            // Add Product types (called URI filters in the code).
            if (((IRasterTypeProperties)theRasterType).SupportedURIFilters == null)
                ((IRasterTypeProperties)theRasterType).SupportedURIFilters = new ArrayClass();
            // Create and setup URI Filters
            IItemURIFilter allFilter = new URIProductNameFilterClass();
            allFilter.Name = "All";
            allFilter.SupportsOrthorectification = true;
            allFilter.SupportedTemplateNames = new StrArrayClass();
            allFilter.SupportedTemplateNames.Add("Raw");
            allFilter.SupportedTemplateNames.Add("Stretch");
            IStringArray allProductNames = new StrArrayClass();
            allProductNames.Add("L1T");
            allProductNames.Add("L1R");
            ((IURIProductNameFilter)allFilter).ProductNames = allProductNames;

            // The L1T filter does not support orthorectification.
            IItemURIFilter l1tFilter = new URIProductNameFilterClass();
            l1tFilter.Name = "L1T";
            l1tFilter.SupportsOrthorectification = false;
            l1tFilter.SupportedTemplateNames = new StrArrayClass();
            l1tFilter.SupportedTemplateNames.Add("Raw");
            l1tFilter.SupportedTemplateNames.Add("Stretch");
            IStringArray l1tProductNames = new StrArrayClass();
            l1tProductNames.Add("L1T");
            ((IURIProductNameFilter)l1tFilter).ProductNames = l1tProductNames;

            IItemURIFilter l1rFilter = new URIProductNameFilterClass();
            l1rFilter.Name = "L1R";
            l1rFilter.SupportsOrthorectification = true;
            l1rFilter.SupportedTemplateNames = new StrArrayClass();
            l1rFilter.SupportedTemplateNames.Add("Raw");
            l1rFilter.SupportedTemplateNames.Add("Stretch");
            IStringArray l1rProductNames = new StrArrayClass();
            l1rProductNames.Add("L1R");
            ((IURIProductNameFilter)l1rFilter).ProductNames = l1rProductNames;

            // Add them to the supported uri filters list
            ((IRasterTypeProperties)theRasterType).SupportedURIFilters.Add(allFilter);
            ((IRasterTypeProperties)theRasterType).SupportedURIFilters.Add(l1tFilter);
            ((IRasterTypeProperties)theRasterType).SupportedURIFilters.Add(l1rFilter);
            // Set 'All' as default
            theRasterType.URIFilter = allFilter;
            #endregion

            return theRasterType;
        }

        /// <summary>
        /// Name of the Raster Type Factory
        /// </summary>
        public string Name
        {
            get { return "Custom Raster Type Factory"; }
        }

        /// <summary>
        /// Names of the Raster Types supported by the factory.
        /// </summary>
        public IStringArray RasterTypeNames
        {
            get { return myRasterTypeNames; }
        }
        #endregion

        #region COM Registration Function(s)
        [ComRegisterFunction()]
        static void Reg(string regKey)
        {
            ESRI.ArcGIS.ADF.CATIDs.RasterTypeFactory.Register(regKey);
        }

        [ComUnregisterFunction()]
        static void Unreg(string regKey)
        {
            ESRI.ArcGIS.ADF.CATIDs.RasterTypeFactory.Unregister(regKey);
        }
        #endregion
    }

    [Guid("316725CB-35F2-4159-BEBB-A1445ECE9CF1")]
    [ClassInterface(ClassInterfaceType.None)]
    [ProgId("SampleRasterType.CustomRasterType")]
    [ComVisible(true)]
    public class DMCIIRasterBuilder : IRasterBuilder, IRasterBuilderInit, IPersistVariant,
        IRasterBuilder2, IRasterBuilderInit2
    {
        #region Private Members
        // The Mosaic Dataset currently using the Raster Type.
        IMosaicDataset myMosaicDataset;
        // The default spatial reference to apply to added data (if no spatial reference exists).
        ISpatialReference myDefaultSpatialReference;

        // The Raster Type Operation object (usually a Raster Type object).
        IRasterTypeOperation myRasterTypeOperation;
        // The Raster Type Properties.
        IPropertySet myRasterTypeProperties;

        // Array to fill with ItemURI's.
        IItemURIArray myURIArray;

        // GeoTransform helper object.
        IGeoTransformationHelper myGeoTransformationHelper;
        // Flags to specify whether the Raster Type can merge items and 
        bool myCanMergeItems;
        // if it has merged item.
        bool myMergeItems;

        // Mapping from field names to names or properties in the item propertyset.
        IPropertySet myAuxiliaryFieldAlias;
        // Fields to add to the Mosaic Dataset when items are added through this Raster Type.
        IFields myAuxiliaryFields;

        ITrackCancel myTrackCancel;
        UID myUID; // UID for the Custom Builder.

        // The current dimap file being processed.
        string myCurrentDimFile;
        #endregion

        public DMCIIRasterBuilder()
        {
            myMosaicDataset = null;
            myDefaultSpatialReference = null;
            myRasterTypeOperation = null;
            myRasterTypeProperties = null;
            myTrackCancel = null;

            myURIArray = null;

            myGeoTransformationHelper = null;
            myCanMergeItems = false;
            myMergeItems = false;

            myAuxiliaryFieldAlias = null;
            myAuxiliaryFields = null;

            myUID = new UIDClass();
            myUID.Value = "{316725CB-35F2-4159-BEBB-A1445ECE9CF1}";
        }

        #region IRasterBuilder Members

        /// <summary>
        /// This defines a mapping from field names in the attribute table of the mosaic to
        /// properties in the property set associated with the dataset, incase a user wants 
        /// specify fields which are different from the property in the dataset.
        /// e.g. The field CloudCover may map to a property called C_C in the dataset built 
        /// by the builder.
        /// </summary>
        public IPropertySet AuxiliaryFieldAlias
        {
            get
            {
                return myAuxiliaryFieldAlias;
            }
            set
            {
                myAuxiliaryFieldAlias = value;
            }
        }

        /// <summary>
        /// Specify fields if necessary to be added to the Mosaic Dataset when 
        /// items are added throug hthis Raster Type.
        /// </summary>
        public IFields AuxiliaryFields
        {
            get
            {
                if (myAuxiliaryFields == null)
                {
                    myAuxiliaryFields = new FieldsClass();
                    AddFields(myAuxiliaryFields);
                }
                return myAuxiliaryFields;
            }
            set
            {
                myAuxiliaryFields = value;
            }
        }

        /// <summary>
        /// Get a crawler recommended by the Raster Type based on the data srouce properties provided.
        /// </summary>
        /// <param name="pDataSourceProperties">Data source properties.</param>
        /// <returns>Data source crawler recommended by the raster type.</returns>
        public IDataSourceCrawler GetRecommendedCrawler(IPropertySet pDataSourceProperties)
        {
            try
            {
                // This is usually a file crawler because it can crawl directories as well, unless
                // special types of data needs to be crawled.
                IDataSourceCrawler myCrawler = new FileCrawlerClass();
                ((IFileCrawler)myCrawler).Path = Convert.ToString(pDataSourceProperties.GetProperty("Source"));
                ((IFileCrawler)myCrawler).Recurse = Convert.ToBoolean(pDataSourceProperties.GetProperty("Recurse"));
                myCrawler.Filter = Convert.ToString(pDataSourceProperties.GetProperty("Filter"));
                if (myCrawler.Filter == null || myCrawler.Filter == "")
                    myCrawler.Filter = "*.dim";
                return myCrawler;
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// Prepare the Raster Type for generating item Unique Resource Identifier (URI)
        /// </summary>
        /// <param name="pCrawler">Crawler to use to generate the item URI's</param>
        public void BeginConstruction(IDataSourceCrawler pCrawler)
        {
            myURIArray = new ItemURIArrayClass();
        }

        /// <summary>
        /// Construct a Unique Resource Identifier (URI)
        /// for each crawler item
        /// </summary>
        /// <param name="crawlerItem">Crawled Item from which the URI is generated</param>
        public void ConstructURIs(object crawlerItem)
        {
            myCurrentDimFile = (string)crawlerItem;
        }

        /// <summary>
        /// Finish construction of the URI's
        /// </summary>
        /// <returns>Array containing finised URI's</returns>
        public IItemURIArray EndConstruction()
        {
            return myURIArray;
        }

        /// <summary>
        /// Generate the next URI.
        /// </summary>
        /// <returns>The URI generated.</returns>
        public IItemURI GetNextURI()
        {
            IItemURI newURI = null;
            try
            {
                // Check to see if the item cralwed is a .dim file.
                if (myCurrentDimFile != "" && myCurrentDimFile != null && myCurrentDimFile.EndsWith(".dim"))
                {
                    // Create a new Dimap Parser obect and item uri.
                    DiMapParser myDimParser = new DiMapParser(myCurrentDimFile);
                    newURI = new ItemURIClass();
                    // Set the display name, Group, Product Name, Tag and Key.
                    newURI.DisplayName = System.IO.Path.GetFileName(myCurrentDimFile);
                    newURI.Group = System.IO.Path.GetFileNameWithoutExtension(myCurrentDimFile);
                    newURI.Key = myCurrentDimFile;
                    newURI.ProductName = myDimParser.ProductType;
                    newURI.Tag = "MS";
                    // Set the timestamp of the dimfile as source time stamp. This helps 
                    // with synchronization later.
                    IRasterTypeEnvironment myEnv = new RasterTypeEnvironmentClass();
                    DateTime dimTS = myEnv.GetTimeStamp(myCurrentDimFile);
                    newURI.SourceTimeStamp = dimTS;

                    myDimParser = null;
                    myCurrentDimFile = "";
                    myURIArray.Add(newURI);
                }
            }
            catch (Exception)
            {
                throw;
            }
            return newURI;
        }

        /// <summary>
        /// Build the Builder Item which includes the function raster dataset and its footprint 
        /// given the ItemURI.
        /// </summary>
        /// <param name="pItemURI">ItemURi to use to build the Builder Item.</param>
        /// <returns>The builder item.</returns>
        public IBuilderItem Build(IItemURI pItemURI)
        {
            try
            {
                // Create a new parser object and builder item.
                DiMapParser myDimParser = new DiMapParser(pItemURI.Key);
                IBuilderItem currItem = new BuilderItemClass();

                // Set Category and URI
                currItem.Category = esriRasterCatalogItemCategory.esriRasterCatalogItemCategoryPrimary;
                currItem.URI = pItemURI;

                // Set FunctionRasterDataset
                IFunctionRasterDataset inputFrd = GetFRD(myDimParser, pItemURI);
                currItem.Dataset = inputFrd;
                // Set band information for the function dataset including names, wavelengths and stats if available.
                SetBandProperties((IDataset)inputFrd, myDimParser);

                // Set Footprint
                IGeoDataset geoDset = (IGeoDataset)inputFrd;
                // Set it to the current raster extent first. If the raster has no 
                // spatial reference, the extents will be in pixel space.
                currItem.Footprint = (IGeometry)geoDset.Extent;
                // The get the footprint from the dim file is it exists.
                currItem.Footprint = GetFootprint(myDimParser);

                // Set Properties. These properties are used to fill the Auxiliary Fields 
                // defined earlier and also key properties if the names are correct.
                IPropertySet propSet = currItem.Dataset.Properties;
                if (null == propSet)
                    propSet = new PropertySetClass();
                double sunAzimuth = Convert.ToDouble(myDimParser.SunAzimuth);
                double sunElevation = Convert.ToDouble(myDimParser.SunElevation);
                double sensorAzimuth = Convert.ToDouble(myDimParser.SensorAzimuth);
                double sensorElevation = 180 - Convert.ToDouble(myDimParser.IncidenceAngle);
                string acqDate = myDimParser.AcquisitionDate;
                string acqTime = myDimParser.AcquisitionTime;
                // Create a time object from the provided date and time.
                ITime acqDateTimeObj = new TimeClass();
                acqDateTimeObj.SetFromTimeString(esriTimeStringFormat.esriTSFYearThruSubSecondWithDash,
                    acqDate + " " + acqTime);
                // and obtain a DateTime object to set as value of the property. This ensures the 
                // field displays the value correctly.
                DateTime acqDateTimeFieldVal = acqDateTimeObj.QueryOleTime();

                propSet.SetProperty("AcquisitionDate", acqDateTimeFieldVal);
                propSet.SetProperty("SensorName", myDimParser.MetadataProfile);
                propSet.SetProperty("SunAzimuth", sunAzimuth);
                propSet.SetProperty("SunElevation", sunElevation);
                propSet.SetProperty("SatAzimuth", sensorAzimuth);
                propSet.SetProperty("SatElevation", sensorElevation);
                currItem.Dataset.Properties = propSet;

                return currItem;
            }
            catch (Exception exc)
            {
                throw exc;
            }
        }

        /// <summary>
        /// Flag to specify whether the Raster Builder can build items in place.
        /// </summary>
        public bool CanBuildInPlace
        {
            get { return false; }
        }

        /// <summary>
        /// Check if the item provided is "stale" or not valid
        /// </summary>
        /// <param name="pItemURI">URI for the item to be checked</param>
        /// <returns>Flag to specify whether the item is stale or not.</returns>
        public bool IsStale(IItemURI pItemURI)
        {
            try
            {
                IRasterTypeEnvironment myEnv = new RasterTypeEnvironmentClass();
                DateTime currDimTS = myEnv.GetTimeStamp(pItemURI.Key);
                return pItemURI.SourceTimeStamp != currDimTS;
            }
            catch (Exception)
            {
                throw;
            }
        }


        /// <summary>
        /// Properties associated with the Raster Type
        /// </summary>
        public IPropertySet Properties
        {
            get
            {
                if (myRasterTypeProperties == null)
                    myRasterTypeProperties = new PropertySetClass();
                return myRasterTypeProperties;
            }
            set
            {
                myRasterTypeProperties = value;
            }
        }

        /// <summary>
        /// Sets band properties on a given dataset including stats, band names and wavelengths.
        /// </summary>
        /// <param name="dataset">The dataset to set properties on.</param>
        /// <param name="dimParser">Dimap parser to read properties from.</param>
        private void SetBandProperties(IDataset dataset, DiMapParser dimParser)
        {
            try
            {
                // Set band band props.
                IRasterKeyProperties rasterKeyProps = (IRasterKeyProperties)dataset;
                IRasterBandCollection rasterBandColl = (IRasterBandCollection)dataset;
                int imageNumBands = ((IFunctionRasterDataset)dataset).RasterInfo.BandCount;
                int dinNumBands = dimParser.NumBands;
                int[] bandIndexes = new int[dinNumBands];
                IStringArray bandNames = new StrArrayClass();
                for (int i = 0; i < dinNumBands; ++i)
                {
                    // Get band index for the first band.
                    bandIndexes[i] = Convert.ToInt16(dimParser.GetBandIndex(i));
                    // Validate band index.
                    if (bandIndexes[i] > 0 && bandIndexes[i] <= imageNumBands)
                    {
                        // Get Band Name for the index.
                        bandNames.Add(dimParser.GetBandDesc(bandIndexes[i]));
                        // Get Band stats for the index.
                        IRasterStatistics bandStats = new RasterStatisticsClass();
                        bandStats.Minimum = Convert.ToDouble(dimParser.GetBandStatMin(bandIndexes[i]));
                        bandStats.Maximum = Convert.ToDouble(dimParser.GetBandStatMax(bandIndexes[i]));
                        bandStats.Mean = Convert.ToDouble(dimParser.GetBandStatMean(bandIndexes[i]));
                        bandStats.StandardDeviation = Convert.ToDouble(dimParser.GetBandStatStdDev(bandIndexes[i]));
                        // Set stats on the dataset.
                        ((IRasterBandEdit2)rasterBandColl.Item(bandIndexes[i] - 1)).AlterStatistics(bandStats);
                        // Set Band Name and wavelengths according to the name.
                        rasterKeyProps.SetBandProperty("BandName", (bandIndexes[i] - 1), bandNames.get_Element(i));
                        SetBandWavelengths(dataset, (bandIndexes[i] - 1));
                        // Refresh dataset so changes are saved.
                        ((IRasterDataset3)dataset).Refresh();
                    }
                }
            }
            catch (Exception exc)
            {
                string error = exc.Message;
            }
        }

        /// <summary>
        /// Set the wavelengths corresponding to the band name.
        /// </summary>
        private void SetBandWavelengths(IDataset dataset, int bandIndex)
        {
            IRasterKeyProperties rasterKeyProps = (IRasterKeyProperties)dataset;
            IRasterBandCollection rasterBandColl = (IRasterBandCollection)dataset;
            string bandName = (string)rasterKeyProps.GetBandProperty("BandName", bandIndex);
            // Set wavelengths for the bands
            switch (bandName.ToLower())
            {
                case "red":
                    {
                        rasterKeyProps.SetBandProperty("WavelengthMin", bandIndex, 630);
                        rasterKeyProps.SetBandProperty("WavelengthMax", bandIndex, 690);
                    }
                    break;

                case "green":
                    {
                        rasterKeyProps.SetBandProperty("WavelengthMin", bandIndex, 520);
                        rasterKeyProps.SetBandProperty("WavelengthMax", bandIndex, 600);
                    }
                    break;

                case "nir":
                case "nearinfrared":
                    {
                        rasterKeyProps.SetBandProperty("WavelengthMin", bandIndex, 770);
                        rasterKeyProps.SetBandProperty("WavelengthMax", bandIndex, 900);
                    }
                    break;
            }
        }

        //private IGeometry GetFootprint(DiMapParser dimParser)
        //{
        //    IGeometry currFootprint = null;
        //    dimParser.ResetVertexCount();
        //    string xs = "";
        //    string ys = "";
        //    string rows = "";
        //    string cols = "";
        //    double minX = 10000000000.0;
        //    double maxX = -1000000000.00;
        //    double minY = 1000000000.00;
        //    double maxY = -1000000000.00;
        //    double minRow = 1000000000.00;
        //    double maxRow = -1000000000.0;
        //    double minCol = 1000000000.00;
        //    double maxCol = -1000000000.0;
        //    double x = 0.0;
        //    double y = 0.0;
        //    double row = 0.0;
        //    double col = 0.0;

        //    while (dimParser.GetNextVertex(out xs, out ys, out rows, out cols))
        //    {
        //        x = Convert.ToDouble(xs);
        //        y = Convert.ToDouble(ys);
        //        row = Convert.ToDouble(rows);
        //        col = Convert.ToDouble(cols);

        //        if (x < minX)
        //            minX = x;
        //        if (x > maxX)
        //            maxX = x;

        //        if (y < minY)
        //            minY = y;
        //        if (y > maxY)
        //            maxY = y;

        //        if (row < minRow)
        //            minRow = row;
        //        if (row > maxRow)
        //            maxRow = row;

        //        if (col < minCol)
        //            minCol = col;
        //        if (col > maxCol)
        //            maxCol = col;

        //        x = 0.0;
        //        y = 0.0;
        //        row = 0.0;
        //        col = 0.0;
        //        xs = "";
        //        ys = "";
        //        rows = "";
        //        cols = "";
        //    }
        //    x = Convert.ToDouble(xs);
        //    y = Convert.ToDouble(ys);
        //    row = Convert.ToDouble(rows);
        //    col = Convert.ToDouble(cols);

        //    if (x < minX)
        //        minX = x;
        //    if (x > maxX)
        //        maxX = x;

        //    if (y < minY)
        //        minY = y;
        //    if (y > maxY)
        //        maxY = y;

        //    if (row < minRow)
        //        minRow = row;
        //    if (row > maxRow)
        //        maxRow = row;

        //    if (col < minCol)
        //        minCol = col;
        //    if (col > maxCol)
        //        maxCol = col;

        //    currFootprint = new PolygonClass();
        //    IPointCollection currPointColl = (IPointCollection)currFootprint;
        //    IEnvelope rectEnvelope = new EnvelopeClass();
        //    rectEnvelope.PutCoords(minX, minY, maxX, maxY);
        //    ISegmentCollection segmentCollection = (ISegmentCollection)currFootprint;
        //    segmentCollection.SetRectangle(rectEnvelope);

        //    // Get Srs
        //    int epsgcode = Convert.ToInt32((dimParser.SrsCode.Split(':'))[1]);
        //    ISpatialReferenceFactory3 srsfactory = new SpatialReferenceEnvironmentClass();
        //    ISpatialReference dimSrs = srsfactory.CreateSpatialReference(epsgcode);
        //    ISpatialReferenceResolution srsRes = (ISpatialReferenceResolution)dimSrs;
        //    srsRes.ConstructFromHorizon();
        //    srsRes.SetDefaultXYResolution();
        //    ((ISpatialReferenceTolerance)dimSrs).SetDefaultXYTolerance();
        //    currFootprint.SpatialReference = dimSrs;

        //    #region Commented
        //    //IEnvelope extent = new EnvelopeClass();
        //    //extent.XMin = geoDset.Extent.XMin;
        //    //extent.XMax = geoDset.Extent.XMax;
        //    //extent.YMin = geoDset.Extent.YMin;
        //    //extent.YMax = geoDset.Extent.YMax;
        //    //extent.SpatialReference = geoDset.SpatialReference;
        //    //extent.Width = inputFrd.RasterInfo.Extent.Width;
        //    //extent.Height = inputFrd.RasterInfo.Extent.Height;
        //    //currItem.Footprint = (IGeometry)extent;

        //    //myDimParser.ResetVertexCount();
        //    //string x = "";
        //    //string y = "";
        //    //string row = "";
        //    //string col = "";
        //    //IGeometry currFootprint = new PolygonClass();
        //    //IPointCollection currPointColl = (IPointCollection)currFootprint;

        //    // Creating a polygon!!!

        //    ////Build a polygon from a sequence of points. 
        //    ////Add arrays of points to a geometry using the IGeometryBridge2 interface on the 
        //    ////GeometryEnvironment singleton object.
        //    //IGeometryBridge2 geometryBridge2 = new GeometryEnvironmentClass();
        //    //IPointCollection4 pointCollection4 = new PolygonClass();

        //    ////TODO:
        //    ////pointCollection4.SpatialReference = 'Define the spatial reference of the new polygon.

        //    //WKSPoint[] aWKSPointBuffer = null;
        //    //long cPoints = 4; //The number of points in the first part.
        //    //aWKSPointBuffer = new WKSPoint[System.Convert.ToInt32(cPoints - 1) + 1];

        //    ////TODO:
        //    ////aWKSPointBuffer = 'Read cPoints into the point buffer.

        //    //geometryBridge2.SetWKSPoints(pointCollection4, ref aWKSPointBuffer);

        //    //myDimParser.GetNextVertex(out x, out y, out col, out row);
        //    //IPoint currPoint1 = new PointClass();
        //    //currPoint1.X = Convert.ToDouble(x);
        //    //currPoint1.Y = Convert.ToDouble(y);
        //    //myDimParser.GetNextVertex(out x, out y, out col, out row);
        //    //IPoint currPoint2 = new PointClass();
        //    //currPoint1.X = Convert.ToDouble(x);
        //    //currPoint1.Y = Convert.ToDouble(y);
        //    //myDimParser.GetNextVertex(out x, out y, out col, out row);
        //    //IPoint currPoint3 = new PointClass();
        //    //currPoint1.X = Convert.ToDouble(x);
        //    //currPoint1.Y = Convert.ToDouble(y);
        //    //myDimParser.GetNextVertex(out x, out y, out col, out row);
        //    //IPoint currPoint4 = new PointClass();
        //    //currPoint1.X = Convert.ToDouble(x);
        //    //currPoint1.Y = Convert.ToDouble(y);
        //    //object refPoint1 = (object)currPoint1;
        //    //object refPoint2 = (object)currPoint2;
        //    //object refPoint3 = (object)currPoint3;
        //    //object refPoint4 = (object)currPoint4;
        //    //currPointColl.AddPoint(currPoint1, ref refPoint4, ref refPoint2);
        //    //currPointColl.AddPoint(currPoint2, ref refPoint1, ref refPoint3);
        //    //currPointColl.AddPoint(currPoint3, ref refPoint2, ref refPoint4);
        //    //currPointColl.AddPoint(currPoint4, ref refPoint3, ref refPoint1);
        //    //((IPolygon)currFootprint).Close();
        //    //currFootprint.SpatialReference = dimSrs;
        //    #endregion
        //    return currFootprint;
        //}

        /// <summary>
        /// Get the footprint from the dimap file if it exists.
        /// </summary>
        /// <param name="dimParser">Dimap file parser.</param>
        /// <returns>Footprint geomtry.</returns>
        private IGeometry GetFootprint(DiMapParser dimParser)
        {
            IGeometry currFootprint = null;
            dimParser.ResetVertexCount();
            string xs = "";
            string ys = "";
            double minX = 10000000000.0;
            double maxX = -1000000000.00;
            double minY = 1000000000.00;
            double maxY = -1000000000.00;
            double x = 0.0;
            double y = 0.0;
            string units = dimParser.ProductType;
            if (units.ToLower() == "L1T".ToLower())
                units = "M";
            else if (units.ToLower() == "L1R".ToLower())
                units = "Deg";
            // Get vertices from the dimap file and figure out the min,max.
            while (dimParser.GetNextVertex2(out xs, out ys, units))
            {
                x = Convert.ToDouble(xs);
                y = Convert.ToDouble(ys);

                if (x < minX)
                    minX = x;
                if (x > maxX)
                    maxX = x;

                if (y < minY)
                    minY = y;
                if (y > maxY)
                    maxY = y;

                x = 0.0;
                y = 0.0;
                xs = "";
                ys = "";
            }
            x = Convert.ToDouble(xs);
            y = Convert.ToDouble(ys);

            if (x < minX)
                minX = x;
            if (x > maxX)
                maxX = x;

            if (y < minY)
                minY = y;
            if (y > maxY)
                maxY = y;

            // create a new polygon and fill it using the vertices calculated.
            currFootprint = new PolygonClass();
            IPointCollection currPointColl = (IPointCollection)currFootprint;
            IEnvelope rectEnvelope = new EnvelopeClass();
            rectEnvelope.PutCoords(minX, minY, maxX, maxY);
            ISegmentCollection segmentCollection = (ISegmentCollection)currFootprint;
            segmentCollection.SetRectangle(rectEnvelope);

            // Get Srs from the dim file and set it on the footprint.
            int epsgcode = Convert.ToInt32((dimParser.SrsCode.Split(':'))[1]);
            ISpatialReferenceFactory3 srsfactory = new SpatialReferenceEnvironmentClass();
            ISpatialReference dimSrs = srsfactory.CreateSpatialReference(epsgcode);
            ISpatialReferenceResolution srsRes = (ISpatialReferenceResolution)dimSrs;
            srsRes.ConstructFromHorizon();
            srsRes.SetDefaultXYResolution();
            ((ISpatialReferenceTolerance)dimSrs).SetDefaultXYTolerance();
            currFootprint.SpatialReference = dimSrs;
            return currFootprint;
        }

        /// <summary>
        /// Create the function raster dataset from the source images.
        /// </summary>
        /// <param name="dimPar">Parser for the dimap file.</param>
        /// <param name="pItemURI">ItemURi to use.</param>
        /// <returns>Function raster dataset created.</returns>
        private IFunctionRasterDataset GetFRD(DiMapParser dimPar, IItemURI pItemURI)
        {
            IFunctionRasterDataset opFrd = null;
            try
            {
                Type factoryType = Type.GetTypeFromProgID("esriDataSourcesRaster.RasterWorkspaceFactory");
                IWorkspaceFactory workspaceFactory = (IWorkspaceFactory)Activator.CreateInstance(factoryType);
                IWorkspace workspace = workspaceFactory.OpenFromFile(System.IO.Path.GetDirectoryName(pItemURI.Key), 0);
                IRasterWorkspace rasterWorkspace = (IRasterWorkspace)workspace;
                // Open the tif file associated with the .dim file as a raster dataset.
                string imagePath = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(pItemURI.Key),
                    pItemURI.Group + ".tif");
                string rpcPath = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(pItemURI.Key),
                    pItemURI.Group + ".rpc");
                IRasterDataset inputRasterDataset = null;
                if (File.Exists(imagePath))
                    inputRasterDataset = rasterWorkspace.OpenRasterDataset(pItemURI.Group + ".tif");
                else
                    return null;

                IFunctionRasterDataset intermedFrd = null;
                // If the file opes successfully, add a RasterInfo function on top.
                if (inputRasterDataset != null)
                {
                    // Create an Identity function dataset to get the raster info.
                    IRasterFunction identityFunction = new IdentityFunctionClass();
                    IFunctionRasterDataset idFrd = new FunctionRasterDatasetClass();
                    idFrd.Init(identityFunction, inputRasterDataset);
                    // Create a raster info function dataset.
                    IRasterFunction rasterInfoFunction = new RasterInfoFunctionClass();
                    IRasterInfoFunctionArguments rasterInfoFuncArgs = new RasterInfoFunctionArgumentsClass();
                    rasterInfoFuncArgs.Raster = inputRasterDataset;
                    rasterInfoFuncArgs.RasterInfo = idFrd.RasterInfo;
                    intermedFrd = new FunctionRasterDatasetClass();
                    intermedFrd.Init(rasterInfoFunction, rasterInfoFuncArgs);
                }
                else
                    return null;
                // Check if there is an RPC file associated with the image. If so
                // then add a geometric function to apply the rpc xform.
                if (File.Exists(rpcPath))
                    opFrd = ApplyRPC(rpcPath, (IRasterDataset)intermedFrd);

                // If no rpc pars exist or applying rpc fails, use the intermediate 
                // function raster dataset created.
                if (opFrd == null)
                    opFrd = intermedFrd;
                
                //IRasterFunction ebFunction = new ExtractBandFunctionClass();
                //IRasterFunctionArguments ebFuncArgs = new ExtractBandFunctionArgumentsClass();
                //ILongArray bandIDs = new LongArrayClass();
                //bandIDs.Add(2);
                //bandIDs.Add(1);
                //bandIDs.Add(0);
                ////bandIDs.Add(4);
                //((IExtractBandFunctionArguments)ebFuncArgs).BandIDs = bandIDs;
                //((IExtractBandFunctionArguments)ebFuncArgs).Raster = inputRasterDataset;
                //opFrd = new FunctionRasterDatasetClass();
                //opFrd.Init(ebFunction, ebFuncArgs);

                //if (opFrd == null)
                //{
                //    IRasterFunction identityFunction = new IdentityFunctionClass();
                //    opFrd = new FunctionRasterDatasetClass();
                //    opFrd.Init(identityFunction, inputRasterDataset);
                //}
            }
            catch (Exception exc)
            {
                string error = exc.Message;
            }
            return opFrd;
        }

        /// <summary>
        /// Parse the RPC parameters file associated with the image and create an RPCXform
        /// to bea applied to the inputDataset as a geomtric function.
        /// </summary>
        /// <param name="rpcPath">Path to the rpc parameters file.</param>
        /// <param name="inputDataset">Input dataset to apply the xform on.</param>
        /// <returns>Function raster dataset created.</returns>
        private IFunctionRasterDataset ApplyRPC(string rpcPath, IRasterDataset inputDataset)
        {
            IFunctionRasterDataset opFrd = null;
            try
            {
                // Open the RPC file and create Geometric transform
                IGeodataXform finalXForm = null;
                IRPCXform rpcXForm = GetRPCXForm(rpcPath);

                IFunctionRasterDataset idFrd = null;
                if (!(inputDataset is IFunctionRasterDataset))
                {
                    IRasterFunction identityFunction = new IdentityFunctionClass();
                    idFrd = new FunctionRasterDatasetClass();
                    idFrd.Init(identityFunction, inputDataset);
                }
                else
                    idFrd = (IFunctionRasterDataset)inputDataset;

                IRasterInfo datasetRasterInfo = idFrd.RasterInfo;
                IEnvelope datasetExtent = datasetRasterInfo.Extent;
                ISpatialReference datasetSrs = ((IGeoDataset)idFrd).SpatialReference;

                long dRows = datasetRasterInfo.Height;
                long dCols = datasetRasterInfo.Width;
                IEnvelope pixelExtent = new EnvelopeClass();
                pixelExtent.PutCoords(-0.5, 0.5 - dRows, -0.5 + dCols, 0.5);

                bool noAffineNeeded = ((IClone)pixelExtent).IsEqual((IClone)datasetExtent);
                if (!noAffineNeeded)
                {
                    // Tranform ground space to pixel space.
                    IAffineTransformation2D affineXform = new AffineTransformation2DClass();
                    affineXform.DefineFromEnvelopes(datasetExtent, pixelExtent);
                    IGeometricXform geoXform = new GeometricXformClass();
                    geoXform.Transformation = affineXform;
                    finalXForm = geoXform;
                }

                // Transform from pixel space back to ground space to set as the forward transform.
                IEnvelope groundExtent = ((IGeoDataset)idFrd).Extent;
                groundExtent.Project(datasetSrs);
                IAffineTransformation2D affineXform2 = new AffineTransformation2DClass();
                affineXform2.DefineFromEnvelopes(pixelExtent, groundExtent);
                IGeometricXform forwardXForm = new GeometricXformClass();
                forwardXForm.Transformation = affineXform2;
                rpcXForm.ForwardXform = forwardXForm;

                // Create the composite transform that changes ground values to pixel space
                // then applies the rpc transform which will transform them back to ground space.
                ICompositeXform compositeXForm = new CompositeXformClass();
                compositeXForm.Add(finalXForm);
                compositeXForm.Add(rpcXForm);
                finalXForm = (IGeodataXform)compositeXForm;

                // Then apply the transform on the raster using the geometric function.
                if (finalXForm != null)
                {
                    IRasterFunction geometricFunction = new GeometricFunctionClass();
                    IGeometricFunctionArguments geometricFunctionArgs = null;
                    // Get the geomtric function arguments if supplied by the user (in the UI).
                    if (myRasterTypeOperation != null &&
                        ((IRasterTypeProperties)myRasterTypeOperation).OrthorectificationParameters != null)
                        geometricFunctionArgs =
                        ((IRasterTypeProperties)myRasterTypeOperation).OrthorectificationParameters;
                    else
                        geometricFunctionArgs = new GeometricFunctionArgumentsClass();
                    // Append the xform to the existing ones from the image.
                    geometricFunctionArgs.AppendGeodataXform = true;
                    geometricFunctionArgs.GeodataXform = finalXForm;
                    geometricFunctionArgs.Raster = inputDataset;
                    opFrd = new FunctionRasterDatasetClass();
                    opFrd.Init(geometricFunction, geometricFunctionArgs);
                }
                return opFrd;
            }
            catch (Exception exc)
            {
                string error = exc.Message;
                return opFrd;
            }
        }

        /// <summary>
        /// Create an RPCXForm from a text file containing parameters.
        /// </summary>
        /// <param name="rpcFilePath">Text file containing the parameters.</param>
        /// <returns>The RPCXForm generated.</returns>
        private IRPCXform GetRPCXForm(string rpcFilePath)
        {
            try
            {
                // Array for parameters.
                double[] RPC = new double[90];
                // Propertyset to store properties as backup.
                //IPropertySet coefficients = new PropertySetClass();

                #region Parse RPC text file
                // Use the stream reader to open the file and read lines from it.
                using (StreamReader sr = new StreamReader(rpcFilePath))
                {
                    string line;
                    int lineNumber = 0;

                    while ((line = sr.ReadLine()) != null)
                    {
                        ++lineNumber;
                        try
                        {
                            // Split the line into tokens based on delimiters
                            char[] delimiters = { ':', ' ' };
                            string[] tokens = line.Split(delimiters, System.StringSplitOptions.RemoveEmptyEntries);
                            int numTokens = tokens.GetLength(0);
                            if (numTokens > 1)
                            {
                                string currPar = tokens[0];
                                double currValue = Convert.ToDouble(tokens[1]);
                                // Convert the Value to a double and store in the array.
                                RPC[(lineNumber - 1)] = currValue;
                                // Store the property and the value in the propertyset to lookup later if needed.
                                //coefficients.SetProperty(currPar, currValue);
                                // Read units for conversion if needed
                                //string currUnit = tokens[2];
                            }
                            else
                                Console.WriteLine("Could not parse line " + lineNumber.ToString());
                        }
                        catch (Exception ex)
                        {
                            Console.Write(ex.ToString());
                        }
                    }
                    sr.Close();
                }
                #endregion

                // Create the new RPCXForm from the parameter array.
                IRPCXform myRPCXform = (IRPCXform)new RPCXform();
                object rpcCoeffs = ((object)RPC);
                myRPCXform.DefineFromCoefficients(ref rpcCoeffs);

                return myRPCXform;
            }
            catch (Exception exc)
            {
                string error = exc.Message;
                throw exc;
            }
        }

        /// <summary>
        /// Create new fields to add to the mosaic dataset attribute table.
        /// </summary>
        /// <param name="myFields">Fields to be added.</param>
        private void AddFields(IFields myFields)
        {
            // Create a new field object
            IField pField = new FieldClass();
            // Set the field editor for this field
            IFieldEdit objectIDFieldEditor = (IFieldEdit)pField;
            // Set the name and alias of the field
            objectIDFieldEditor.Name_2 = "SensorName"; 
            objectIDFieldEditor.AliasName_2 = "Sensor Name";
            // Set the type of the field
            objectIDFieldEditor.Type_2 = esriFieldType.esriFieldTypeString;
            // Add the newly created field to list of existing fields
            IFieldsEdit fieldsEditor = (IFieldsEdit)myFields;
            fieldsEditor.AddField(pField);

            // Create a new field object
            pField = new FieldClass();
            // Set the field editor for this field
            objectIDFieldEditor = (IFieldEdit)pField;
            // Set the name and alias of the field
            objectIDFieldEditor.Name_2 = "AcquisitionDate"; 
            objectIDFieldEditor.AliasName_2 = "Acquisition Date";
            // Set the type of the field
            objectIDFieldEditor.Type_2 = esriFieldType.esriFieldTypeDate;
            fieldsEditor.AddField(pField);

            // Create a new field object
            pField = new FieldClass();
            // Set the field editor for this field
            objectIDFieldEditor = (IFieldEdit)pField;
            // Set the name and alias of the field
            objectIDFieldEditor.Name_2 = "SunAzimuth";
            objectIDFieldEditor.AliasName_2 = "Sun Azimuth";
            // Set the type of the field
            objectIDFieldEditor.Type_2 = esriFieldType.esriFieldTypeDouble;
            fieldsEditor.AddField(pField);

            // Create a new field object
            pField = new FieldClass();
            // Set the field editor for this field
            objectIDFieldEditor = (IFieldEdit)pField;
            // Set the name and alias of the field
            objectIDFieldEditor.Name_2 = "SunElevation";
            objectIDFieldEditor.AliasName_2 = "Sun Elevation";
            // Set the type of the field
            objectIDFieldEditor.Type_2 = esriFieldType.esriFieldTypeDouble;
            fieldsEditor.AddField(pField);

            // Create a new field object
            pField = new FieldClass();
            // Set the field editor for this field
            objectIDFieldEditor = (IFieldEdit)pField;
            // Set the name and alias of the field
            objectIDFieldEditor.Name_2 = "SatAzimuth";
            objectIDFieldEditor.AliasName_2 = "Satellite Azimuth";
            // Set the type of the field as Blob
            objectIDFieldEditor.Type_2 = esriFieldType.esriFieldTypeDouble;
            fieldsEditor.AddField(pField);

            // Create a new field object
            pField = new FieldClass();
            // Set the field editor for this field
            objectIDFieldEditor = (IFieldEdit)pField;
            // Set the name and alias of the field
            objectIDFieldEditor.Name_2 = "SatElevation";
            objectIDFieldEditor.AliasName_2 = "Satellite Elevation";
            // Set the type of the field as Blob
            objectIDFieldEditor.Type_2 = esriFieldType.esriFieldTypeDouble;
            fieldsEditor.AddField(pField);
        }
        #endregion

        #region IRasterBuilderInit Members

        public ISpatialReference DefaultSpatialReference
        {
            get
            {
                return myDefaultSpatialReference;
            }
            set
            {
                myDefaultSpatialReference = value;
            }
        }

        public IMosaicDataset MosaicDataset
        {
            get
            {
                return myMosaicDataset;
            }
            set
            {
                myMosaicDataset = value;
            }
        }

        public IRasterTypeOperation RasterTypeOperation
        {
            get
            {
                return myRasterTypeOperation;
            }
            set
            {
                myRasterTypeOperation = value;
            }
        }

        public ITrackCancel TrackCancel
        {
            get
            {
                return myTrackCancel;
            }
            set
            {
                myTrackCancel = value;
            }
        }

        #endregion

        #region IPersistVariant Members
        /// <summary>
        /// UID for the object implementing the Persist Variant
        /// </summary>
        public UID ID
        {
            get { return myUID; }
        }

        /// <summary>
        /// Load the object from the stream provided
        /// </summary>
        /// <param name="Stream">Stream that represents the serialized Raster Type</param>
        public void Load(IVariantStream Stream)
        {
            string name = (string)Stream.Read();
            //if (innerRasterBuilder is IPersistVariant)
            //    ((IPersistVariant)innerRasterBuilder).Load(Stream);
            //innerRasterBuilder = (IRasterBuilder)Stream.Read(); // Load the innerRasterBuilder from the stream.
        }

        /// <summary>
        /// Same the Raster Type to the stream provided
        /// </summary>
        /// <param name="Stream">Stream to serialize the Raster Type into</param>
        public void Save(IVariantStream Stream)
        {
            Stream.Write("CustomRasterType");
            //if (innerRasterBuilder is IPersistVariant)
            //    ((IPersistVariant)innerRasterBuilder).Save(Stream);
            //Stream.Write(innerRasterBuilder); // Save the innerRasterBuilder into the stream.
        }

        #endregion

        #region IRasterBuilder2 Members
        /// <summary>
        /// Check if the data source provided is a valid data source for the builder.
        /// </summary>
        /// <param name="vtDataSource">Data source (usually the path to a metadta file)</param>
        /// <returns>Flag to specify whether it is  valid source.</returns>
        public bool CanBuild(object vtDataSource)
        {
            if (!(vtDataSource is string))
                return false;
            string dimFilePath = (string)vtDataSource;
            if (!dimFilePath.ToLower().EndsWith(".dim"))
                return false;
            DiMapParser myDimParser = null;
            try
            {
                myDimParser = new DiMapParser(dimFilePath);
                if (myDimParser.MetadataProfile.ToLower() == "DMCII".ToLower())
                {
                    myDimParser = null;
                    return true;
                }
                else
                {
                    myDimParser = null;
                    return false;
                }
            }
            catch (Exception exc)
            {
                myDimParser = null;
                string error = exc.Message;
                return false;
            }
        }

        public bool CanMergeItems
        {
            get { return myCanMergeItems; }
        }

        public bool MergeItems
        {
            get
            {
                return myMergeItems;
            }
            set
            {
                myMergeItems = value;
            }
        }

        /// <summary>
        /// Check to see if the properties provided to the raster type/builder 
        /// are sufficient for it to work. Usually used for UI validation.
        /// </summary>
        public void Validate()
        {
            return;
        }
        #endregion

        #region IRasterBuilderInit2 Members

        /// <summary>
        /// Helper object to store geographic transformations set on the mosaic dataset.
        /// </summary>
        public IGeoTransformationHelper GeoTransformationHelper
        {
            get
            {
                return myGeoTransformationHelper;
            }
            set
            {
                myGeoTransformationHelper = null;
            }
        }

        #endregion
    }

    /// <summary>
    /// Class used to parse the dim file (xml format) and get relevant properties from it.
    /// </summary>
    public class DiMapParser
    {
        private string myXmlPath;
        private XmlDocument myXmlDoc;
        private XmlNodeList bandInfo;
        private XmlNodeList bandStats;
        private XmlNodeList footprintInfo;
        private int vertexCount;

        public DiMapParser()
        {
            myXmlPath = null;
            bandInfo = null;
            bandStats = null;
            footprintInfo = null;
            vertexCount = 0;
        }

        public DiMapParser(string xmlPath)
        {
            myXmlPath = xmlPath;
            bandInfo = null;
            bandStats = null;
            footprintInfo = null;
            vertexCount = 0;
            myXmlDoc = new XmlDocument();
            myXmlDoc.Load(myXmlPath);
        }

        /// <summary>
        /// Flag to specify whether the footprint exists in the xml file.
        /// </summary>
        public bool FootPrintExists
        {
            get
            {
                if (footprintInfo == null)
                    footprintInfo = myXmlDoc.SelectSingleNode("//Dataset_Frame").SelectNodes("Vertex");
                return footprintInfo != null;
            }
        }

        /// <summary>
        /// Reset the vertex count to get vertices of the footprint.
        /// </summary>
        public void ResetVertexCount()
        {
            vertexCount = 0;
        }

        public bool GetNextVertex(out string x, out string y, out string col, out string row)
        {
            if (footprintInfo == null)
                footprintInfo = myXmlDoc.SelectSingleNode("//Dataset_Frame").SelectNodes("Vertex");
            x = footprintInfo[vertexCount].SelectSingleNode("FRAME_LON").InnerText;
            y = footprintInfo[vertexCount].SelectSingleNode("FRAME_LAT").InnerText;
            col = footprintInfo[vertexCount].SelectSingleNode("FRAME_COL").InnerText;
            row = footprintInfo[vertexCount].SelectSingleNode("FRAME_ROW").InnerText;
            ++vertexCount;

            if (vertexCount >= footprintInfo.Count)
                return false;
            else
                return true;
        }

        /// <summary>
        /// Get next vertex from the footprint defined in the xml based on the vertex count and unit.
        /// </summary>
        /// <param name="x">The X value.</param>
        /// <param name="y">The Y value.</param>
        /// <param name="unit">Unit to check which parameter to get vertex from.</param>
        /// <returns>True if next vertex exists.</returns>
        public bool GetNextVertex2(out string x, out string y, string unit)
        {
            if (unit == "Deg")
            {
                if (footprintInfo == null)
                    footprintInfo = myXmlDoc.SelectSingleNode("//Dataset_Frame").SelectNodes("Vertex");
                x = footprintInfo[vertexCount].SelectSingleNode("FRAME_LON").InnerText;
                y = footprintInfo[vertexCount].SelectSingleNode("FRAME_LAT").InnerText;
                //col = footprintInfo[vertexCount].SelectSingleNode("FRAME_COL").InnerText;
                //row = footprintInfo[vertexCount].SelectSingleNode("FRAME_ROW").InnerText;
            }
            else
            {
                if (footprintInfo == null)
                    footprintInfo = myXmlDoc.SelectSingleNode("//Dataset_Frame").SelectNodes("Vertex");
                x = footprintInfo[vertexCount].SelectSingleNode("FRAME_X").InnerText;
                y = footprintInfo[vertexCount].SelectSingleNode("FRAME_Y").InnerText;
                //col = footprintInfo[vertexCount].SelectSingleNode("FRAME_COL").InnerText;
                //row = footprintInfo[vertexCount].SelectSingleNode("FRAME_ROW").InnerText;
            }
            ++vertexCount;

            if (vertexCount >= footprintInfo.Count)
                return false;
            else
                return true;
        }

        /// <summary>
        /// The number of bands defined in the xml.
        /// </summary>
        public int NumBands
        {
            get
            {
                if (bandInfo == null)
                    bandInfo = myXmlDoc.SelectNodes("//Spectral_Band_Info");
                if (bandStats == null)
                    bandStats = myXmlDoc.SelectNodes("//Band_Statistics");
                return bandInfo.Count;
            }
        }

        /// <summary>
        /// Index of the band based on the counter.
        /// </summary>
        /// <param name="indexCounter">Counter (similar to vertexCount) to get the index for.</param>
        /// <returns>Index of the band as string.</returns>
        public string GetBandIndex(int indexCounter)
        {
            if (bandInfo == null)
                bandInfo = myXmlDoc.SelectNodes("//Spectral_Band_Info");
            return bandInfo[indexCounter].SelectSingleNode("BAND_INDEX").InnerText;
        }

        /// <summary>
        /// Get the name of the band.
        /// </summary>
        /// <param name="bandIndex">Index of the band for which to get the name.</param>
        /// <returns>Band name as string.</returns>
        public string GetBandDesc(int bandIndex)
        {
            if (bandInfo == null)
                bandInfo = myXmlDoc.SelectNodes("//Spectral_Band_Info");
            return bandInfo[bandIndex - 1].SelectSingleNode("BAND_DESCRIPTION").InnerText;
        }

        /// <summary>
        /// Get minimum value for the band.
        /// </summary>
        /// <param name="bandIndex">Index of the band for which to get the value.</param>
        /// <returns>Value requested as string.</returns>
        public string GetBandStatMin(int bandIndex)
        {
            if (bandStats == null)
                bandStats = myXmlDoc.SelectNodes("//Band_Statistics");
            return bandStats[bandIndex - 1].SelectSingleNode("STX_LIN_MIN").InnerText;
        }

        /// <summary>
        /// Get maximum value for the band.
        /// </summary>
        /// <param name="bandIndex">Index of the band for which to get the value.</param>
        /// <returns>Value requested as string.</returns>
        public string GetBandStatMax(int bandIndex)
        {
            if (bandStats == null)
                bandStats = myXmlDoc.SelectNodes("//Band_Statistics");
            return bandStats[bandIndex - 1].SelectSingleNode("STX_LIN_MAX").InnerText;
        }

        /// <summary>
        /// Get mean value for the band.
        /// </summary>
        /// <param name="bandIndex">Index of the band for which to get the value.</param>
        /// <returns>Value requested as string.</returns>
        public string GetBandStatMean(int bandIndex)
        {
            if (bandStats == null)
                bandStats = myXmlDoc.SelectNodes("//Band_Statistics");
            return bandStats[bandIndex - 1].SelectSingleNode("STX_MEAN").InnerText;
        }

        /// <summary>
        /// Get standard deviation value for the band.
        /// </summary>
        /// <param name="bandIndex">Index of the band for which to get the value.</param>
        /// <returns>Value requested as string.</returns>
        public string GetBandStatStdDev(int bandIndex)
        {
            if (bandStats == null)
                bandStats = myXmlDoc.SelectNodes("//Band_Statistics");
            return bandStats[bandIndex - 1].SelectSingleNode("STX_STDV").InnerText;
        }

        /// <summary>
        /// Get the product type for the dataset.
        /// </summary>
        public string ProductType
        {
            get
            {
                return myXmlDoc.SelectSingleNode("//PRODUCT_TYPE").InnerText;
            }
        }

        /// <summary>
        /// Get the sensor name for the dataset.
        /// </summary>
        public string MetadataProfile
        {
            get
            {
                return myXmlDoc.SelectSingleNode("//METADATA_PROFILE").InnerText;
            }
        }

        /// <summary>
        /// Get the geometric processing for the dataset.
        /// </summary>
        public string GeometricProcessing
        {
            get
            {
                return myXmlDoc.SelectSingleNode("//GEOMETRIC_PROCESSING").InnerText;
            }
        }

        /// <summary>
        /// Get the Acquisition Date for the dataset.
        /// </summary>
        public string AcquisitionDate
        {
            get
            {
                return myXmlDoc.SelectSingleNode("//IMAGING_DATE").InnerText;
            }
        }

        /// <summary>
        /// Get the Acquisition Time for the dataset.
        /// </summary>
        public string AcquisitionTime
        {
            get
            {
                return myXmlDoc.SelectSingleNode("//IMAGING_TIME").InnerText;
            }
        }

        /// <summary>
        /// Get the Sensor Angle for the dataset.
        /// </summary>
        public string IncidenceAngle
        {
            get
            {
                return myXmlDoc.SelectSingleNode("//INCIDENCE_ANGLE").InnerText;
            }
        }

        /// <summary>
        /// Get the Sun Azimuth for the dataset.
        /// </summary>
        public string SunAzimuth
        {
            get
            {
                return myXmlDoc.SelectSingleNode("//SUN_AZIMUTH").InnerText;
            }
        }

        /// <summary>
        /// Get the Sun Elevation for the dataset.
        /// </summary>
        public string SunElevation
        {
            get
            {
                return myXmlDoc.SelectSingleNode("//SUN_ELEVATION").InnerText;
            }
        }

        /// <summary>
        /// Get the epsg code for the spatial reference of the dataset.
        /// </summary>
        public string SrsCode
        {
            get
            {
                return myXmlDoc.SelectSingleNode("//HORIZONTAL_CS_CODE").InnerText;
            }
        }

        /// <summary>
        /// Get the Sensor Azimuth for the dataset.
        /// </summary>
        public string SensorAzimuth
        {
            get
            {
                XmlNodeList qualityAssessments = myXmlDoc.SelectNodes("//Quality_Assessment");
                XmlNodeList qualityPars = qualityAssessments[1].SelectNodes("Quality_Parameter");
                for (int i = 0; i < qualityPars.Count; ++i)
                {
                    if (qualityPars[i].SelectSingleNode("QUALITY_PARAMETER_CODE").InnerText.Contains("SENSOR_AZIMUTH"))
                        return qualityPars[i].SelectSingleNode("QUALITY_PARAMETER_VALUE").InnerText;
                }
                return "";
            }
        }
    }
}