/******************************************************************************
 *
 * Purpose:  Implementation of the CPCIDSKEphemerisSegment class.
 * 
 ******************************************************************************
 * Copyright (c) 2009
 * PCI Geomatics, 50 West Wilmot Street, Richmond Hill, Ont, Canada
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 ****************************************************************************/

#include "segment/cpcidsksegment.h"
#include "core/pcidsk_utils.h"
#include "segment/cpcidskephemerissegment.h"
#include "pcidsk_exception.h"
#include "core/pcidsk_utils.h"

#include <vector>
#include <string>
#include <cassert>
#include <cstring>

using namespace PCIDSK;

namespace
{
    /** 
     * Function to get the minimum value of two values.
     * 
     * @param a The first value.
     * @param b The second value.
     * 
     * @return The minimum value of the two specified values.
     */
    int MinFunction(int a,int b) 
    {
        return (a<b)?a:b;
    }
}

/**
 * Ephemeris Segment constructor
 * @param file the PCIDSK file
 * @param segment the segment index
 * @param segment_pointer the segement pointer
 * @param bLoad true to load the segment, else false (default true)
 */
CPCIDSKEphemerisSegment::CPCIDSKEphemerisSegment(PCIDSKFile *file, 
                                                   int segment,
                                                   const char *segment_pointer,
                                                   bool bLoad) :
    CPCIDSKSegment(file, segment, segment_pointer),
    loaded_(false),mbModified(false)
{
    mpoEphemeris = NULL;
    if(bLoad)
    {
        Load();
    }
}


CPCIDSKEphemerisSegment::~CPCIDSKEphemerisSegment()
{
    delete mpoEphemeris;
}

/**
 * Load the contents of the segment
 */
void CPCIDSKEphemerisSegment::Load()
{
    // Check if we've already loaded the segment into memory
    if (loaded_) {
        return;
    }

    seg_data.SetSize((int)data_size - 1024);
    
    ReadFromFile(seg_data.buffer, 0, data_size - 1024);

    // We test the name of the binary segment before starting to read 
    // the buffer.
    if (std::strncmp(seg_data.buffer, "ORBIT   ", 8)) 
    {
        seg_data.Put("ORBIT   ",0,8);
        loaded_ = true;
        return ;
    }
    
    mpoEphemeris = BinaryToEphemeris(0);

    // We've now loaded the structure up with data. Mark it as being loaded 
    // properly.
    loaded_ = true;
    
}

/**
 * Write the segment on disk
 */
void CPCIDSKEphemerisSegment::Write(void)
{
    //We are not writing if nothing was loaded.
    if (!loaded_) {
        return;
    }

    seg_data.Put("ORBIT   ",0,8);

    EphemerisToBinary( mpoEphemeris, 0);
    WriteToFile(seg_data.buffer,0,seg_data.buffer_size);

    mbModified = false;
}

/**
 * Synchronize the segement, if it was modified then
 * write it into disk.
 */
void CPCIDSKEphemerisSegment::Synchronize()
{
    if(mbModified)
    {
        this->Write();
    }
}

/************************************************************************/
/*			ConvertDeg()					*/
/************************************************************************/
/**									
 * if mode is 0, convert angle from 0 to 360 to 0 to 180 and 0 to -180 
 * if mode is 1, convert angle from 0 to 180 and 0 to -180 to 0 to 360 
 *
 * @param degree the degree
 * @param mode  the mode
 */
double CPCIDSKEphemerisSegment::ConvertDeg(double degree, int mode)
{
    double result;

    if (mode == 0)
    {
/* -------------------------------------------------------------------- */
/*	degree is in range of 0 to 360					*/
/* -------------------------------------------------------------------- */
	if (degree > 180)
	    result = degree - 360;
	else
	    result = degree;
    }
    else
    {
/* -------------------------------------------------------------------- */
/*	degree is in range of 0 to 180 and 0 to -180			*/
/* -------------------------------------------------------------------- */
	if (degree < 0)
	    result = 360 + degree;
	else
	    result = degree;
	
    }
    return (result);
}

/************************************************************************/
/*		      ReadAvhrrEphemerisSegment()                       */
/************************************************************************/
/**                                                                      
 *  Read the contents of blocks 9, 11, and onwards from the orbit	
 *  segment into the EphemerisSeg_t structure.	
 * @param nStartBlock where to start to read in the buffer
 * @param psEphSegRec the structure to populate with information.
 */   
void 
CPCIDSKEphemerisSegment::ReadAvhrrEphemerisSegment(int nStartBlock,
                                         EphemerisSeg_t *psEphSegRec)
{
    int  nBlock = 0, nLine = 0;
    int nPos = 0;
    AvhrrSeg_t *as = NULL;

    int nDataLength = seg_data.buffer_size;
/* -------------------------------------------------------------------- */
/*  Allocate the AVHRR segment portion of EphemerisSeg_t.		*/
/* -------------------------------------------------------------------- */
    psEphSegRec->AvhrrSeg = new AvhrrSeg_t();
    as = psEphSegRec->AvhrrSeg;

/* -------------------------------------------------------------------- */
/*  Read in the Nineth Block which contains general info + ephemeris	*/
/*  info as well.							*/
/* -------------------------------------------------------------------- */
    nPos = nStartBlock + 8*512;
    
    as->szImageFormat = seg_data.Get(nPos, 16);
    as->nImageXSize = seg_data.GetInt(nPos+16, 16);
    as->nImageYSize = seg_data.GetInt(nPos+32, 16);

    
    if ( std::strncmp(seg_data.Get(nPos+48,9), "ASCENDING", 9)==0 )
        as->bIsAscending = true;
    else
        as->bIsAscending = false;
    if ( std::strncmp(seg_data.Get(nPos+64,7), "ROTATED", 7)==0 )
        as->bIsImageRotated = true;
    else
        as->bIsImageRotated = false;

    as->szOrbitNumber = seg_data.Get(nPos+80, 16);
    as->szAscendDescendNodeFlag = seg_data.Get(nPos+96,16);
    as->szEpochYearAndDay = seg_data.Get(nPos+112,16);
    as->szEpochTimeWithinDay = seg_data.Get(nPos+128,16);
    as->szTimeDiffStationSatelliteMsec = seg_data.Get(nPos+144,16);
    as->szActualSensorScanRate = seg_data.Get(nPos+160,16);
    as->szIdentOfOrbitInfoSource = seg_data.Get(nPos+176,16);
    as->szInternationalDesignator = seg_data.Get(nPos+192,16);
    as->szOrbitNumAtEpoch = seg_data.Get(nPos+208,16);
    as->szJulianDayAscendNode = seg_data.Get(nPos+224,16);
    as->szEpochYear = seg_data.Get(nPos+240,16);
    as->szEpochMonth = seg_data.Get(nPos+256,16);
    as->szEpochDay = seg_data.Get(nPos+272,16);
    as->szEpochHour = seg_data.Get(nPos+288,16);
    as->szEpochMinute = seg_data.Get(nPos+304,16);
    as->szEpochSecond = seg_data.Get(nPos+320,16);
    as->szPointOfAriesDegrees = seg_data.Get(nPos+336,16);
    as->szAnomalisticPeriod = seg_data.Get(nPos+352,16);
    as->szNodalPeriod = seg_data.Get(nPos+368,16);
    as->szEccentricity = seg_data.Get(nPos+384,16);
    as->szArgumentOfPerigee = seg_data.Get(nPos+400,16);
    as->szRAAN = seg_data.Get(nPos+416,16);
    as->szInclination = seg_data.Get(nPos+432,16);
    as->szMeanAnomaly = seg_data.Get(nPos+448,16);
    as->szSemiMajorAxis = seg_data.Get(nPos+464,16);
                                                                      
/* -------------------------------------------------------------------- */
/*  Skip the 10th block which is reserved for future use.		*/
/* -------------------------------------------------------------------- */

/* -------------------------------------------------------------------- */
/*  Read in the 11th block, which contains indexing info.               */
/* -------------------------------------------------------------------- */
    nPos = nStartBlock + 512*10;
    
    as->nRecordSize             = seg_data.GetInt(nPos,    16);
    as->nBlockSize              = seg_data.GetInt(nPos+16, 16);
    as->nNumRecordsPerBlock     = seg_data.GetInt(nPos+32, 16);
    as->nNumBlocks              = seg_data.GetInt(nPos+48, 16);
    as->nNumScanlineRecords     = seg_data.GetInt(nPos+64, 16);
    
/* -------------------------------------------------------------------- */
/*  Allocate the scanline records.                                      */
/* -------------------------------------------------------------------- */
    if ( as->nNumScanlineRecords == 0 )
        return;

/* -------------------------------------------------------------------- */
/*  Now read the 12th block and onward.                                 */
/* -------------------------------------------------------------------- */
    nBlock = 12;

    if ( as->nNumRecordsPerBlock == 0 )
	return;

    for(nLine = 0; nLine < as->nNumScanlineRecords;
                   nLine += as->nNumRecordsPerBlock)
    {
        int nNumRecords = MinFunction(as->nNumRecordsPerBlock,
                                      as->nNumScanlineRecords - nLine);
        nPos = nStartBlock + 512*(nBlock-1);
	if( nDataLength < 512*nBlock )
	{
	    break;
	}
     
        for(int i = 0; i < nNumRecords; ++i)
        {
            AvhrrLine_t sLine;
            ReadAvhrrScanlineRecord(nPos+i*80, &sLine);
            as->Line.push_back(sLine);
        }

        ++nBlock;
    }
}

