GeoRasterRasterBand::GeoRasterRasterBand( GeoRasterDataset *poGDS,
                                          int nBand,
                                          int nLevel )
{
    poDS                = (GDALDataset*) poGDS;
    poGeoRaster         = poGDS->poGeoRaster;
    this->nBand         = nBand;
    this->eDataType     = OWGetDataType( poGeoRaster->pszCellDepth );
    poColorTable        = new GDALColorTable();
    poDefaultRAT        = NULL;
    pszVATName          = NULL;
    nRasterXSize        = poGeoRaster->nRasterColumns;
    nRasterYSize        = poGeoRaster->nRasterRows;
    nBlockXSize         = poGeoRaster->nColumnBlockSize;
    nBlockYSize         = poGeoRaster->nRowBlockSize;
    dfNoData            = 0.0;
    bValidStats         = false;
    nOverviewLevel      = nLevel;
    papoOverviews       = NULL;
    nOverviews          = 0;

    //  -----------------------------------------------------------------------
    //  Initialize overview list
    //  -----------------------------------------------------------------------

    if( nLevel == 0 && poGeoRaster->nPyramidMaxLevel > 0 )
    {
        nOverviews      = poGeoRaster->nPyramidMaxLevel;
        papoOverviews   = (GeoRasterRasterBand**) VSIMalloc(
                sizeof(GeoRasterRasterBand*) * nOverviews );
        for( int i = 0; i < nOverviews; i++ )
        {
          papoOverviews[i] = new GeoRasterRasterBand(
                (GeoRasterDataset*) poDS, nBand, i + 1 );
        }
    }

    //  -----------------------------------------------------------------------
    //  Initialize this band as an overview
    //  -----------------------------------------------------------------------

    if( nLevel )
    {
        double dfScale  = pow( (double) 2.0, (double) nLevel );

        nRasterXSize    = (int) floor( nRasterXSize / dfScale );
        nRasterYSize    = (int) floor( nRasterYSize / dfScale );

        if( nRasterXSize <= ( nBlockXSize / 2.0 ) &&
            nRasterYSize <= ( nBlockYSize / 2.0 ) )
        {
            nBlockXSize = nRasterXSize;
            nBlockYSize = nRasterYSize;
        }
    }
}
GeoRasterRasterBand::GeoRasterRasterBand( GeoRasterDataset *poGDS,
                                          int nBand,
                                          int nLevel )
{
    poDS                = (GDALDataset*) poGDS;
    poGeoRaster         = poGDS->poGeoRaster;
    this->nBand         = nBand;
    this->eDataType     = OWGetDataType( poGeoRaster->sCellDepth.c_str() );
    poColorTable        = new GDALColorTable();
    poDefaultRAT        = NULL;
    pszVATName          = NULL;
    nRasterXSize        = poGeoRaster->nRasterColumns;
    nRasterYSize        = poGeoRaster->nRasterRows;
    nBlockXSize         = poGeoRaster->nColumnBlockSize;
    nBlockYSize         = poGeoRaster->nRowBlockSize;
    dfNoData            = 0.0;
    bValidStats         = false;
    nOverviewLevel      = nLevel;
    papoOverviews       = NULL;
    nOverviewCount      = 0;
    pahNoDataArray      = NULL;
    nNoDataArraySz      = 0;
    bHasNoDataArray     = false;
    
    //  -----------------------------------------------------------------------
    //  Initialize overview list
    //  -----------------------------------------------------------------------

    if( nLevel == 0 && poGeoRaster->nPyramidMaxLevel > 0 )
    {
        nOverviewCount      = poGeoRaster->nPyramidMaxLevel;
        papoOverviews   = (GeoRasterRasterBand**) VSIMalloc(
                sizeof(GeoRasterRasterBand*) * nOverviewCount );
        for( int i = 0; i < nOverviewCount; i++ )
        {
          papoOverviews[i] = new GeoRasterRasterBand(
                (GeoRasterDataset*) poDS, nBand, i + 1 );
        }
    }

    //  -----------------------------------------------------------------------
    //  Initialize this band as an overview
    //  -----------------------------------------------------------------------

    if( nLevel )
    {
        double dfScale  = pow( (double) 2.0, (double) nLevel );

        nRasterXSize    = (int) floor( nRasterXSize / dfScale );
        nRasterYSize    = (int) floor( nRasterYSize / dfScale );

        if( nRasterXSize <= ( nBlockXSize / 2.0 ) &&
            nRasterYSize <= ( nBlockYSize / 2.0 ) )
        {
            nBlockXSize = nRasterXSize;
            nBlockYSize = nRasterYSize;
        }
    }

    //  -----------------------------------------------------------------------
    //  Load NoData values and value ranges for this band (layer)
    //  -----------------------------------------------------------------------

    if( ( (GeoRasterDataset*) poDS)->bApplyNoDataArray )
    {
        CPLList* psList = NULL;
        int nLayerCount = 0;
        int nObjCount = 0;

        /*
         *  Count the number of NoData values and value ranges
         */

        for( psList = poGeoRaster->psNoDataList; psList ; psList = psList->psNext )
        {
            hNoDataItem* phItem = (hNoDataItem*) psList->pData;

            if( phItem->nBand == nBand )
            {
                nLayerCount++;
            }

            if( phItem->nBand == 0 )
            {
                nObjCount++;
            }

            if( phItem->nBand > nBand )
            {
                break;
            }
        }

        /*
         * Join the object nodata values to layer NoData values
         */

        nNoDataArraySz = nLayerCount + nObjCount;

        pahNoDataArray = (hNoDataItem*) VSIMalloc2( sizeof(hNoDataItem),
                nNoDataArraySz );

        int i = 0;
        bool bFirst = true;

        for( psList = poGeoRaster->psNoDataList ; psList && i < nNoDataArraySz;
             psList = psList->psNext )
        {
            hNoDataItem* phItem = (hNoDataItem*) psList->pData;

            if( phItem->nBand == nBand || phItem->nBand == 0 )
            {
                pahNoDataArray[i].nBand = nBand;
                pahNoDataArray[i].dfLower = phItem->dfLower;
                pahNoDataArray[i].dfUpper = phItem->dfUpper;
                i++;

                if( bFirst )
                {
                    bFirst = false;

                    /*
                     * Use the first value to assigned pixel values
                     * on method ApplyNoDataArray()
                     */
                    
                    dfNoData = phItem->dfLower;
                }
            }
        }

        bHasNoDataArray = nNoDataArraySz > 0;
    }
}