/// <summary>
        /// Create an Erdas image file given specs
        /// </summary>
        public Image(string filename,
                     Dimensions dimensions,
                     int bandCount,
                     System.TypeCode bandType,
                     IMetadata metadata)
        {
            // if filename does not end in .gis or .lan throw exception
            string extension = Path.GetExtension(filename).ToLower();
            if (!(extension.Equals(".gis")) && !(extension.Equals(".lan")))
                throw new ApplicationException("Erdas image must have either GIS or LAN as extension");
                
            // if dimensions are messed up throw exception
            if ((dimensions.Rows < 1) || (dimensions.Columns < 1))
                throw new ApplicationException("Erdas image given invalid dimensions");
                
            // if bandCount messed up throw exception
            if ((bandCount < 1) || (bandCount > 0xffff))
                throw new ApplicationException("Erdas image given invalid band count");
            
            // more bandCount checking
            if (extension.Equals(".gis"))
            {
                if (bandCount > 1)
                    throw new ApplicationException("Erdas GIS files cannot support multiband images");
            }
                
            this.imageHeader =
                new ImageHeader(dimensions, bandType, bandCount, metadata);

            this.imageHeader.Write(filename);            
        }
 private Metadata         metadata;    // the metadata assoc w/ raster
 
 /// <summary>
 /// No arg constructor
 /// </summary>
 /// <remark>
 /// Used before calling Read()
 /// </remark>
 public ImageHeader()
 {
     this.dimensions = new Dimensions(0,0);
     this.bandType = System.TypeCode.Byte;
     this.bandSize = 0;
     this.bandCount = 0;
     this.metadata = new Metadata();
 }
 /// <summary>
 /// Open a writer on a new file
 /// </summary>
 public WritableImage(string filename,
                      Dimensions dimensions,
                      int bandCount,
                      System.TypeCode bandType,
                      IMetadata metadata)
   : base(filename, dimensions, bandCount, bandType, metadata)
 {
     this.pixelsWritten = 0;
     
     // open file for writing
     this.file = new FileStream(filename,FileMode.Open);
     this.fileWriter = new BinaryWriter(this.file);
    
 }
 /// <summary>
 /// Fully specified constructor - used before calling Write()
 /// </summary>
 /// <remark>
 /// Usually used before calling Write() but could call NoArg constructor,
 /// Read(), and then Write() if copying images
 /// </remark>
 public ImageHeader(Dimensions dimensions, System.TypeCode bandType,
                         int bandCount, IMetadata metadata)
 {
     this.dimensions = dimensions;
     this.bandType   = bandType;
     this.bandCount  = bandCount;
     this.metadata   = metadata as Metadata;
     if (bandType == System.TypeCode.Byte)
         this.bandSize   = 1;
     else if (bandType == System.TypeCode.UInt16)
         this.bandSize   = 2;
     else
         throw new ApplicationException("ImageHeader: bandType must either be Byte or UInt16");
 }
 private void TryCtor(string filename,
                      Dimensions dimensions,
                      int bandCount,
                      System.TypeCode bandType,
                      IMetadata metadata)
 {
     try {
         Image image = new Image(filename, dimensions,
                                  bandCount, bandType,
                                  metadata);
     }
     catch (System.Exception exc) {
         Data.Output.WriteLine(exc.Message);
         throw;
     }
 }
        /// <summary>
        /// Read the Erdas Image Header from a file given filename
        /// </summary>
        /// <remark>
        /// Uses variable definitions straight from Erdas spec - ipack, nbands,
        /// irows, icols, xstart, ystart, maptyp, nclass, iautyp, acre, xmap,
        /// ymap, xcell, ycell
        /// </remark>
        public void Read(string filename)
        {
            // init members as needed
            this.metadata = new Metadata();
            
            // prepare to read header
            FileStream file = null;
            BinaryReader fileReader = null;
            System.UInt16 ipack = 0;
            System.UInt16 nbands = 0;
            System.UInt32 irows = 0;
            System.UInt32 icols = 0;

            try
            {
                // open file
                file = new FileStream(filename,FileMode.Open);
                fileReader = new BinaryReader(file);

                // Read Header

                // if not start with "HEAD74" throw exception
                byte[] sentinel = fileReader.ReadBytes(6);
                if ((sentinel[0] != (byte)'H') ||
                    (sentinel[1] != (byte)'E') ||
                    (sentinel[2] != (byte)'A') ||
                    (sentinel[3] != (byte)'D') ||
                    (sentinel[4] != (byte)'7') ||
                    (sentinel[5] != (byte)'4'))
                    throw new ApplicationException(filename+" is not an ERDAS 7.4 compatible image file");

                // packing
                ipack = fileReader.ReadUInt16();

                // nbands
                nbands = fileReader.ReadUInt16();

                // unused
                byte[] unused = fileReader.ReadBytes(6);

                // icols
                icols = fileReader.ReadUInt32();

                // irows
                irows = fileReader.ReadUInt32();

                // xstart
                System.Int32 xstart = fileReader.ReadInt32();
                this.metadata[MetadataIds.RASTER_ULX] = xstart;

                // ystart
                System.Int32 ystart = fileReader.ReadInt32();
                this.metadata[MetadataIds.RASTER_ULY] = ystart;

                // unused
                unused = fileReader.ReadBytes(56);

                // maptyp
                System.UInt16 maptyp = fileReader.ReadUInt16();
                string projection = Projections.find(maptyp);
                if (projection != null)
                    this.metadata[MetadataIds.PROJECTION] = projection;
                if (maptyp == 0)
                    this.metadata[MetadataIds.SCALE_UNITS] = "degrees";
                else if (maptyp == 2)
                    this.metadata[MetadataIds.SCALE_UNITS] = "feet";
                else
                    this.metadata[MetadataIds.SCALE_UNITS] = "meters";

                // nclass : calc if needed but never has been in past
                System.UInt16 nclass = fileReader.ReadUInt16();

                // unused
                unused = fileReader.ReadBytes(14);

                // iautyp
                System.UInt16 iautyp = fileReader.ReadUInt16();

                // acre
                System.Single acre = fileReader.ReadSingle();

                // xmap
                System.Single xmap = fileReader.ReadSingle();
                this.metadata[MetadataIds.WORLD_ULX] = xmap;

                // ymap
                System.Single ymap = fileReader.ReadSingle();
                this.metadata[MetadataIds.WORLD_ULY] = ymap;

                // xcell
                System.Single xcell = fileReader.ReadSingle();
                this.metadata[MetadataIds.X_SCALE] = xcell;

                // ycell
                System.Single ycell = fileReader.ReadSingle();
                this.metadata[MetadataIds.Y_SCALE] = ycell;
            }
            catch
            {
                throw;
            }
            finally
            {
                if (fileReader != null)
                    fileReader.Close();
                    // the prev line automatically closes file also
                else if (file != null)
                    file.Close();
            }
            
            // now set instance vars
            // metadata already set by above code
            this.dimensions = new Dimensions((int)irows,(int)icols);
            this.bandCount = nbands;
            if (ipack == 0)
            {
                this.bandType = System.TypeCode.Byte;
                this.bandSize = 1;
            }
            else if (ipack == 2)
            {
                this.bandType = System.TypeCode.UInt16;
                this.bandSize = 2;
            }
            else
                throw new ApplicationException("ImageHeader: Only 8 and 16 bit bands are supported");
        }
        //---------------------------------------------------------------------

        /// <summary>
        /// Runs a model scenario.
        /// </summary>
        public static void Run(string scenarioPath)
        {
            //  Initialize plug-ins manager with the default plug-ins
            //	database in the folder where application resides.
            PlugIns.Manager.Initialize(PlugIns.Database.DefaultPath);

            IScenario scenario = LoadScenario(scenarioPath);

            cellLength = 29.0f;              // 29m hard-wired until metadata implemented in raster driver

            LoadSpecies(scenario.Species);
            LoadEcoregions(scenario.Ecoregions);

            Log.Info("Initializing landscape from ecoregions map \"{0}\" ...", scenario.EcoregionsMap);
            Ecoregions.Map ecoregionsMap = new Ecoregions.Map(scenario.EcoregionsMap,
                                                              Model.Ecoregions);
            using (Landscape.IInputGrid <bool> grid = ecoregionsMap.OpenAsInputGrid()) {
                landscape = new Landscape.Landscape(grid);
            }
            landscapeMapDims = new Raster.Dimensions((int)landscape.Rows,
                                                     (int)landscape.Columns);
            SiteVars.Initialize(ecoregionsMap);

            //  Load and initialize plug-ins.

            Log.Info("Loading {0} plug-in ...", scenario.Succession.Info.Name);
            succession = PlugIns.Manager.Load <ISuccession>(scenario.Succession.Info);
            succession.Initialize(scenario.Succession.InitFile);
            succession.InitializeSites(scenario.InitialCommunities,
                                       scenario.InitialCommunitiesMap);

            IDisturbance[] disturbancePlugIns = LoadPlugIns <IDisturbance>(scenario.Disturbances);
            IOutput[]      outputPlugIns      = LoadPlugIns <IOutput>(scenario.Outputs);

            //  Run those output plug-ins whose next time to run is 0.
            foreach (IOutput outPlugIn in GetPlugInsToRun <IOutput>(outputPlugIns, 0))
            {
                outPlugIn.Run(0);
            }

            //******************// for Rob
            //  Main time loop  //
            //******************//
            // currentTime (years)
            for (int currentTime = 1; currentTime <= scenario.Duration; ++currentTime)
            {
                List <IDisturbance> distPlugInsToRun;
                distPlugInsToRun = GetPlugInsToRun <IDisturbance>(disturbancePlugIns, currentTime);
                bool isDistTimestep = distPlugInsToRun.Count > 0;

                List <IOutput> outPlugInsToRun;
                outPlugInsToRun = GetPlugInsToRun <IOutput>(outputPlugIns, currentTime);
                bool isOutTimestep = outPlugInsToRun.Count > 0;

                bool isSuccTimestep = succession.NextTimeToRun == currentTime;

                //  If not a succession timestep, a disturance timestep or
                //  an output timestep, then go to the next timestep.
                if (!(isSuccTimestep || isDistTimestep || isOutTimestep))
                {
                    continue;
                }

                Log.Info("Current time: {0}", currentTime);

                if (isDistTimestep)
                {
                    if (scenario.DisturbancesRandomOrder)
                    {
                        distPlugInsToRun = Shuffle(distPlugInsToRun);
                    }
                    foreach (IDisturbance distPlugIn in distPlugInsToRun)
                    {
                        distPlugIn.Run(currentTime);
                    }
                }

                if (isSuccTimestep || isDistTimestep)
                {
                    IEnumerable <ActiveSite> sites;
                    if (isSuccTimestep)
                    {
                        sites = Model.Landscape.ActiveSites;
                    }
                    else
                    {
                        sites = DisturbedSites();
                    }
                    succession.AgeCohorts(sites, currentTime);
                    succession.ComputeShade(sites);
                    succession.ReproducePlants(sites);
                }

                //  Run output plug-ins.
                foreach (IOutput outPlugIn in outPlugInsToRun)
                {
                    outPlugIn.Run(currentTime);
                }

                if (!isSuccTimestep)
                {
                    SiteVars.Disturbed.ActiveSiteValues = false;
                }
            }              // main time loop
        }
        RWFlag           mode;        // file open mode: Read or Write

        /// <summary>
        /// Create a file given specs        
        /// </summary>
        public ErdasImageFile(string filename,
                              Dimensions dimensions,
                              int bandCount,
                              System.TypeCode bandType,
                              IMetadata metadata)
        {
            // set instance variables
            this.open        = false;
            this.mode        = RWFlag.Write;
            this.dimensions  = dimensions;
            this.bandType    = bandType;
            this.bandCount   = bandCount;
            this.currPixel   = 0;
            this.totalPixels = dimensions.Rows*dimensions.Columns;
            this.metadata    = metadata;
            
            // if filename does not end in .gis or .lan throw exception
            string extension = Path.GetExtension(filename).ToLower();
            if (!(extension.Equals(".gis")) && !(extension.Equals(".lan")))
                throw new System.ApplicationException("Erdas file must have either GIS or LAN as extension");
                
            // if dimensions are messed up throw exception
            if ((dimensions.Rows < 1) || (dimensions.Columns < 1))
                throw new System.ApplicationException("Erdas file given invalid dimensions");
                
            // if bandCount messed up throw exception
            if ((bandCount < 1) || (bandCount > 0xffff))
                throw new System.ApplicationException("Erdas file given invalid band count");
            
            // more bandCount checking
            if (extension.Equals(".gis"))
            {
                if (bandCount > 1)
                    throw new System.ApplicationException("Erdas GIS files cannot support multiband images");
                if (bandType != System.TypeCode.Byte)
                    throw new System.ApplicationException("Erdas GIS files only suupport byte for bandtype");
            }
                
            // if bandType not System.Byte or System.UInt16 throw exception
            if (bandType == System.TypeCode.Byte)
                this.bandSize = 1;
            else if (bandType == System.TypeCode.UInt16)
                this.bandSize = 2;
            else
                throw new System.ApplicationException("Erdas file given unsupported band type");
             
            // open file for writing
            this.file = new FileStream(filename,FileMode.OpenOrCreate);
            this.fileWriter = new BinaryWriter(this.file);
            this.open = true;
            
            // write header (using metadata whenever possible)
            
            try
            {

                // sentinel
                byte[] sentinel = new byte[6];
                sentinel[0] = (byte) 'H';
                sentinel[1] = (byte) 'E';
                sentinel[2] = (byte) 'A';
                sentinel[3] = (byte) 'D';
                sentinel[4] = (byte) '7';
                sentinel[5] = (byte) '4';
                this.fileWriter.Write(sentinel);

                // packing
                System.UInt16 ipack;
                if (bandType == System.TypeCode.Byte)
                    ipack = 0;
                else
                    ipack = 2;
                this.fileWriter.Write(ipack);

                // nbands
                System.UInt16 nbands = (System.UInt16)bandCount;
                this.fileWriter.Write(nbands);

                // unused
                for (int i = 0; i < 6; i++)
                    this.fileWriter.Write((byte)0);

                // icols
                System.UInt32 icols = (System.UInt32)dimensions.Columns;
                this.fileWriter.Write(icols);

                // irows
                System.UInt32 irows = (System.UInt32)dimensions.Rows;
                this.fileWriter.Write(irows);

                // xstart
                System.Int32 xstart = 0;
                if ((metadata != null) &&
                    (metadata.TryGetValue<System.Int32>(RASTER_ULX,ref xstart)))
                    {
                    }
                this.fileWriter.Write(xstart);

                // ystart
                System.Int32 ystart = 0;
                if ((metadata != null) &&
                    (metadata.TryGetValue<System.Int32>(RASTER_ULY,ref ystart)))
                {
                }
                this.fileWriter.Write(ystart);

                // unused
                for (int i = 0; i < 56; i++)
                    this.fileWriter.Write((byte)0);

                // maptyp
                System.UInt16 maptyp = 99;  // 99 means NONE
                string projection = null;
                if ((metadata != null) &&
                    (metadata.TryGetValue<string>(PROJECTION,ref projection)))
                {
                    int projNum = Projections.find(projection);
                    if (projNum != -1)
                        maptyp = (System.UInt16)projNum;
                }
                this.fileWriter.Write(maptyp);

                // nclass : calc if needed but never has been in past
                System.UInt16 nclass = 0;
                this.fileWriter.Write(nclass);

                // unused
                for (int i = 0; i < 14; i++)
                    this.fileWriter.Write((byte)0);

                // iautyp : first need xcell and ycell and then acre
                System.Single xcell = 0;
                if ((metadata != null) &&
                    (metadata.TryGetValue<System.Single>(X_SCALE,ref xcell)))
                {
                }
                if (maptyp == 99)
                    xcell = 0;
                System.Single ycell = 0;
                if ((metadata != null) &&
                    (metadata.TryGetValue<System.Single>(Y_SCALE,ref ycell)))
                {
                }
                if (maptyp == 99)
                    ycell = 0;
                System.UInt16 iautyp = 0;
                System.Single acre = 0;
                switch (maptyp)  // iautyp depends upon maptyp indirectly
                {
                    case 0: // Lat/Long -> dist unit == degrees
                        iautyp = 0;  // default to no area unit
                        break;
                    case 2: // State Plane ->  dist unit == feet
                        iautyp = 1;  // default to acres
                        acre = xcell * ycell;
                        // acre = sq.feet at this pt
                        //   so now convert to acres
                        acre = (float) ((double)acre * 0.0000229568411386593);
                        break;
                    default: //  dist unit == meters
                        iautyp = 2;  // default to hectares
                        acre = xcell * ycell;
                        // acre = sq.meters at this pt
                        //   so now convert to hectares
                        acre *= 0.0001f;
                        break;
                }
                this.fileWriter.Write(iautyp);

                // acre
                this.fileWriter.Write(acre);

                // xmap
                System.Single xmap = 0;
                if ((metadata != null) &&
                    (metadata.TryGetValue<System.Single>(WORLD_ULX,ref xmap)))
                {
                }
                this.fileWriter.Write(xmap);

                // ymap
                System.Single ymap = 0;
                if ((metadata != null) &&
                    (metadata.TryGetValue<System.Single>(WORLD_ULY,ref ymap)))
                {
                }
                this.fileWriter.Write(ymap);

                // xcell
                this.fileWriter.Write(xcell);

                // ycell
                this.fileWriter.Write(ycell);

                // now create pixel data as zeroes for now
                // many nested for loops avoids index calc overflows
                for (int row = 0; row < dimensions.Rows; row++)
                    for (int bandNum = 0; bandNum < this.bandCount; bandNum++)
                        for (int col = 0; col < dimensions.Columns; col++)
                            for (int byteNum = 0; byteNum < this.bandSize; byteNum++)
                                this.fileWriter.Write((byte)0);
            }
            catch (System.Exception)
            {
                Close();
                throw;
            }
        }
        /// <summary>
        /// Open an existing file
        /// </summary>
        public ErdasImageFile(string filename, RWFlag mode)
        {
            this.open = false;
            this.mode = mode;
            
            // if filename does not end in .gis or .lan throw exception
            string extension = Path.GetExtension(filename).ToLower();
            if (!(extension.Equals(".gis")) && !(extension.Equals(".lan")))
                throw new System.ApplicationException("Erdas file must have either GIS or LAN as extension");
                
            // open file
            this.file = new FileStream(filename,FileMode.Open);
            this.fileReader = new BinaryReader(this.file);
            this.open = true;

            try
            {
                // prepare to build metadata while reading
                Metadata metadata = new Metadata();

                // Read Header

                // if not start with "HEAD74" throw exception
                byte[] sentinel = fileReader.ReadBytes(6);
                if ((sentinel[0] != (byte)'H') ||
                    (sentinel[1] != (byte)'E') ||
                    (sentinel[2] != (byte)'A') ||
                    (sentinel[3] != (byte)'D') ||
                    (sentinel[4] != (byte)'7') ||
                    (sentinel[5] != (byte)'4'))
                    throw new System.ApplicationException(filename+" is not an ERDAS 7.4 compatible image file");

                // packing
                System.UInt16 ipack = this.fileReader.ReadUInt16();
                if ((ipack != 0) && (ipack != 2))
                    throw new System.ApplicationException("Only 8 and 16 bit bands are supported by Erdas reader");

                // nbands
                System.UInt16 nbands = this.fileReader.ReadUInt16();

                // unused
                byte[] unused = this.fileReader.ReadBytes(6);

                // icols
                System.UInt32 icols = this.fileReader.ReadUInt32();

                // irows
                System.UInt32 irows = this.fileReader.ReadUInt32();

                // xstart
                System.Int32 xstart = this.fileReader.ReadInt32();
                metadata[RASTER_ULX] = xstart;

                // ystart
                System.Int32 ystart = this.fileReader.ReadInt32();
                metadata[RASTER_ULY] = ystart;

                // unused
                unused = this.fileReader.ReadBytes(56);

                // maptyp
                System.UInt16 maptyp = this.fileReader.ReadUInt16();
                string projection = Projections.find(maptyp);
                if (projection != null)
                    metadata[PROJECTION] = projection;
                if (maptyp == 0)
                    metadata[SCALE_UNITS] = "degrees";
                else if (maptyp == 2)
                    metadata[SCALE_UNITS] = "feet";
                else
                    metadata[SCALE_UNITS] = "meters";

                // nclass : calc if needed but never has been in past
                System.UInt16 nclass = this.fileReader.ReadUInt16();

                // unused
                unused = this.fileReader.ReadBytes(14);

                // iautyp
                System.UInt16 iautyp = this.fileReader.ReadUInt16();

                // acre
                System.Single acre = this.fileReader.ReadSingle();

                // xmap
                System.Single xmap = this.fileReader.ReadSingle();
                metadata[WORLD_ULX] = xmap;

                // ymap
                System.Single ymap = this.fileReader.ReadSingle();
                metadata[WORLD_ULY] = ymap;

                // xcell
                System.Single xcell = this.fileReader.ReadSingle();
                metadata[X_SCALE] = xcell;

                // ycell
                System.Single ycell = this.fileReader.ReadSingle();
                metadata[Y_SCALE] = ycell;

                // construct instance variables based upon hedaer info
                this.dimensions  = new Dimensions((int)irows,(int)icols);
                if (ipack == 0)
                {
                    this.bandType    = System.TypeCode.Byte;
                    this.bandSize    = 1;
                }
                else  // ipack == 2 due to earlier screening
                {
                    this.bandType    = System.TypeCode.UInt16;
                    this.bandSize    = 2;
                }
                this.bandCount   = nbands;
                this.currPixel   = 0;
                this.totalPixels = (int)irows * (int)icols;
                this.metadata    = metadata;

                if (mode == RWFlag.Write)
                {
                    this.fileReader.Close();
                    this.fileReader = null;
                    // need to reopen stream - fileReader.Close() shuts it
                    this.file = new FileStream(filename,FileMode.Open);
                    this.fileWriter = new BinaryWriter(this.file);
                }
            }
            catch (System.Exception)
            {
                Close();
                throw;
            }
        }