/************************************************************************/
/*		        ReadAvhrrScanlineRecord()                       */
/************************************************************************/
/**                                                                      
 *  Read from a byte buffer in order to set a scanline record.     
 * @param pbyBuf the buffer that contains the record to read.
 * @param psScanlineRecord the record to read.
 */
void 
CPCIDSKEphemerisSegment::ReadAvhrrScanlineRecord(int nPos,
                                           AvhrrLine_t *psScanlineRecord)
{
    int i;
    AvhrrLine_t *sr = psScanlineRecord;

    sr->nScanLineNum = ReadAvhrrInt32((unsigned char*)seg_data.Get(nPos,4));
    sr->nStartScanTimeGMTMsec = ReadAvhrrInt32((unsigned char*)seg_data.Get(nPos+4,4));

    for(i = 0; i < 10; ++i)
        sr->abyScanLineQuality[i] = seg_data.GetInt(nPos+8+i,1);

    for(i = 0; i < 5; ++i)
    {
        sr->aabyBadBandIndicators[i][0] = seg_data.GetInt(nPos+18+2*i,1);
        sr->aabyBadBandIndicators[i][1] = seg_data.GetInt(nPos+18+2*i+1,1);
    }

    for(i = 0; i < 8; ++i)
        sr->abySatelliteTimeCode[i] = seg_data.GetInt(nPos+28+i,1);

    for(i = 0; i < 3; ++i)
        sr->anTargetTempData[i] = ReadAvhrrInt32((unsigned char*)seg_data.Get(nPos+36+i*4,4));
    for(i = 0; i < 3; ++i)
        sr->anTargetScanData[i] = ReadAvhrrInt32((unsigned char*)seg_data.Get(nPos+48+i*4,4));
    for(i = 0; i < 5; ++i)
        sr->anSpaceScanData[i]  = ReadAvhrrInt32((unsigned char*)seg_data.Get(nPos+60+i*4,4));
}

/************************************************************************/
/*			   ReadAvhrrInt32()                             */
/************************************************************************/
/**                                                                      
 * Read an integer from a given buffer of at least 4 bytes. 
 * @param pbyBuf the buffer that contains the value.
 * @return the value
 */
int 
CPCIDSKEphemerisSegment::ReadAvhrrInt32(unsigned char* pbyBuf)
{
    int nValue = 0;
    unsigned char* b = pbyBuf;
    nValue = (int)((b[0]<<24) | (b[1]<<16) | (b[2]<<8) | b[3]);

    return( nValue );
}

/************************************************************************/
/*		      WriteAvhrrEphemerisSegment()                      */
/************************************************************************/
/**                                                                      
 *  Write the contents of blocks 9, 10, and onwards to the orbit	
 *  segment from fields in the EphemerisSeg_t structure.
 * @param nStartBlock where to start to write the information in the buffer
 * @param psEphSegRec the information to write.
 */
