void saveBuffer( const DataBuffer& buff, int fd ) throw (MC2String)
{
   int retVal =  write( fd, 
                        buff.getBufferAddress(), 
                        buff.getCurrentOffset() );
   if ( retVal == -1 ) {
      throw MC2String("[DBU]: Could not write: ") + strerror(errno);
   } else if ( uint32(retVal) != buff.getCurrentOffset() ) {
      throw MC2String("[DBU]: Could not write buffer. Short byte count");
   }
}
bool
NavMapHandler::handleVectorMap( UserItem* userItem, 
                                NavRequestPacket* req,
                                NavReplyPacket* reply )
{
   bool ok = true;

   // The params
   const NParamBlock& params = req->getParamBlock();
   NParamBlock& rparams = reply->getParamBlock();

   uint32 startTime = TimeUtility::getCurrentTime();
   MC2String reqStr;

   // Start parameter printing
   mc2log << info << "handleVectorMap:";
   
   if ( params.getParam( 2400 ) ) {
      reqStr = params.getParam( 2400 )->getString(
         m_thread->clientUsesLatin1());
      mc2log << " " << reqStr;
   }
   mc2log << endl;

   rparams.addParam( NParam( 2500, reqStr, 
                             m_thread->clientUsesLatin1() ) );

   DataBuffer* data = m_thread->getTileMap( reqStr.c_str() );

   if ( data != NULL ) {
      NParam& pdata = rparams.addParam( NParam( 2501 ) );
      pdata.addByteArray( data->getBufferAddress(), 
                          data->getCurrentOffset() );
      mc2log << info << "handleVectorMap: Reply " 
             << data->getCurrentOffset() << " bytes" << endl;
   } else { // Error
      mc2log << warn << "handleVectorMap: NULL TileMap answer: ";
      if ( TimeUtility::getCurrentTime() - startTime > 3000 ) {
         reply->setStatusCode( 
            NavReplyPacket::NAV_STATUS_REQUEST_TIMEOUT );
         mc2log << "Timeout";
      } else {
         reply->setStatusCode(
            NavReplyPacket::NAV_STATUS_NOT_OK );
         mc2log << "Error";
      }
      mc2log << endl;
   }
   
   delete data;
   
   return ok;
}
bool
NavMapHandler::handleMultiVectorMap( UserItem* userItem, 
                                     NavRequestPacket* req,
                                     NavReplyPacket* reply )
{
   bool ok = true;

   // The params
   const NParamBlock& params = req->getParamBlock();
   NParamBlock& rparams = reply->getParamBlock();

   uint32 startTime = TimeUtility::getCurrentTime();

   vector<MC2SimpleString> tmapParams;
   uint32 inReqSize = 0;
   uint32 startOffset = 0;
   uint32 maxSize = 2048;

   // Start parameter printing
   mc2log << info << "handleMultiVectorMap:";
   
   if ( params.getParam( 4600 ) ) {
      startOffset = params.getParam( 4600 )->getUint32();
      mc2log << " startOffset " << startOffset;
   }

   if ( params.getParam( 4601 ) ) {
      maxSize = params.getParam( 4601 )->getUint32();
      mc2log << " maxSize " << maxSize;
   }

   if ( params.getParam( 4602 ) ) {
      uint32 pos = 0;
      while ( pos < params.getParam( 4602 )->getLength() ) {
         MC2String reqStr = params.getParam( 4602 )->incGetString(            
            m_thread->clientUsesLatin1(), pos);
         mc2log << " " << reqStr;
         tmapParams.push_back( reqStr.c_str() );
      }
      inReqSize = pos;
   }
   mc2log << endl;

   DataBuffer* data = m_thread->getTileMaps( 
      tmapParams, startOffset, maxSize );

   if ( data != NULL ) {
      for ( uint32 pos = 0; pos < data->getCurrentOffset() ; 
            pos += MAX_UINT16 )
      {
         NParam& pdata = rparams.addParam( NParam( 4700 ) );
         uint32 size = MIN( data->getCurrentOffset() - pos, MAX_UINT16 );
         pdata.addByteArray( data->getBufferAddress() + pos, size );
      }
      mc2log << info << "handleMultiVectorMap: Reply " 
             << data->getCurrentOffset() << " bytes Request " 
             << inReqSize << " bytes" << endl;
   } else { // Error
      mc2log << warn << "handleMultiVectorMap: NULL TileMap answer: ";
      if ( TimeUtility::getCurrentTime() - startTime > 3000 ) {
         reply->setStatusCode( 
            NavReplyPacket::NAV_STATUS_REQUEST_TIMEOUT );
         mc2log << "Timeout";
      } else {
         reply->setStatusCode(
            NavReplyPacket::NAV_STATUS_NOT_OK );
         mc2log << "Error";
      }
      mc2log << endl;
   }
   
   delete data;
   
   return ok;
}
bool
GenericMapHeader::internalLoad(DataBuffer& dataBuffer)
{
   CLOCK_MAPLOAD(DebugClock loadClock);
   mc2dbg4 << "GenericMapHeader::internalLoad" << endl;
   // ***************************************************************
   //                                Read the general map information
   // ***************************************************************
   uint32 currentMapID = dataBuffer.readNextLong();
   // do check without map set bits
   if (currentMapID != MapBits::getMapIDWithoutMapSet( m_mapID )) {
      mc2log << fatal << "GenericMapHeader::createFromDataBuffer, currentMapID: " 
             << prettyMapIDFill(currentMapID) << " does not match filename, mapID: " 
             << prettyMapIDFill(m_mapID) << ". EXITING!" << endl;
      exit(1);
   }
   m_totalMapSize = dataBuffer.readNextLong(); // WARNING: Not set in file!!!
   mc2dbg << "[GMH]: Total map size variable = " << m_totalMapSize
          << " and size of DataBuffer = " << dataBuffer.getBufferSize()
          << endl;
   
   // Read the creationtime of this map
   m_creationTime = dataBuffer.readNextLong();

   // Read some data about all the items in this map
   m_country = StringTable::countryCode(dataBuffer.readNextLong());
   
   byte flagByte = dataBuffer.readNextByte();
   byte nbrNativeLanguages = dataBuffer.readNextByte();
   byte nbrCurrencies = dataBuffer.readNextByte();
   m_loadedVersion= dataBuffer.readNextByte();

   if ( m_loadedVersion < 3 ) {
      m_driveOnRightSide = (flagByte != 0);
   } else {
      m_driveOnRightSide          = BitUtility::getBit( flagByte, 0 );
      m_groupsInLocationNameOrder = BitUtility::getBit( flagByte, 1 );
   }
   
   m_nbrAllocators = dataBuffer.readNextLong();
   mc2dbg << "Nbr allocators: " << m_nbrAllocators << endl;

   // The languages
   m_nativeLanguages.resize( nbrNativeLanguages );
   for (NativeLanguageIndexes::size_type i=0; i<nbrNativeLanguages; i++) {
      m_nativeLanguages[ i ] = 
         static_cast<NativeLanguageIndexes::value_type>
         ( dataBuffer.readNextLong() );
   }

   // The currencies
   m_currency = new Vector(nbrCurrencies);
   for (uint32 i=0; i<nbrCurrencies; i++) {
      m_currency->addLast(dataBuffer.readNextLong());
   }

   // Variable header: 
   delete [] m_name;
   delete [] m_origin;
   delete [] m_mapCountryDir;
   switch ( m_loadedVersion ) {
      case ( 0 ) :
         m_name = StringUtility::newStrDup( "" );
         m_origin = StringUtility::newStrDup( "" );
         m_trueCreationTime = MAX_UINT32;
         m_waspTime = MAX_UINT32;
         m_dynamicExtradataTime = MAX_UINT32;
         m_utf8Strings = false;
         m_mapFiltered = false;
         m_mapGfxDataFiltered = false;
         m_mapCountryDir = StringUtility::newStrDup("");

         break;
      case ( 1 ) : {
         uint32 offset = dataBuffer.getCurrentOffset();
         uint32 variableHeaderSize = dataBuffer.readNextLong();
         
         m_name = StringUtility::newStrDup( dataBuffer.readNextString() );
         m_origin = StringUtility::newStrDup( "" );
         m_trueCreationTime = MAX_UINT32;
         m_waspTime = MAX_UINT32;
         m_dynamicExtradataTime = MAX_UINT32;
         m_utf8Strings = false;
         m_mapFiltered = false;
         m_mapGfxDataFiltered = false;
         m_mapCountryDir = StringUtility::newStrDup("");

         dataBuffer.readPastBytes( variableHeaderSize - 
                                  ( dataBuffer.getCurrentOffset() - offset ) );
       } break;         
      case ( 2 ) :
      case ( 3 ) : {
         uint32 offset = dataBuffer.getCurrentOffset();
         uint32 variableHeaderSize = dataBuffer.readNextLong();
         
         m_name = StringUtility::newStrDup( dataBuffer.readNextString() );
         m_origin = StringUtility::newStrDup( dataBuffer.readNextString() );
         m_trueCreationTime = MAX_UINT32;
         m_waspTime = MAX_UINT32;
         m_dynamicExtradataTime = MAX_UINT32;
         m_utf8Strings = false;
         m_mapFiltered = false;
         m_mapGfxDataFiltered = false;
         m_mapCountryDir = StringUtility::newStrDup("");

         dataBuffer.readPastBytes( variableHeaderSize - 
                                  ( dataBuffer.getCurrentOffset() - offset ) );
       } break;
      case ( 4 ) : {
         uint32 offset = dataBuffer.getCurrentOffset();
         uint32 variableHeaderSize = dataBuffer.readNextLong();
         
         m_name = StringUtility::newStrDup( dataBuffer.readNextString() );
         m_origin = StringUtility::newStrDup( dataBuffer.readNextString() );
         m_trueCreationTime = dataBuffer.readNextLong();
         m_waspTime = dataBuffer.readNextLong();
         m_dynamicExtradataTime = dataBuffer.readNextLong();
         m_utf8Strings = false;
         m_mapFiltered = false;
         m_mapGfxDataFiltered = false;
         m_mapCountryDir = StringUtility::newStrDup("");

         dataBuffer.readPastBytes( variableHeaderSize - 
                                  ( dataBuffer.getCurrentOffset() - offset ) );
       } break;
      case (5) :
      case (6) :  // GenericMap::m_userRightsTable
      case (7) :  // GenericMap::m_adminAreaCentres
      default : {
         uint32 offset = dataBuffer.getCurrentOffset();
         uint32 variableHeaderSize = dataBuffer.readNextLong();
         
         m_name = StringUtility::newStrDup( dataBuffer.readNextString() );
         m_origin = StringUtility::newStrDup( dataBuffer.readNextString() );
         m_trueCreationTime = dataBuffer.readNextLong();
         m_waspTime = dataBuffer.readNextLong();
         m_dynamicExtradataTime = dataBuffer.readNextLong();
         m_utf8Strings = dataBuffer.readNextBool();
         m_mapFiltered = dataBuffer.readNextBool();
         m_mapGfxDataFiltered = dataBuffer.readNextBool();
         m_mapCountryDir = 
            StringUtility::newStrDup( dataBuffer.readNextString() );

         dataBuffer.readPastBytes( variableHeaderSize - 
                                  ( dataBuffer.getCurrentOffset() - offset ) );
       } break;
   }

   // Read string with copyright-information for images of this map
   m_copyrightString = StringUtility::newStrDup(dataBuffer.readNextString());

   CLOCK_MAPLOAD(mc2log << "[" << m_mapID << "] Header loaded in "
                 << loadClock
                 << ", m_loadedVersion=" << int(m_loadedVersion) << endl );
   return true;
}
bool 
OldCountryOverviewMap::internalSave(int outfile)
{
   // Save the general map data
   bool retVal = OldGenericMap::internalSave(outfile);
   
   mc2dbg1 << "SAVING COUNTRYMAP" << endl;
   if (retVal) {
      // Save the ID of the maps in this country
      DataBuffer dataBuffer((m_mapsInCountry.size()+1)*24);
      dataBuffer.writeNextLong(m_mapsInCountry.size());
      mc2dbg1 << "Nbr maps = " << m_mapsInCountry.size() << endl;
      for (uint32 i=0; i<m_mapsInCountry.size(); i++) {
         mc2dbg4 << "Saving map with ID=" 
                 << m_mapsInCountry[i].mapID << endl;
         dataBuffer.writeNextLong(m_mapsInCountry[i].mapID);
         dataBuffer.writeNextLong(m_mapsInCountry[i].creationTime);
         mc2dbg4 << "creationTime = " 
                 << m_mapsInCountry[i].creationTime << endl;
         dataBuffer.writeNextLong(m_mapsInCountry[i].maxLat);
         dataBuffer.writeNextLong(m_mapsInCountry[i].minLon);
         dataBuffer.writeNextLong(m_mapsInCountry[i].minLat);
         dataBuffer.writeNextLong(m_mapsInCountry[i].maxLon);
      }

      // Save to file
      write(outfile, 
            dataBuffer.getBufferAddress(), 
            dataBuffer.getCurrentOffset());

      // Save the original ID of the items in this map
      uint32 nbrOriginalIDs = m_originalIDs.size();
      mc2dbg1 << "To save " << nbrOriginalIDs << " original ID:s" << endl;
      DataBuffer origIDs(4 + nbrOriginalIDs*12);
      origIDs.writeNextLong(nbrOriginalIDs);
      map<uint32, struct originalIDs_t>::iterator p = m_originalIDs.begin();
      while (p != m_originalIDs.end()) {
         origIDs.writeNextLong(p->first);
         origIDs.writeNextLong(p->second.origMapID);
         origIDs.writeNextLong(p->second.origItemID);
         mc2dbg4 << "Saving itemID " << p->first << " orig("
                 << p->second.origMapID << "." << p->second.origItemID 
                 << ")" << endl;
         p++;
      }

      // Write the original IDs to file
      write(outfile, 
            origIDs.getBufferAddress(), 
            origIDs.getCurrentOffset());
      
      // Write the array of filter stacks.
      if (m_simplifiedGfxStack != NULL) {

         int numElements = m_nbrGfxPolygons * NBR_SIMPLIFIED_COUNTRY_GFX;
         // 10MB should be enough.
         for (byte i = 0; i < NBR_SIMPLIFIED_COUNTRY_GFX; i++) {
            // And each stack for that level
            for (uint32 j = 0; j < m_nbrGfxPolygons; j++) {
               // The number of elements of this stack.
               numElements += m_simplifiedGfxStack[i][j]->getStackSize();
            }
         }

         mc2dbg4 << "required stack size="<<4*numElements+12<<endl;

         DataBuffer* stackBuf = new DataBuffer(4*numElements + 12);

         // Write the number of bytes to follow (filled in later)
         stackBuf->writeNextLong(0);
         
         // Nbr levels of stack.
         stackBuf->writeNextLong(NBR_SIMPLIFIED_COUNTRY_GFX);

         // Nbr of polygons per level.
         stackBuf->writeNextLong(m_nbrGfxPolygons);
         // For each level.
         for (byte i = 0; i < NBR_SIMPLIFIED_COUNTRY_GFX; i++) {
            // And each stack for that level
            for (uint32 j = 0; j < m_nbrGfxPolygons; j++) {
               // The number of elements of this stack.
               Stack* curStack = m_simplifiedGfxStack[i][j];
               stackBuf->writeNextLong(curStack->getStackSize());
               // And write all elements
               for (uint32 k = 0; k < curStack->getStackSize(); k++) {
                  stackBuf->writeNextLong(curStack->getElementAt(k));
               }
            }
         }
         // Fill in size
         stackBuf->writeLong( stackBuf->getCurrentOffset() - 4, 0);
         write(outfile, 
               stackBuf->getBufferAddress(), 
               stackBuf->getCurrentOffset());
         delete stackBuf;
      }
      

   } else {
      mc2log << error << here << " Failed to save country overview map" 
             << endl;
   }

   return (retVal);
}
bool 
OldCountryOverviewMap::internalLoad(DataBuffer& dataBuffer)
{
   // Load the general map data
   bool retVal = OldGenericMap::internalLoad(dataBuffer);

   if (retVal) {
      // Read the number of countries
      uint32 nbrCountries = dataBuffer.readNextLong();
      if (nbrCountries > 0) {
         CLOCK_MAPLOAD(uint32 startTime = TimeUtility::getCurrentMicroTime());
         // Insert the mapID's into the m_mapsInCountry-array
         for (uint32 i=0; i<nbrCountries; i++) {
            struct mapnotice_t notice;
            notice.mapID = dataBuffer.readNextLong();
            notice.creationTime = dataBuffer.readNextLong();
            notice.maxLat = dataBuffer.readNextLong();
            notice.minLon = dataBuffer.readNextLong();
            notice.minLat = dataBuffer.readNextLong();
            notice.maxLon = dataBuffer.readNextLong();
            mc2dbg2 << "[COMap] Creation time(0x" << hex << notice.mapID 
                    << dec  << "):" << notice.creationTime << endl;
            m_mapsInCountry.push_back(notice);
            mc2dbg2 << "   Added map with ID=" << notice.mapID << endl;
         }
         CLOCK_MAPLOAD(mc2log << "[" << m_mapID << "] Countries read in "
                        << (TimeUtility::getCurrentMicroTime()-startTime)/1000.0
                        << " ms" << endl;
                 startTime = TimeUtility::getCurrentMicroTime());


         // Read the number of original IDs
         uint32 nbrOrigIDs = dataBuffer.readNextLong();

         // Read the original IDs of the items in this map
         mc2dbg2 << "To insert " << nbrOrigIDs << " original IDs" << endl;
         for (uint32 i=0; i<nbrOrigIDs; i++) {
            uint32 newID = dataBuffer.readNextLong();
            struct originalIDs_t origIDs;
            origIDs.origMapID = dataBuffer.readNextLong();
            origIDs.origItemID = dataBuffer.readNextLong();
            mc2dbg4 << "   ID: " << newID << " <==> " << origIDs.origMapID
                    << "." << origIDs.origItemID << endl;
            m_originalIDs.insert(make_pair(newID, origIDs));
         }
         CLOCK_MAPLOAD(mc2log << "[" << m_mapID << "] Orig IDs read in "
                        << (TimeUtility::getCurrentMicroTime()-startTime)/1000.0
                        << " ms" << endl;
                 startTime = TimeUtility::getCurrentMicroTime());

         // Create the simplified representation of the country gfxdata.
         // If it exists on disk, then read from there, otherwise filter.
         if ( (dataBuffer.getBufferSize() - dataBuffer.getCurrentOffset()) 
                  > 0) {
            // Read the size.(not used now)
             dataBuffer.readNextLong();
            // Ok, read from disk.
               
            // Nbr levels of stack.
            uint32 levelsOfStack = dataBuffer.readNextLong();

            // Nbr polygons per level.
            m_nbrGfxPolygons = dataBuffer.readNextLong();

            // Allocate stack matrix.
            m_simplifiedGfxStack = new Stack**[levelsOfStack];

            // For each level.
            for (byte i = 0; i < levelsOfStack; i++) {
               // And each stack for that level
               m_simplifiedGfxStack[i] = new Stack*[m_nbrGfxPolygons];
               for (uint32 j = 0; j < m_nbrGfxPolygons; j++) {
                  Stack* curStack = new Stack;
                  // The number of elements of this stack.
                  uint32 nbrElems = dataBuffer.readNextLong();
                  // And read all elements
                  for (uint32 k = 0; k < nbrElems; k++) {
                     curStack->push(dataBuffer.readNextLong());
                  }
                  m_simplifiedGfxStack[i][j] = curStack;
               }
            }
         } else {
            // Could not read from disk, filter now instead.
            mc2log << info << "OldCountryOverviewMap::internalLoad(), "
                   << "Error reading simplified representation of "
                   << "country gfxdata. Exits." << endl;
            //makeSimplifiedCountryGfx();
            exit(1);
         }
         CLOCK_MAPLOAD(mc2log << "[" << m_mapID << "] Country GfxData "
                        << "created/read in "
                        << (TimeUtility::getCurrentMicroTime()-startTime)/1000.0
                        << " ms" << endl;
                 startTime = TimeUtility::getCurrentMicroTime());
      } else {
bool
MapModuleNoticeContainer::load( DataBuffer& dataBuf, uint32 mapSet )
{
   dataBuf.readNextLong(); // old totalLength
   dataBuf.readNextLong(); // nbrMaps

   mc2dbg << "[MMNC]: Using new kind of index.db" << endl;
   // Format on disk begins with two 32-bit words with zeroes.
   // They should already have been read by load.
   // We should really implement version 0 here as well so that
   // we can remove the MapModuleObjVector.
   // Then comes length and version

   uint32 totalLength = dataBuf.readNextLong(); // length
   uint32 version  = dataBuf.readNextLong();
   uint32 nbrItems = dataBuf.readNextLong();

   if (dataBuf.getNbrBytesLeft() == 0) {
      // we must have some bytes left
      // TODO: check if nbr bytes left is at least 
      // = length * something...
      return false;
   }

   // Reset the internal structs.
   deleteAllObjs();
   
   // Version should only be 1 now.
   for ( uint32 i = 0; i < nbrItems; ++i ) {
      MapModuleNotice* notice = 
         new MapModuleNotice( &dataBuf, version, mapSet );
      // Add the notice to the appropriate vectors and maps.
      addNotice( notice );
      mc2dbg << "[MMNC]: Added MapModuleNotice for "
             << notice->getMapName() << endl;
   }

   // Read the map hierarchy
   m_mapTree.load( &dataBuf, mapSet );

   // Read the regions
   int nbrRegions = dataBuf.readNextLong();
   m_regions.clear();

   mc2dbg << "[MMNC]: Number of top regions:" << nbrRegions << endl;

   for ( int i = 0; i < nbrRegions; ++i ) {

      MapTopRegion* region = new MapTopRegion();
      region->load( &dataBuf, mapSet );

      m_regions[ region->getID() ] = region;
      const char* name = region->getName( LangTypes::english );

      if ( name == NULL ) {
         name = "NULL";
      }

      mc2dbg << "[MMNC]: Added Top Region ID:" << region->getID()
             << " name: " << name << endl;
   }
   
   // Read the region hierarchy
   m_regionTree.load( &dataBuf );

   // Read map supplier coverage data.
   mc2dbg8 << "Curr offset: " << dataBuf.getCurrentOffset()
           << " total length " << totalLength << endl;
   if (dataBuf.getCurrentOffset() < totalLength+12 ){
      mc2dbg << "[MMNC]: Loading map supplier coverage." << endl;
      loadMapSupCoverage( &dataBuf );
      mc2dbg << "[MMNC]: Done loading map supplier coverage." << endl;
   }
   else {
      mc2dbg << "[MMNC]: Not loading map supplier coverage." << endl;
   }

#ifdef DEBUG_LEVEL_1
   //
   // debug
   //
   for(uint32 i = 0; i < m_allNotices.size(); ++i ) {
      mc2dbg << "Overview maps for " << m_allNotices[i]->getMapID()
             << endl;
      vector<uint32> overviewIDs;
      m_mapTree.getOverviewMapsFor(m_allNotices[i]->getMapID(),
                                   overviewIDs);
      for(uint32 j = 0; j < overviewIDs.size(); ++j ) {
         mc2dbg << "    " << j << "=" << overviewIDs[j] << endl;
      }
   }

   {
      // Print stuff
      mc2dbg << "MAP_HIERARCHY" << endl;
      set<uint32> mapIDs;
      m_mapTree.getTopLevelMapIDs(mapIDs);
      for(set<uint32>::const_iterator it = mapIDs.begin();
          it != mapIDs.end();
          ++it) {
         mc2dbg << "TopLevelMap :" << hex << *it << dec << " contains " 
                << endl;
         set<IDPair_t> items;
         m_mapTree.getContents(*it, items);
         for( set<IDPair_t>::iterator it = items.begin();
              it != items.end();
              ++it ) {
            mc2dbg << "      " << it->getMapID() << ":" << hex
                   << it->getItemID() << dec << endl;
         }
      }
   }

   // Print stuff
   mc2dbg << "REGION_HIERARCHY" << endl;
   set<uint32> mapIDs;
   m_regionTree.getTopLevelRegionIDs(mapIDs);
   for(set<uint32>::const_iterator it = mapIDs.begin();
       it != mapIDs.end();
       ++it) {
      mc2dbg << "TopLevelRegion : " 
             << getRegion( *it )->getNames()
                  ->getBestName( LangTypes::swedish )->getName()
             << " " << *it << endl;
      
      const ItemIDTree& idTree = getRegion( *it )->getItemIDTree();
      set<uint32> mapIDs;
      mc2dbg << " consists of the following items:" << endl;
      idTree.getTopLevelMapIDs( mapIDs );
      for ( set<uint32>::const_iterator jt = mapIDs.begin();
            jt != mapIDs.end(); ++jt ) {
         mc2dbg << " map id = " << *jt << endl;
         set<IDPair_t> items;
         idTree.getContents( *jt, items );
         for ( set<IDPair_t>::const_iterator kt = items.begin();
               kt != items.end(); ++kt ) {
            mc2dbg << "   [" << kt->first << ", " << kt->second << "]"
                   << endl;
         }
      }
      
      
      mc2dbg << " contains the following other regions: " << endl;
      set<uint32> items;
      m_regionTree.getContents(*it, items);
      for( set<uint32>::iterator jt = items.begin();
           jt != items.end();
           ++jt ) {
         mc2dbg << "      " << *jt << endl;
      }
   }

   //
   // end debug
   //   
#endif // DEBUG_LEVEL_1

   return true;
}
void
IDTranslationTable::loadOld(DataBuffer& dataBuffer, uint32 mapSet) {

   // Nbr elements in the table or tables
   uint32 size = dataBuffer.readNextLong();

   mc2dbg << "Loading old id translation table size = " << size << endl;

   m_lookupTable.clear();
   m_lookupTable.reserve( size );
   uint32 version = MAX_UINT32 - dataBuffer.readLong(dataBuffer.getCurrentOffset());

   // if we have version above 100....this should be enough to indicate
   // that the buffer value is MapID
   if ( version < MAX_UINT32 - 100 )
      version++;
   else
      version = 0;

   mc2dbg << "Loading old id table version = " << version << endl;

   // Chck if we have one or several tables in the databuffer
   if ( version == 1 ) {
      // TWO tables
      mc2dbg << "[IDT] To create IDTranslationTable from "
             << "databuffer with TWO tables, size: " << size << endl;
      dataBuffer.readNextLong();   // Skip flag
      
      // Read and ignore elements for reverseTable
      for (uint32 i=0; i < size; i++) {
         dataBuffer.readNextLong(); // mapID
         dataBuffer.readNextLong(); // itemID
         dataBuffer.readNextLong(); // overviewItemID
      }

      // Read and insert the elements into the lookup table
      for (uint32 i=0; i < size; i++) {

         uint32 tmpMapID = dataBuffer.readNextLong();

         if (mapSet != MAX_UINT32)
            tmpMapID = MapBits::getMapIDWithMapSet(tmpMapID, mapSet);

         const uint32 tmpItemID = dataBuffer.readNextLong();
         const uint32 tmpOverviewItemID = dataBuffer.readNextLong();

         m_lookupTable.push_back(
            lookupElement_t(tmpOverviewItemID, 
                            IDPair_t(tmpMapID, tmpItemID) ) );
      }
      // setup and sort reverse table
      sortReverseTable();   
  
   } else if ( version == 2 ) {
      dataBuffer.readNextLong();   // Skip flag

      m_reverseLookupTable.resize( size );

      // Read and insert the elements into the lookup tables
      for ( uint32 i = 0; i < size; ++i ) {
         uint32 tmpMapID = dataBuffer.readNextLong();
         const uint32 tmpItemID = dataBuffer.readNextLong();
         const uint32 tmpOverviewItemID = dataBuffer.readNextLong();
         m_reverseLookupTable[ i ] = dataBuffer.readNextLong();

         if ( mapSet != MAX_UINT32 )
            tmpMapID = MapBits::getMapIDWithMapSet(tmpMapID, mapSet);


         addElement(tmpOverviewItemID, tmpMapID, tmpItemID);


      }
      
   } else if ( version == 0 ) {
      // "Normal", one table..
      
      mc2log << "[IDTranslationTable]: Reading ONE table, size = "
             << size << endl;
      
      // Read and insert the elements into the lookup tables
      // Must be sorted as in m_reverseLookupTable
      for (uint32 i=0; i < size; ++i) {
         uint32 tmpMapID = dataBuffer.readNextLong();
         if (mapSet != MAX_UINT32)
            tmpMapID = MapBits::getMapIDWithMapSet(tmpMapID, mapSet);
         const uint32 tmpItemID = dataBuffer.readNextLong();
         const uint32 tmpOverviewItemID = dataBuffer.readNextLong();
         addElement(tmpOverviewItemID, tmpMapID, tmpItemID);
      }

      // setup and sort reverse table
      sortReverseTable();
   }
   

}
int
ParserCWHandler::getURL( const MC2String& urlStr, 
                         const MC2String& postData,
                         uint32 peerIP, uint32 fromByte, uint32 toByte,
                         LangTypes::language_t clientLang,
                         const HttpHeader* inHeaders,
                         HttpHeader& outHeaders, MC2String& reply,
                         uint32& startByte, uint32& endByte )
{
   uint32 startTime = TimeUtility::getCurrentTime();

   // Work with url
   MC2String serverURLStr( urlStr );
   mc2dbg2 << "serverURLStr " << serverURLStr << endl;
   updateRequest( serverURLStr, clientLang );

   bool fetchedThruProxy = false;
   if ( serverURLStr.find( "://sendThruProxyServer" ) != MC2String::npos ) {
      // This url should be fetched thru the proxy server
      
      // Remove 'sendThruProxyServer' from URL
      STLStringUtility::replaceString( serverURLStr, 
                                       "://sendThruProxyServer/",
                                       "://" );

      URL url(serverURLStr);
      HttpBody outBody;
      HttpVariableContainer myVar;
      myVar.https = ( serverURLStr.find( "https://" ) != MC2String::npos );
      
      // Fetch the url thru proxy server. If proxy fails it will be fetched without
      // proxy below.
      fetchedThruProxy =
         HttpProxyFunctions::fetchThruProxy( url, &outHeaders, &outBody, m_thread, &myVar );
      if ( fetchedThruProxy ) {
         // Successfully fetched thru proxy
         reply.append( outBody.getBody(), outBody.getBodyLength() );      
      } 
   }
   
   // Work with url
   mc2dbg2 << "serverURLStr " << serverURLStr << endl;
   updateRequest( serverURLStr, clientLang );
   URL url2( serverURLStr );
   int ures = 0;
   uint32 timeout = Properties::getUint32Property( "CW_TIMEOUT", 
                                                   5000 );
   
   if ( ! fetchedThruProxy ) {
      if ( serverURLStr.find( "internalInThisProcess" ) != MC2String::npos ) {
         // Handle internally
         reply.clear();
         if ( serverURLStr.find("/TMap/") != MC2String::npos ) {
            MC2String urlParam = STLStringUtility::basename( url2.getFile() );
            if ( !urlParam.empty() ) {
               DataBuffer* d = m_thread->getTileMap( urlParam.c_str() );
               if ( d != NULL ) {
                  ures = 200;
                  reply.append( reinterpret_cast<char*>( d->getBufferAddress() ),
                                d->getCurrentOffset() );
                  outHeaders.setStartLine( 200 );
               } else {
                  outHeaders.setStartLine( 503 );
               }
               delete d;
            }
         }
      }  else {
         // Send request using the parserthreads urlfetcher
         URLFetcher* f = m_thread->getURLFetcher();
         HttpHeader sendHeaders; // Extra headers to send
         // TODO: Add byterange using fromByte and toByte if not 0,MAX_UINT32
         //       so we don't download whole file all the time.
         MC2String peerIPstr = NetUtility::ip2str( peerIP );
         sendHeaders.addHeaderLine( "X-Forwarded-For", peerIPstr );
         
         static const MC2String notForwardHeadersStr[] = {
            "X-WAYF-CT",
            HttpHeaderLines::CONTENT_TYPE,
            HttpHeaderLines::CONTENT_LENGTH,
            HttpHeaderLines::CONNECTION,
            HttpHeaderLines::TRANSFER_ENCODING,
            HttpHeaderLines::X_FORWARDED_FOR,
            HttpHeaderLines::PROXY_CONNECTION,
            HttpHeaderLines::HOST,
            HttpHeaderLines::TE,
            HttpHeaderLines::TRAILER,
            HttpHeaderLines::KEEP_ALIVE,
            HttpHeaderLines::PROXY_AUTHENTICATE,
            HttpHeaderLines::PROXY_AUTHORIZATION,
            HttpHeaderLines::UPGRADE,
         };
         // TODO: Also remove all headers in Connection: header. Like
         //       "Connection: Keep-Alive, Trailer" should delete those two.
         static const set< MC2String, strNoCaseCompareLess > notForwardHeaders( 
            BEGIN_ARRAY( notForwardHeadersStr ), 
            END_ARRAY( notForwardHeadersStr ) );
         
         if ( inHeaders != NULL ) {
            const HttpHeader::HeaderMap& headers = inHeaders->getHeaderMap();
            for ( HttpHeader::HeaderMap::const_iterator it = headers.begin() ;
                  it != headers.end() ; ++it ) {
               if ( notForwardHeaders.find( it->first ) == 
                    notForwardHeaders.end() ) {
                  sendHeaders.addHeaderLine( it->first, *it->second );
               }
            }
         }
         
         if ( postData.empty() ) {
            ures = f->get(  reply, outHeaders, url2, 
                            timeout, &sendHeaders );
         } else {
            if ( inHeaders->getHeaderValue( "X-WAYF-CT" ) != NULL ) {
               sendHeaders.addHeaderLine( 
                  HttpHeaderLines::CONTENT_TYPE,
                  *inHeaders->getHeaderValue( "X-WAYF-CT" ) );
            } else {
               sendHeaders.addHeaderLine( 
                  HttpHeaderLines::CONTENT_TYPE, 
                  "application/x-www-form-urlencoded" );
            }
            ures = f->post( reply, outHeaders, url2, postData, 
                            timeout, &sendHeaders );
         }
         // Reset user agent
         //f->setDefaultUserAgent();
      }
   } // if (! fetchedThruProxy )
   
   // Remove chunked-encoding from reply (if present)
   const MC2String teh( "Transfer-Encoding" );
   const MC2String* te = outHeaders.getHeaderValue( &teh );
   if ( te != NULL && ( te->find( "chunked") != MC2String::npos ) ) {
      outHeaders.deleteHeaderLine( &teh );
   }
      
   // Check if web updated user
   const MC2String wfidh( "X-WFID-UPDATE" );
   const MC2String* wfid = outHeaders.getHeaderValue( &wfidh );
   if ( wfid != NULL ) {
      // Remove the uin from user cache
      uint32 uin = STLStringUtility::strtoul( *wfid );
      m_group->removeUserFromCache( uin );

      // And remove the header
      outHeaders.deleteHeaderLine( &wfidh );
   }

   // Make reply
   const MC2String eol( "\r\n" );
   if ( fromByte > toByte ) {
      toByte = fromByte;
   }
   const uint32 maxBytes = toByte - fromByte;
   uint32 lastByte = uint32( MAX( int32(reply.size()) - 1, 0 ) );
   startByte = MIN( fromByte, lastByte );
   endByte = startByte + MIN( lastByte - startByte, maxBytes );

   if ( ures > 0 && reply.size() > 0 && 
        (endByte != lastByte || startByte != 0) ) 
   {
      // Set byte range in reply
      MC2String rangeStr( "bytes " );
      STLStringUtility::uint2str( startByte, rangeStr );
      rangeStr.append( "-" );
      STLStringUtility::uint2str( endByte, rangeStr );
      rangeStr.append( "/" );
      STLStringUtility::uint2str( reply.size(), rangeStr ); // Real size
      outHeaders.addHeaderLine( "Content-Range", rangeStr );
      rangeStr = "";
      STLStringUtility::uint2str( endByte - startByte + 1, rangeStr );
      // Set right content length
      outHeaders.addHeaderLine( "Content-Length", rangeStr );
      // Set startline with 206 Partial Content
      MC2String responce( outHeaders.getStartLine()->substr( 0, 9 ) );
      responce.append( "206 Partial Content" );
      responce.append( eol );
      outHeaders.setStartLine( new MC2String( responce ) );
   } else if ( ures < 0 || outHeaders.getStartLine() == NULL ) {
      if ( TimeUtility::getCurrentTime() - startTime >= timeout ) {
         outHeaders.setStartLine( 503 );
      } else {
         outHeaders.setStartLine( 500 );
      }
   } else {
      // Set startline with eol
      outHeaders.setStartLine( 
         new MC2String( StringUtility::trimStartEnd( 
                           *outHeaders.getStartLine() ) + eol ) );
   }

   return ures;
}