void 
CPCIDSKEphemerisSegment::WriteAvhrrEphemerisSegment(int nStartBlock,
                                           EphemerisSeg_t *psEphSegRec)
{
    int  nBlock = 0, nLine = 0;
    int nPos = 0;
/* -------------------------------------------------------------------- */
/*  Check that the AvhrrSeg is not NULL.				*/
/* -------------------------------------------------------------------- */
    AvhrrSeg_t *as = NULL;
    as = psEphSegRec->AvhrrSeg;

    if ( as == NULL)
    {
	throw PCIDSKException("The AvhrrSeg is NULL.");
    }

/* -------------------------------------------------------------------- */
/*      Realloc the data buffer large enough to hold all the AVHRR      */
/*      information, and zero it.                                       */
/* -------------------------------------------------------------------- */
    int nToAdd = 512 *
        (((as->nNumScanlineRecords + as->nNumRecordsPerBlock-1) /
                   as->nNumRecordsPerBlock)
        +4);
    seg_data.SetSize(seg_data.buffer_size + nToAdd);

    nPos = nStartBlock;
    memset(seg_data.buffer+nPos,' ',nToAdd);

/* -------------------------------------------------------------------- */
/*  Write the first avhrr Block.					*/
/* -------------------------------------------------------------------- */

    seg_data.Put(as->szImageFormat.c_str(),nPos,16);

    seg_data.Put(as->nImageXSize,nPos+16,16);
    seg_data.Put(as->nImageYSize,nPos+32,16);

    if ( as->bIsAscending )
        seg_data.Put("ASCENDING",nPos+48,9);
    else
        seg_data.Put("DESCENDING",nPos+48,10);

    if ( as->bIsImageRotated )
        seg_data.Put("ROTATED",nPos+64,7);
    else
        seg_data.Put("NOT ROTATED",nPos+64,11);
              
    seg_data.Put(as->szOrbitNumber.c_str(),nPos+80,16);
    seg_data.Put(as->szAscendDescendNodeFlag.c_str(),nPos+96,16,true);
    seg_data.Put(as->szEpochYearAndDay.c_str(),nPos+112,16,true);
    seg_data.Put(as->szEpochTimeWithinDay.c_str(),nPos+128,16,true);
    seg_data.Put(as->szTimeDiffStationSatelliteMsec.c_str(),nPos+144,16,true);
    seg_data.Put(as->szActualSensorScanRate.c_str(),nPos+160,16,true);
    seg_data.Put(as->szIdentOfOrbitInfoSource.c_str(),nPos+176,16,true);
    seg_data.Put(as->szInternationalDesignator.c_str(),nPos+192,16,true);
    seg_data.Put(as->szOrbitNumAtEpoch.c_str(),nPos+208,16,true);
    seg_data.Put(as->szJulianDayAscendNode.c_str(),nPos+224,16,true);
    seg_data.Put(as->szEpochYear.c_str(),nPos+240,16,true);
    seg_data.Put(as->szEpochMonth.c_str(),nPos+256,16,true);
    seg_data.Put(as->szEpochDay.c_str(),nPos+272,16,true);
    seg_data.Put(as->szEpochHour.c_str(),nPos+288,16,true);
    seg_data.Put(as->szEpochMinute.c_str(),nPos+304,16,true);
    seg_data.Put(as->szEpochSecond.c_str(),nPos+320,16,true);
    seg_data.Put(as->szPointOfAriesDegrees.c_str(),nPos+336,16,true);
    seg_data.Put(as->szAnomalisticPeriod.c_str(),nPos+352,16,true);
    seg_data.Put(as->szNodalPeriod.c_str(),nPos+368,16,true);
    seg_data.Put(as->szEccentricity.c_str(), nPos+384,16,true);
    seg_data.Put(as->szArgumentOfPerigee.c_str(),nPos+400,16,true);
    seg_data.Put(as->szRAAN.c_str(),nPos+416,16,true);
    seg_data.Put(as->szInclination.c_str(),nPos+432,16,true);
    seg_data.Put(as->szMeanAnomaly.c_str(),nPos+448,16,true);
    seg_data.Put(as->szSemiMajorAxis.c_str(),nPos+464,16,true);
   
/* -------------------------------------------------------------------- */
/*  second avhrr block is all zeros.					*/
/* -------------------------------------------------------------------- */

/* -------------------------------------------------------------------- */
/*  Write the 3rd avhrr Block.                                          */
/* -------------------------------------------------------------------- */
    nPos = nStartBlock + 512*2;
    
    seg_data.Put(as->nRecordSize,nPos,16);
    seg_data.Put(as->nBlockSize,nPos+16,16);
    seg_data.Put(as->nNumRecordsPerBlock,nPos+32,16);
    seg_data.Put(as->nNumBlocks,nPos+48,16);
    seg_data.Put(as->nNumScanlineRecords,nPos+64,16);

/* -------------------------------------------------------------------- */
/*  Write the fourth avhrr block onwards.                               */
/* -------------------------------------------------------------------- */
    if ( as->Line.size() == 0 )
	return;

    nBlock = 4;

    if ( as->nNumRecordsPerBlock == 0 )
	return;

    for(nLine = 0; nLine < as->nNumScanlineRecords;
                   nLine += as->nNumRecordsPerBlock)
    {
        int nNumRecords = MinFunction(as->nNumRecordsPerBlock,
                                      as->nNumScanlineRecords - nLine);
        nPos = nStartBlock + (nBlock-1) * 512;

        for(int i = 0; i < nNumRecords; ++i)
        {
            WriteAvhrrScanlineRecord(&(as->Line[nLine+i]), nPos + i*80);
        }

        ++nBlock;
    }
}

/************************************************************************/
/*  		   WriteAvhrrScanlineRecord()                           */
/************************************************************************/
/**                                                                      
 * Write a scanline record to a byte buffer.  
 * @param psScanlineRecord the record to write
 * @param pbyBuf the buffer to write.
 */
void 
CPCIDSKEphemerisSegment::WriteAvhrrScanlineRecord(
                                         AvhrrLine_t *psScanlineRecord,
                                         int nPos)
{
    int i;
    AvhrrLine_t *sr = psScanlineRecord;
    unsigned char* b = (unsigned char*)&(seg_data.buffer[nPos]);

    WriteAvhrrInt32(sr->nScanLineNum, b);
    WriteAvhrrInt32(sr->nStartScanTimeGMTMsec, b+4);

    for(i=0 ; i < 10 ; i++)
        seg_data.Put(sr->abyScanLineQuality[i],nPos+8+i,1);

    for(i = 0; i < 5; ++i)
    {
        seg_data.Put(sr->aabyBadBandIndicators[i][0],nPos+18+i*2,1);
        seg_data.Put(sr->aabyBadBandIndicators[i][1],nPos+18+i*2+1,1);
    }

    for(i=0 ; i < 8 ; i++)
        seg_data.Put(sr->abySatelliteTimeCode[i],nPos+28+i,1);

    for(i = 0; i < 3; ++i)
        WriteAvhrrInt32(sr->anTargetTempData[i], b+(36+i*4));
    for(i = 0; i < 3; ++i)
        WriteAvhrrInt32(sr->anTargetScanData[i], b+(48+i*4));
    for(i = 0; i < 5; ++i)
        WriteAvhrrInt32(sr->anSpaceScanData[i],  b+(60+i*4));

}
 
/************************************************************************/
/*			   WriteAvhrrInt32()                            */
/************************************************************************/
/**                                                                      
 * Write an integer into a given buffer of at least 4 bytes.            
 * @param nValue the value to write
 * @param pbyBuf the buffer to write into.
 */
void CPCIDSKEphemerisSegment::WriteAvhrrInt32(int nValue, 
                                              unsigned char* pbyBuf)
{
    pbyBuf[0] = ((nValue & 0xff000000) >> 24);
    pbyBuf[1] = ((nValue & 0x00ff0000) >> 16);
    pbyBuf[2] = ((nValue & 0x0000ff00) >> 8);
    pbyBuf[3] =  (nValue & 0x000000ff);
}


/************************************************************************/
/*                        BinaryToEphemeris()                           */
/************************************************************************/
/**
 * Read binary information from a binary buffer to create an 
 * EphemerisSeg_t structure. The caller is responsible to free the memory
 * of the returned structure with delete.
 *
 * @param nStartBlock where to start read the orbit info into the buffer.
 * @return the orbbit information 
 */
EphemerisSeg_t *
CPCIDSKEphemerisSegment::BinaryToEphemeris( int nStartBlock )

{
    EphemerisSeg_t *segment;
    int		i;
    int nPos = nStartBlock;

    segment = new EphemerisSeg_t();
    
/* -------------------------------------------------------------------- */
/*	Process first block.						*/
/* -------------------------------------------------------------------- */
    
    segment->SatelliteDesc = seg_data.Get(nPos+8,32);  
    segment->SceneID = seg_data.Get(nPos+40, 32);

/* -------------------------------------------------------------------- */
/*	Process the second block.					*/
/* -------------------------------------------------------------------- */
    nPos = nStartBlock + 512;

    segment->SatelliteSensor = seg_data.Get(nPos, 16);
    for (i=0; i<16; i++)
    {
        if (segment->SatelliteSensor[i] == ' ')
        {
            segment->SatelliteSensor = segment->SatelliteSensor.substr(0,i);
            break;
        }
    }

    segment->SensorNo = seg_data.Get(nPos+22, 2);
    segment->DateImageTaken = seg_data.Get(nPos+44, 22);

    if (seg_data.buffer[nPos+66] == 'Y' || 
        seg_data.buffer[nPos+66] == 'y')
        segment->SupSegExist = true;
    else
        segment->SupSegExist = false;
    segment->FieldOfView = seg_data.GetDouble(nPos+88, 22); 
    segment->ViewAngle = seg_data.GetDouble(nPos+110, 22);
    segment->NumColCentre = seg_data.GetDouble(nPos+132, 22);
    segment->RadialSpeed = seg_data.GetDouble(nPos+154, 22);
    segment->Eccentricity = seg_data.GetDouble(nPos+176, 22);
    segment->Height = seg_data.GetDouble(nPos+198, 22);
    segment->Inclination = seg_data.GetDouble(nPos+220, 22);
    segment->TimeInterval = seg_data.GetDouble(nPos+242, 22);
    segment->NumLineCentre = seg_data.GetDouble(nPos+264, 22);
    segment->LongCentre = seg_data.GetDouble(nPos+286, 22);
    segment->AngularSpd = seg_data.GetDouble(nPos+308, 22);		
    segment->AscNodeLong = seg_data.GetDouble(nPos+330, 22);
    segment->ArgPerigee = seg_data.GetDouble(nPos+352, 22);
    segment->LatCentre = seg_data.GetDouble(nPos+374, 22);
    segment->EarthSatelliteDist = seg_data.GetDouble(nPos+396, 22);
    segment->NominalPitch = seg_data.GetDouble(nPos+418, 22);
    segment->TimeAtCentre = seg_data.GetDouble(nPos+440, 22);
    segment->SatelliteArg = seg_data.GetDouble(nPos+462, 22);
    segment->bDescending = true;
    if (seg_data.buffer[nPos+484] == 'A')
        segment->bDescending = false;

/* -------------------------------------------------------------------- */
/*	Process the third block.					*/
/* -------------------------------------------------------------------- */
    nPos = nStartBlock + 2*512;

    segment->XCentre = seg_data.GetDouble(nPos, 22);
    segment->YCentre = seg_data.GetDouble(nPos+22, 22);
    segment->UtmXCentre = seg_data.GetDouble(nPos+44, 22);
    segment->UtmYCentre = seg_data.GetDouble(nPos+66, 22);
    segment->PixelRes = seg_data.GetDouble(nPos+88, 22);
    segment->LineRes = seg_data.GetDouble(nPos+110, 22);
    if (seg_data.buffer[nPos+132] == 'Y' || 
        seg_data.buffer[nPos+132] == 'y')
        segment->CornerAvail = true;
    else
        segment->CornerAvail = false;
    segment->MapUnit = seg_data.Get(nPos+133, 16);

    segment->XUL = seg_data.GetDouble(nPos+149, 22);
    segment->YUL = seg_data.GetDouble(nPos+171, 22);
    segment->XUR = seg_data.GetDouble(nPos+193, 22);
    segment->YUR = seg_data.GetDouble(nPos+215, 22);
    segment->XLR = seg_data.GetDouble(nPos+237, 22);
    segment->YLR = seg_data.GetDouble(nPos+259, 22);
    segment->XLL = seg_data.GetDouble(nPos+281, 22);
    segment->YLL = seg_data.GetDouble(nPos+303, 22);
    segment->UtmXUL = seg_data.GetDouble(nPos+325, 22);
    segment->UtmYUL = seg_data.GetDouble(nPos+347, 22);
    segment->UtmXUR = seg_data.GetDouble(nPos+369, 22);
    segment->UtmYUR = seg_data.GetDouble(nPos+391, 22);
    segment->UtmXLR = seg_data.GetDouble(nPos+413, 22);
    segment->UtmYLR = seg_data.GetDouble(nPos+435, 22);
    segment->UtmXLL = seg_data.GetDouble(nPos+457, 22);
    segment->UtmYLL = seg_data.GetDouble(nPos+479, 22);
    
/* -------------------------------------------------------------------- */
/*      Process the 4th block (Corner lat/long coordinates)             */
/* -------------------------------------------------------------------- */
    nPos = nStartBlock + 3*512;

    segment->LongCentreDeg = seg_data.GetDouble(nPos, 16);
    segment->LatCentreDeg = seg_data.GetDouble(nPos+16, 16);
    segment->LongUL =  seg_data.GetDouble(nPos+32, 16);
    segment->LatUL = seg_data.GetDouble(nPos+48, 16);
    segment->LongUR =  seg_data.GetDouble(nPos+64, 16);
    segment->LatUR = seg_data.GetDouble(nPos+80, 16);
    segment->LongLR = seg_data.GetDouble(nPos+96, 16);
    segment->LatLR = seg_data.GetDouble(nPos+112, 16);
    segment->LongLL = seg_data.GetDouble(nPos+128, 16);
    segment->LatLL = seg_data.GetDouble(nPos+144, 16);
    segment->HtCentre = seg_data.GetDouble(nPos+160, 16);
    segment->HtUL = seg_data.GetDouble(nPos+176, 16);
    segment->HtUR = seg_data.GetDouble(nPos+192, 16);
    segment->HtLR = seg_data.GetDouble(nPos+208, 16);
    segment->HtLL = seg_data.GetDouble(nPos+224, 16);

/* -------------------------------------------------------------------- */
/*      Process the 5th block.                                          */
/* -------------------------------------------------------------------- */
    nPos = nStartBlock + 512*4;

    segment->ImageRecordLength = seg_data.GetInt(nPos, 16);
    segment->NumberImageLine = seg_data.GetInt(nPos+16, 16);
    segment->NumberBytePerPixel = seg_data.GetInt(nPos+32, 16);
    segment->NumberSamplePerLine = seg_data.GetInt(nPos+48, 16);
    segment->NumberPrefixBytes = seg_data.GetInt(nPos+64, 16);
    segment->NumberSuffixBytes = seg_data.GetInt(nPos+80, 16);

/* -------------------------------------------------------------------- */
/*      Process the 6th and 7th block.                                  */
/* -------------------------------------------------------------------- */
    nPos = nStartBlock + 5*512;

    segment->SPNCoeff = 0;

    if(std::strncmp(seg_data.Get(nPos,8), "SPOT1BOD", 8)==0 ||
       std::strncmp(seg_data.Get(nPos,8), "SPOT1BNW", 8)==0)
    {
        segment->SPNCoeff = seg_data.GetInt(nPos+22, 22);
        for (i=0; i<20; i++)   
        {
            segment->SPCoeff1B[i] = 
                seg_data.GetDouble(nPos+(i+2)*22, 22);
        }

        if (std::strncmp(seg_data.Get(nPos,8), "SPOT1BNW", 8)==0)
        {
            nPos = nStartBlock + 6*512;

            for (i=0; i<19; i++)   
            {
                segment->SPCoeff1B[i+20] = 
                    seg_data.GetDouble(nPos+i*22, 22);
            }
            segment->SPCoeffSg[0] = seg_data.GetInt(nPos+418, 8);
            segment->SPCoeffSg[1] = seg_data.GetInt(nPos+426, 8);
            segment->SPCoeffSg[2] = seg_data.GetInt(nPos+434, 8);
            segment->SPCoeffSg[3] = seg_data.GetInt(nPos+442, 8);
        }
    }

/* -------------------------------------------------------------------- */
/*	6th and 7th block of ORBIT segment are blank.			*/
/*	Read in the 8th block.						*/
/* -------------------------------------------------------------------- */
    nPos = nStartBlock + 7*512;
    
    if (std::strncmp(seg_data.Get(nPos,8), "ATTITUDE", 8)==0)
        segment->Type = OrbAttitude;
    else if (std::strncmp(seg_data.Get(nPos,8), "RADAR   ", 8)==0)
        segment->Type = OrbLatLong;
    else if (std::strncmp(seg_data.Get(nPos,8), "AVHRR   ", 8)==0)
        segment->Type = OrbAvhrr;
    else if (std::strncmp(seg_data.Get(nPos,8), "NO_DATA ", 8)==0)
        segment->Type = OrbNone;
    else
        throw PCIDSKException("Invalid Orbit type found: [%s]", 
                              seg_data.Get(nPos,8));

/* -------------------------------------------------------------------- */
/*	Orbit segment is a Satellite Attitude Segment(ATTITUDE) only	*/
/*	for SPOT 1A.							*/
/* -------------------------------------------------------------------- */
    if (segment->Type == OrbAttitude)
    {
        AttitudeSeg_t 	*AttitudeSeg;
        int		nBlock, nData;

        AttitudeSeg = segment->AttitudeSeg = new AttitudeSeg_t();  
	
/* -------------------------------------------------------------------- */
/*	Read in the 9th block.						*/
/* -------------------------------------------------------------------- */
        nPos = nStartBlock + 512*8;
        
        AttitudeSeg->Roll = seg_data.GetDouble(nPos, 22);
        AttitudeSeg->Pitch = seg_data.GetDouble(nPos+22, 22);
        AttitudeSeg->Yaw = seg_data.GetDouble(nPos+44, 22);
        AttitudeSeg->NumberOfLine = seg_data.GetInt(nPos+88, 22);
        if (AttitudeSeg->NumberOfLine % ATT_SEG_LINE_PER_BLOCK != 0)
            AttitudeSeg->NumberBlockData = 1 + 
                AttitudeSeg->NumberOfLine / ATT_SEG_LINE_PER_BLOCK;
        else
            AttitudeSeg->NumberBlockData =  
                AttitudeSeg->NumberOfLine / ATT_SEG_LINE_PER_BLOCK;

/* -------------------------------------------------------------------- */
/*	Read in the line required.					*/
/* -------------------------------------------------------------------- */
        for (nBlock=0, nData=0; nBlock<AttitudeSeg->NumberBlockData; 
             nBlock++)
        {
/* -------------------------------------------------------------------- */
/*	Read in 10+nBlock th block as required.				*/
/* -------------------------------------------------------------------- */
            nPos = nStartBlock + 512*(9+nBlock);

/* -------------------------------------------------------------------- */
/*	Fill in the lines as required.					*/
/* -------------------------------------------------------------------- */
            for (i=0; 
                 i<ATT_SEG_LINE_PER_BLOCK 
		     && nData < AttitudeSeg->NumberOfLine; 
                 i++, nData++)
            {
                AttitudeLine_t oAttitudeLine;
                oAttitudeLine.ChangeInAttitude
                    = seg_data.GetDouble(nPos+i*44, 22);
                oAttitudeLine.ChangeEarthSatelliteDist
                    = seg_data.GetDouble(nPos+i*44+22, 22);
                AttitudeSeg->Line.push_back(oAttitudeLine);
            }
        }

        if (nData != AttitudeSeg->NumberOfLine)
        {
            throw PCIDSKException("Number of data line read (%d) "
                     "does not matches with what is specified in "
                     "the segment (%d).\n", nData, 
                     AttitudeSeg->NumberOfLine);
        }
    }
/* -------------------------------------------------------------------- */
/*	Radar segment (LATLONG)						*/
/* -------------------------------------------------------------------- */
    else if (segment->Type == OrbLatLong)
    {
        RadarSeg_t *RadarSeg;
        int	nBlock, nData;

        RadarSeg = segment->RadarSeg = new RadarSeg_t(); 
/* -------------------------------------------------------------------- */
/*	Read in the 9th block.						*/
/* -------------------------------------------------------------------- */
        nPos = nStartBlock + 512*8;

        RadarSeg->Identifier = seg_data.Get(nPos, 16);
        RadarSeg->Facility = seg_data.Get(nPos+16, 16);
        RadarSeg->Ellipsoid = seg_data.Get(nPos+32, 16);

        RadarSeg->EquatorialRadius = seg_data.GetDouble(nPos+48, 16);
        RadarSeg->PolarRadius = seg_data.GetDouble(nPos+64, 16); 
        RadarSeg->IncidenceAngle = seg_data.GetDouble(nPos+80, 16);
        RadarSeg->LineSpacing = seg_data.GetDouble(nPos+96, 16);
        RadarSeg->PixelSpacing = seg_data.GetDouble(nPos+112, 16);
        RadarSeg->ClockAngle = seg_data.GetDouble(nPos+128, 16);

/* -------------------------------------------------------------------- */
/*	Read in the 10th block.						*/
/* -------------------------------------------------------------------- */
        nPos = nStartBlock + 9*512;

        RadarSeg->NumberBlockData = seg_data.GetInt(nPos, 8);
        RadarSeg->NumberData = seg_data.GetInt(nPos+8, 8);

/* -------------------------------------------------------------------- */
/* 	Read in the 11-th through 11+RadarSeg->NumberBlockData th block	*/
/*	for the ancillary data present.					*/
/* -------------------------------------------------------------------- */
        for (nBlock = 0, nData = 0; 
             nBlock < RadarSeg->NumberBlockData; nBlock++)
        {
/* -------------------------------------------------------------------- */
/*	Read in one block of data.					*/
/* -------------------------------------------------------------------- */
            nPos = nStartBlock + 512*(10+nBlock);

            for (i=0; 
                 i<ANC_DATA_PER_BLK &&  nData < RadarSeg->NumberData; 
                 i++, nData++)
            {
                int	offset;
                char	*currentindex;
                void	*currentptr;
                double	tmp;
                int32	tmpInt;
                const double million = 1000000.0;
                
/* -------------------------------------------------------------------- */
/*	Reading in one ancillary data at a time.			*/
/* -------------------------------------------------------------------- */
                AncillaryData_t oData;
                offset = i*ANC_DATA_SIZE;

                currentindex = (char *)seg_data.Get(nPos+offset,4);
                currentptr = (char *) currentindex; 
                SwapData(currentptr,4,1);
                tmpInt = *((int32 *) currentptr);
                oData.SlantRangeFstPixel = tmpInt; 

                currentindex = (char *)seg_data.Get(nPos+offset+4,4); 
                currentptr = (char *) currentindex;
                SwapData(currentptr,4,1);
                tmpInt = *((int32 *) currentptr); 
                oData.SlantRangeLastPixel = tmpInt; 

                currentindex = (char *)seg_data.Get(nPos+offset+8,4);
                currentptr = (char *) currentindex;
                SwapData(currentptr,4,1);
                tmpInt = *((int32 *) currentptr); 
                tmp = (double) tmpInt / million;
                oData.FstPixelLat
                    = (float) ConvertDeg(tmp, 0);

                currentindex = (char *)seg_data.Get(nPos+offset+12,4);
                currentptr = (char *) currentindex;
                SwapData(currentptr,4,1);
                tmpInt = *((int32 *) currentptr); 
                tmp = (double) tmpInt / million;
                oData.MidPixelLat 
                    = (float) ConvertDeg(tmp, 0);

                currentindex = (char *)seg_data.Get(nPos+offset+16,4);
                currentptr = (char *) currentindex;
                SwapData(currentptr,4,1);
                tmpInt = *((int32 *) currentptr); 
                tmp = (double) tmpInt / million;
                oData.LstPixelLat
                    = (float) ConvertDeg(tmp, 0);

                currentindex = (char *)seg_data.Get(nPos+offset+20,4);
                currentptr = (char *) currentindex;
                SwapData(currentptr,4,1);
                tmpInt = *((int32 *) currentptr); 
                tmp = (double) tmpInt / million;
                oData.FstPixelLong
                    = (float) ConvertDeg(tmp, 0);

                currentindex = (char *)seg_data.Get(nPos+offset+24,4);
                currentptr = (char *) currentindex; 
                SwapData(currentptr,4,1);
                tmpInt = *((int32 *) currentptr); 
                tmp = (double) tmpInt / million;
                oData.MidPixelLong
                    = (float) ConvertDeg(tmp, 0);

                currentindex = (char *)seg_data.Get(nPos+offset+28,4);
                currentptr = (char *) currentindex;
                SwapData(currentptr,4,1);
                tmpInt = *((int32 *) currentptr); 
                tmp = (double) tmpInt / million;
                oData.LstPixelLong
                    = (float) ConvertDeg(tmp, 0);

                RadarSeg->Line.push_back(oData);
            }
        }

        if (RadarSeg->NumberData != nData)
        {
            throw PCIDSKException("Number "
		     "of data lines read (%d) does not match with"
                     "\nwhat is specified in segment (%d).\n", nData, 
                     RadarSeg->NumberData);
        }
    }
/* -------------------------------------------------------------------- */
/*	AVHRR segment 							*/
/* -------------------------------------------------------------------- */
    else if (segment->Type == OrbAvhrr)
    {
        ReadAvhrrEphemerisSegment( nStartBlock, segment);
    }

    return segment;
}

/************************************************************************/
/*                        EphemerisToBinary()                           */
/************************************************************************/
/**
 * Write an Orbit segment information into a binary buffer of size 4096.
 * The caller is responsible to free this memory with delete [].
 *
 * @param psOrbit the orbit information to write into the binary
 * @param nStartBlock where to start writing in the buffer.
 */
void
CPCIDSKEphemerisSegment::EphemerisToBinary( EphemerisSeg_t * psOrbit,
                                              int nStartBlock )

{
    int		i,j;

/* -------------------------------------------------------------------- */
/*      The binary data must be at least 8 blocks (4096 bytes) long     */
/*      for the common information.                                     */
/* -------------------------------------------------------------------- */
    seg_data.SetSize(nStartBlock+4096);
    memset(seg_data.buffer+nStartBlock,' ',4096);

    int nPos = nStartBlock;

/* -------------------------------------------------------------------- */
/*	Write the first block						*/
/* -------------------------------------------------------------------- */

    seg_data.Put("ORBIT   ",nPos,8);
    seg_data.Put(psOrbit->SatelliteDesc.c_str(), nPos+8,32,true);
    seg_data.Put(psOrbit->SceneID.c_str(), nPos+40,32,true);

/* -------------------------------------------------------------------- */
/*	Write the second block						*/
/* -------------------------------------------------------------------- */
    nPos = nStartBlock + 1*512;
    
    seg_data.Put(psOrbit->SatelliteSensor.c_str(), nPos,16);
    seg_data.Put(psOrbit->SensorNo.c_str(),nPos+22,2,true);
    seg_data.Put(psOrbit->DateImageTaken.c_str(), nPos+44,22,true);

    if (psOrbit->SupSegExist)
        seg_data.Put("Y",nPos+66,1);
    else
        seg_data.Put("N",nPos+66,1);

    seg_data.Put(psOrbit->FieldOfView,nPos+88,22,"%22.14f");
    seg_data.Put(psOrbit->ViewAngle,nPos+110,22,"%22.14f");
    seg_data.Put(psOrbit->NumColCentre,nPos+132,22,"%22.14f");
    seg_data.Put(psOrbit->RadialSpeed,nPos+154,22,"%22.14f");
    seg_data.Put(psOrbit->Eccentricity,nPos+176,22,"%22.14f");
    seg_data.Put(psOrbit->Height,nPos+198,22,"%22.14f");
    seg_data.Put(psOrbit->Inclination,nPos+220,22,"%22.14f");
    seg_data.Put(psOrbit->TimeInterval,nPos+242,22,"%22.14f");
    seg_data.Put(psOrbit->NumLineCentre,nPos+264,22,"%22.14f");
    seg_data.Put(psOrbit->LongCentre,nPos+286,22,"%22.14f");
    seg_data.Put(psOrbit->AngularSpd,nPos+308,22,"%22.14f");
    seg_data.Put(psOrbit->AscNodeLong,nPos+330,22,"%22.14f");
    seg_data.Put(psOrbit->ArgPerigee,nPos+352,22,"%22.14f");
    seg_data.Put(psOrbit->LatCentre,nPos+374,22,"%22.14f");
    seg_data.Put(psOrbit->EarthSatelliteDist,nPos+396,22,"%22.14f");
    seg_data.Put(psOrbit->NominalPitch,nPos+418,22,"%22.14f");
    seg_data.Put(psOrbit->TimeAtCentre,nPos+440,22,"%22.14f");
    seg_data.Put(psOrbit->SatelliteArg,nPos+462,22,"%22.14f");

    if (psOrbit->bDescending)
        seg_data.Put("DESCENDING",nPos+484,10);
    else
        seg_data.Put("ASCENDING ",nPos+484,10);

/* -------------------------------------------------------------------- */
/*	Write the third block						*/
/* -------------------------------------------------------------------- */
    nPos = nStartBlock + 512*2;

    seg_data.Put(psOrbit->XCentre,nPos,22,"%22.14f");
    seg_data.Put(psOrbit->YCentre,nPos+22,22,"%22.14f");
    seg_data.Put(psOrbit->UtmXCentre,nPos+44,22,"%22.14f");
    seg_data.Put(psOrbit->UtmYCentre,nPos+66,22,"%22.14f");
    seg_data.Put(psOrbit->PixelRes,nPos+88,22,"%22.14f");
    seg_data.Put(psOrbit->LineRes,nPos+110,22,"%22.14f");

    if (psOrbit->CornerAvail == true)
        seg_data.Put("Y",nPos+132,1);
    else
        seg_data.Put("N",nPos+132,1);

    seg_data.Put(psOrbit->MapUnit.c_str(),nPos+133,16,true);

    seg_data.Put(psOrbit->XUL,nPos+149,22,"%22.14f");
    seg_data.Put(psOrbit->YUL,nPos+171,22,"%22.14f");
    seg_data.Put(psOrbit->XUR,nPos+193,22,"%22.14f");
    seg_data.Put(psOrbit->YUR,nPos+215,22,"%22.14f");
    seg_data.Put(psOrbit->XLR,nPos+237,22,"%22.14f");
    seg_data.Put(psOrbit->YLR,nPos+259,22,"%22.14f");
    seg_data.Put(psOrbit->XLL,nPos+281,22,"%22.14f");
    seg_data.Put(psOrbit->YLL,nPos+303,22,"%22.14f");
    seg_data.Put(psOrbit->UtmXUL,nPos+325,22,"%22.14f");
    seg_data.Put(psOrbit->UtmYUL,nPos+347,22,"%22.14f");
    seg_data.Put(psOrbit->UtmXUR,nPos+369,22,"%22.14f");
    seg_data.Put(psOrbit->UtmYUR,nPos+391,22,"%22.14f");
    seg_data.Put(psOrbit->UtmXLR,nPos+413,22,"%22.14f");
    seg_data.Put(psOrbit->UtmYLR,nPos+435,22,"%22.14f");
    seg_data.Put(psOrbit->UtmXLL,nPos+457,22,"%22.14f");
    seg_data.Put(psOrbit->UtmYLL,nPos+479,22,"%22.14f");

/* -------------------------------------------------------------------- */
/*	Write the fourth block						*/
/* -------------------------------------------------------------------- */
    nPos = nStartBlock + 512*3;
    
    seg_data.Put(psOrbit->LongCentreDeg,nPos,22,"%16.7f");
    seg_data.Put(psOrbit->LatCentreDeg,nPos+16,22,"%16.7f");
    seg_data.Put(psOrbit->LongUL,nPos+32,22,"%16.7f");
    seg_data.Put(psOrbit->LatUL,nPos+48,22,"%16.7f");
    seg_data.Put(psOrbit->LongUR,nPos+64,22,"%16.7f");
    seg_data.Put(psOrbit->LatUR,nPos+80,22,"%16.7f");
    seg_data.Put(psOrbit->LongLR,nPos+96,22,"%16.7f");
    seg_data.Put(psOrbit->LatLR,nPos+112,22,"%16.7f");
    seg_data.Put(psOrbit->LongLL,nPos+128,22,"%16.7f");
    seg_data.Put(psOrbit->LatLL,nPos+144,22,"%16.7f");
    seg_data.Put(psOrbit->HtCentre,nPos+160,22,"%16.7f");
    seg_data.Put(psOrbit->HtUL,nPos+176,22,"%16.7f");
    seg_data.Put(psOrbit->HtUR,nPos+192,22,"%16.7f");
    seg_data.Put(psOrbit->HtLR,nPos+208,22,"%16.7f");
    seg_data.Put(psOrbit->HtLL,nPos+224,22,"%16.7f");

/* -------------------------------------------------------------------- */
/*	Write the fifth block						*/
/* -------------------------------------------------------------------- */
    nPos = nStartBlock + 512*4;

    seg_data.Put(psOrbit->ImageRecordLength,nPos,16);
    seg_data.Put(psOrbit->NumberImageLine,nPos+16,16);
    seg_data.Put(psOrbit->NumberBytePerPixel,nPos+32,16);
    seg_data.Put(psOrbit->NumberSamplePerLine,nPos+48,16);
    seg_data.Put(psOrbit->NumberPrefixBytes,nPos+64,16);
    seg_data.Put(psOrbit->NumberSuffixBytes,nPos+80,16);

/* -------------------------------------------------------------------- */
/*	Write the sixth and seventh block (blanks)			*/
/*	For SPOT it is not blank					*/
/* -------------------------------------------------------------------- */
    nPos = nStartBlock + 512*5;

    if (psOrbit->SPNCoeff > 0)
    {
        if (psOrbit->SPNCoeff == 20)
	{
            seg_data.Put("SPOT1BOD",nPos,8);
            seg_data.Put(psOrbit->SPNCoeff,nPos+22,22);

	    j = 44;
	    for (i=0; i<20; i++)
	    {
                seg_data.Put(psOrbit->SPCoeff1B[i],
                                     nPos+j,22,"%22.14f");
		j += 22;
	    }
	}
	else
	{
            seg_data.Put("SPOT1BNW",nPos,8);
            seg_data.Put(psOrbit->SPNCoeff,nPos+22,22);

	    j = 44;
            for (i=0; i<20; i++)
            {
                seg_data.Put(psOrbit->SPCoeff1B[i],
                                     nPos+j,22,"%22.14f");
                j += 22;
            }

            nPos = nStartBlock + 512*6;

            j = 0;
            for (i=20; i<39; i++)
            {
                seg_data.Put(psOrbit->SPCoeff1B[i],
                                     nPos+j,22,"%22.14f");
                j += 22;
            }

            seg_data.Put(psOrbit->SPCoeffSg[0],nPos+418,8);
            seg_data.Put(psOrbit->SPCoeffSg[1],nPos+426,8);
            seg_data.Put(psOrbit->SPCoeffSg[2],nPos+434,8);
            seg_data.Put(psOrbit->SPCoeffSg[3],nPos+442,8);
        }
    } 

/* -------------------------------------------------------------------- */
/*	Write the eighth block.						*/
/* -------------------------------------------------------------------- */
    nPos = nStartBlock + 512*7;
    
    if (psOrbit->Type == OrbAttitude)
        seg_data.Put("ATTITUDE",nPos,8);
    else if (psOrbit->Type == OrbLatLong)
        seg_data.Put("RADAR   ",nPos,8);
    else if (psOrbit->Type == OrbAvhrr)
        seg_data.Put("AVHRR   ",nPos,8);
    else if (psOrbit->Type == OrbNone)
        seg_data.Put("NO_DATA ",nPos,8);
    else
    {
        throw PCIDSKException("Invalid Orbit type."); 
    }

/* ==================================================================== */
/*	Orbit segment is a Satellite Attitude Segment(ATTITUDE) only	*/
/*	for SPOT 1A.							*/
/* ==================================================================== */
    if (psOrbit->Type == OrbAttitude)
    {
        AttitudeSeg_t *AttitudeSeg;
        int		nBlock, nData;

        AttitudeSeg = psOrbit->AttitudeSeg;

        if (AttitudeSeg == NULL)
        {
            throw PCIDSKException("The AttitudeSeg is NULL.");
        }

/* -------------------------------------------------------------------- */
/*      Add one block                                                   */
/* -------------------------------------------------------------------- */
        seg_data.SetSize(seg_data.buffer_size + 512);
            
        nPos = nStartBlock + 512*8;
        memset(seg_data.buffer+nPos,' ',512);
            
/* -------------------------------------------------------------------- */
/*	Write the nineth block.						*/
/* -------------------------------------------------------------------- */

        seg_data.Put(AttitudeSeg->Roll,nPos,22,"%22.14f");
        seg_data.Put(AttitudeSeg->Pitch,nPos+22,22,"%22.14f");
        seg_data.Put(AttitudeSeg->Yaw,nPos+44,22,"%22.14f");

        if (AttitudeSeg->NumberOfLine % ATT_SEG_LINE_PER_BLOCK != 0)
            AttitudeSeg->NumberBlockData = 1 + 
                AttitudeSeg->NumberOfLine / ATT_SEG_LINE_PER_BLOCK;
        else
            AttitudeSeg->NumberBlockData =  
                AttitudeSeg->NumberOfLine / ATT_SEG_LINE_PER_BLOCK;

        seg_data.Put(AttitudeSeg->NumberBlockData,nPos+66,22);
        seg_data.Put(AttitudeSeg->NumberOfLine,nPos+88,22);

/* -------------------------------------------------------------------- */
/*      Add NumberBlockData blocks to array.                            */
/* -------------------------------------------------------------------- */
        seg_data.SetSize(seg_data.buffer_size + 
                                 512 * AttitudeSeg->NumberBlockData);
            
        nPos = nStartBlock + 512*9;
        memset(seg_data.buffer+nPos,' ',
               512 * AttitudeSeg->NumberBlockData);
            
/* -------------------------------------------------------------------- */
/*	Write out the line required.					*/
/* -------------------------------------------------------------------- */
        for (nBlock=0, nData=0; nBlock<AttitudeSeg->NumberBlockData; 
             nBlock++)
        {
            int		i;
            nPos = nStartBlock + 512*(nBlock + 9);

/* -------------------------------------------------------------------- */
/*	Fill in buffer as required.					*/
/* -------------------------------------------------------------------- */
            for (i=0; 
                 i<ATT_SEG_LINE_PER_BLOCK 
		     && nData < AttitudeSeg->NumberOfLine; 
                 i++, nData++)
            {
                seg_data.Put(
                    AttitudeSeg->Line[nData].ChangeInAttitude,
                    nPos+i*44,22,"%22.14f");
                seg_data.Put(
                    AttitudeSeg->Line[nData].ChangeEarthSatelliteDist,
                    nPos+i*44+22,22,"%22.14f");
            }
        }

        if (nData != AttitudeSeg->NumberOfLine)
        {
            throw PCIDSKException("Number of data line written"
		    " (%d) does not match with\nwhat is specified "
		    " in the segment (%d).\n", 
		    nData, AttitudeSeg->NumberOfLine);
        }
    }

/* ==================================================================== */
/*	Radar segment (LATLONG)						*/
/* ==================================================================== */
    else if (psOrbit->Type == OrbLatLong)
    {
        RadarSeg_t *RadarSeg;
        int	   i, nBlock, nData;

        RadarSeg = psOrbit->RadarSeg;

        if (RadarSeg == NULL)
        {
            throw PCIDSKException("The RadarSeg is NULL.");
        }

/* -------------------------------------------------------------------- */
/*      Add two blocks.                                                 */
/* -------------------------------------------------------------------- */
        seg_data.SetSize(seg_data.buffer_size + 512*2);
            
        nPos = nStartBlock + 512*8;
        memset(seg_data.buffer+nPos,' ', 512*2);
            
/* -------------------------------------------------------------------- */
/*	Write out the nineth block.					*/
/* -------------------------------------------------------------------- */

        seg_data.Put(RadarSeg->Identifier.c_str(), nPos,16);
        seg_data.Put(RadarSeg->Facility.c_str(), nPos+16,16);
        seg_data.Put(RadarSeg->Ellipsoid.c_str(), nPos+32,16);

        seg_data.Put(RadarSeg->EquatorialRadius,nPos+48,16,"%16.7f");
        seg_data.Put(RadarSeg->PolarRadius,nPos+64,16,"%16.7f");
        seg_data.Put(RadarSeg->IncidenceAngle,nPos+80,16,"%16.7f");
        seg_data.Put(RadarSeg->LineSpacing,nPos+96,16,"%16.7f");
        seg_data.Put(RadarSeg->PixelSpacing,nPos+112,16,"%16.7f");
        seg_data.Put(RadarSeg->ClockAngle,nPos+128,16,"%16.7f");

/* -------------------------------------------------------------------- */
/*	Write out the tenth block.					*/
/* -------------------------------------------------------------------- */
        nPos = nStartBlock + 512*9;

        seg_data.Put(RadarSeg->NumberBlockData,nPos,8);
        seg_data.Put(RadarSeg->NumberData,nPos+8,8);

/* -------------------------------------------------------------------- */
/*      Make room for all the following per-line data.                  */
/* -------------------------------------------------------------------- */
        seg_data.SetSize(seg_data.buffer_size + 
                                 512 * RadarSeg->NumberBlockData);
            
        nPos = nStartBlock + 512*10;
        memset(seg_data.buffer+nPos,' ', 
               512 * RadarSeg->NumberBlockData);
        
/* -------------------------------------------------------------------- */
/* 	Write out the 11-th through 11+psOrbit->NumberBlockData  block	*/
/*	for the ancillary data present.					*/
/* -------------------------------------------------------------------- */
        for (nBlock = 0, nData = 0; 
             nBlock < RadarSeg->NumberBlockData; nBlock++)
        {
            for (i=0; 
                 i<ANC_DATA_PER_BLK &&  nData < RadarSeg->NumberData;
                 i++, nData++)
            {
                int		offset;
                char		*currentptr, *currentindex;
                double		tmp, tmpDouble;
                const double million = 1000000.0;
                int32		tmpInt;
                
/* -------------------------------------------------------------------- */
/*	Point to correct block						*/
/* -------------------------------------------------------------------- */
                nPos = nStartBlock + 512*(10+nBlock);
            
/* -------------------------------------------------------------------- */
/*	Writing out one ancillary data at a time.			*/
/* -------------------------------------------------------------------- */
                offset = i*ANC_DATA_SIZE;

                currentptr = 
                    (char *) &(RadarSeg->Line[nData].SlantRangeFstPixel); 
                SwapData(currentptr,4,1);
                currentindex = &(seg_data.buffer[nPos+offset]);
                std::memcpy((void *) currentindex,currentptr, 4); 

                currentptr =
                    (char *) &(RadarSeg->Line[nData].SlantRangeLastPixel);
                SwapData(currentptr,4,1);
                currentindex += 4; 
                std::memcpy((void *) currentindex,currentptr, 4);

                tmp = ConvertDeg(RadarSeg->Line[nData].FstPixelLat, 1);
                tmpDouble =  tmp * million;
                tmpInt = (int32) tmpDouble;
                currentptr = (char *) &tmpInt;
                SwapData(currentptr,4,1);
                currentindex += 4; 
                std::memcpy((void *) currentindex,currentptr, 4);

                tmp = ConvertDeg(RadarSeg->Line[nData].MidPixelLat, 1);
                tmpDouble =  tmp * million; 
                tmpInt = (int32) tmpDouble;
                currentptr = (char *) &tmpInt;
                SwapData(currentptr,4,1);
                currentindex += 4;
                std::memcpy((void *) currentindex,currentptr, 4);

                tmp = ConvertDeg(RadarSeg->Line[nData].LstPixelLat, 1);
                tmpDouble =  tmp * million;
                tmpInt = (int32) tmpDouble;
                currentptr = (char *) &tmpInt;
                SwapData(currentptr,4,1);
                currentindex += 4;
                std::memcpy((void *) currentindex,currentptr, 4);

                tmp = ConvertDeg(RadarSeg->Line[nData].FstPixelLong, 1);
                tmpDouble =  tmp * million;
                tmpInt = (int32) tmpDouble;
                currentptr = (char *) &tmpInt;
                SwapData(currentptr,4,1);
                currentindex += 4;
                std::memcpy((void *) currentindex,currentptr, 4);

                tmp = ConvertDeg(RadarSeg->Line[nData].MidPixelLong, 1);
                tmpDouble = tmp * million;
                tmpInt = (int32) tmpDouble;
                currentptr = (char *) &tmpInt;
                SwapData(currentptr,4,1);
                currentindex += 4;
                std::memcpy((void *) currentindex,currentptr, 4);

                tmp = ConvertDeg(RadarSeg->Line[nData].LstPixelLong, 1);
                tmpDouble =  tmp * million;
                tmpInt = (int32) tmpDouble;
                currentptr = (char *) &tmpInt;
                SwapData(currentptr,4,1);
                currentindex += 4;
                std::memcpy((void *) currentindex,currentptr, 4);
            }
        }
    }

/* ==================================================================== */
/*	AVHRR segment 							*/
/* ==================================================================== */
    else if ( psOrbit->Type == OrbAvhrr &&
              psOrbit->AvhrrSeg->nNumRecordsPerBlock > 0 )
    {
        WriteAvhrrEphemerisSegment(nStartBlock + 8*512 , psOrbit);
    }
}


