text: // ==========================================================================
  //                 SeqAn - The Library for Sequence Analysis
  // ==========================================================================
  // Copyright (c) 2006-2010, Knut Reinert, FU Berlin
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without
  // modification, are permitted provided that the following conditions are met:
  //
  //     * Redistributions of source code must retain the above copyright
  //       notice, this list of conditions and the following disclaimer.
  //     * Redistributions in binary form must reproduce the above copyright
  //       notice, this list of conditions and the following disclaimer in the
  //       documentation and/or other materials provided with the distribution.
  //     * Neither the name of Knut Reinert or the FU Berlin nor the names of
  //       its contributors may be used to endorse or promote products derived
  //       from this software without specific prior written permission.
  //
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  // ARE DISCLAIMED. IN NO EVENT SHALL KNUT REINERT OR THE FU BERLIN BE LIABLE
  // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  // DAMAGE.
  //
  // ==========================================================================
  
  #ifndef SEQAN_HEADER_FILE_ARRAY_H
  #define SEQAN_HEADER_FILE_ARRAY_H
  
  #include <sstream>
  #include <iomanip>
  
  
  //////////////////////////////////////////////////////////////////////////////
  
  namespace SEQAN_NAMESPACE_MAIN
  {
  
  	//template < __int64 FILE_SIZE = 2*1024*1024*1024-1, typename TFile = File<> >
  	//struct Chained;
  
  	//template < unsigned FileCount_ = 2, typename TFile = File<> >
  	//struct Striped;
  
  
      template < __int64 FILE_SIZE, typename TFile >
      struct Size< File< Chained<FILE_SIZE, TFile> > >
      {
          typedef __int64 Type;
      };
  
      template < __int64 FILE_SIZE, typename TFile >
      struct Position< File< Chained<FILE_SIZE, TFile> > >
      {
          typedef __int64 Type;
      };
  
      template < __int64 FILE_SIZE, typename TFile >
      struct Difference< File< Chained<FILE_SIZE, TFile> > >
      {
          typedef __int64 Type;
      };
  
      template < __int64 FILE_SIZE, typename TFile >
      struct AsyncRequest< File< Chained<FILE_SIZE, TFile> > >
      {
  		typedef typename AsyncRequest<TFile>::Type Type;
      };
  
  
      template < unsigned FileCount_, typename TFile >
      struct Size< File< Striped<FileCount_, TFile> > >
      {
          typedef __int64 Type;
      };
  
      template < unsigned FileCount_, typename TFile >
      struct Position< File< Striped<FileCount_, TFile> > >
      {
          typedef __int64 Type;
      };
  
      template < unsigned FileCount_, typename TFile >
      struct Difference< File< Striped<FileCount_, TFile> > >
      {
          typedef __int64 Type;
      };
  
      template < unsigned FileCount_, typename TFile >
      struct AsyncRequest< File< Striped<FileCount_, TFile> > >
      {
  		typedef typename AsyncRequest<TFile>::Type Type;
      };
  
  
  	template < unsigned FileCount_, typename TFile >
  	class File< Striped<FileCount_, TFile> >: public Tuple< TFile, FileCount_ > {
  		File(void * /*dummy = NULL*/) {}	// to be compatible with the FILE*(NULL) constructor
  		operator bool() const { return (*this)[0]; }
  	};
  
      template < __int64 FILE_SIZE, typename TFile >
  	class File< Chained<FILE_SIZE, TFile> >: public String< TFile > {
  		typedef String< TFile > Base;
  
  		::std::string	baseName;
  		int				openMode;
  		__int64			fileSize;
  		bool			temporary;
  
  		File(void * /*dummy = NULL*/) :	// to be compatible with the FILE*(NULL) constructor
  			fileSize(0),
  			_realign(false) {}
  
  	private:
  		
  		bool _realign;
  	
  		template < typename TSize, typename TValue >
  		inline void _alignFloor(TSize _size, TValue const *) {
  			__int64 alignment = sizeof(TValue) * sectorSize(TFile());
  			fileSize = (_size / alignment) * alignment;
  		}
  
  		template < typename TSize, typename TValue >
  		inline void _alignCeil(TSize _size, TValue const *) {
  			__int64 alignment = sizeof(TValue) * sectorSize(TFile());
  			fileSize = ((_size + alignment - 1) / alignment) * alignment;
  		}
  
  	public:
  	
  		inline ::std::string getFileName(int i) const { 
  			::std::stringstream strm;
  			strm << baseName << '.' << ::std::setfill('0') << ::std::setw(3) << i;
  			return strm.str();
  		}
  
  		inline operator bool() const { 
  			return (*this)[0]; 
  		}
  
  		inline unsigned fileCount() const {
  			return length(*(Base*)this);
  		}
  
  		inline TFile& getFile(int fileNo) {
  			unsigned _oldFileCount = fileCount();
  			if (fileNo > 0 && static_cast<unsigned>(fileNo) >= _oldFileCount) {
  				resize(*(Base*)this, fileNo + 1);
  				for(unsigned i = _oldFileCount; i <= static_cast<unsigned>(fileNo); ++i)  // Cast OK since fileNo > 0 checked above.
  					if (temporary)
  						openTemp((*this)[i], openMode);
  					else
  						open((*this)[i], getFileName(i).c_str(), openMode);
  			}
  			return (*this)[fileNo];
  		}
  
  		inline void tryOpen() {
  			unsigned fileCount = 0;
  			while (fileExists(getFileName(fileCount).c_str())) ++fileCount;
  			if (fileCount) {
  				fileSize = size(getFile(0));
  				_realign = (fileCount == 1);
  				getFile(fileCount - 1);
  			} 
  		}
  
  		// fileSize dependent functions
  
  		template < typename TValue >
  		inline void adjustFileSize(TValue const *dummy) {
  			if (_realign) {
  				_alignCeil(fileSize, dummy);
  				_realign = false;
  				if (fileSize < FILE_SIZE)
  					fileSize = 0;
  			}
  			if (!fileSize) 
  				_alignFloor(FILE_SIZE, dummy);
  		}
  
  		template < typename TPos, typename TOffset, typename TValue >
  		inline TFile& getFileAndOffset(TPos offset, TOffset &fileOffset, TValue const *dummy) {
  			adjustFileSize(dummy);
  			offset *= sizeof(TValue);
  			fileOffset = (offset % fileSize) / sizeof(TValue);
  			return getFile(offset / fileSize);
  		}
  
  		template < typename TOffset, typename TValue >
  		inline __int64 restAt(TOffset fileOffset, TValue const *dummy) {
  			adjustFileSize(dummy);
  			__int64 restBytes = fileSize;
  			restBytes -= fileOffset * sizeof(TValue);
  			return restBytes / sizeof(TValue);
  		}
  
  		inline void resizeArray(__int64 _newSize) {
  			if (fileSize) {
  				unsigned _oldFileCount = fileCount();
  				unsigned _newFileCount = enclosingBlocks(_newSize, fileSize);
  				for(unsigned i = _newFileCount; i < _oldFileCount; ++i) {
  					close((*this)[i]);
  					if (!temporary) fileUnlink(getFileName(i).c_str());
  				}
  				resize(*(Base*)this, _newFileCount);
  				if (_newFileCount) {
  					typename Size<TFile>::Type lastFileSize = _newSize % fileSize;
  					if (fileSize) resize((*this)[_newFileCount - 1], lastFileSize);
  				}
  			}
  		}
  
          inline void clearInternals() {
  			clear(*(Base*)this);
              fileSize = 0;
              _realign = false;
  		}
  	};
  
  
      //////////////////////////////////////////////////////////////////////////////
      // generic open/close interface
      template < typename TFileArray >
      inline bool _openTempFArray(TFileArray &me, int openMode) {
  		bool result = true;
  		for(int i = 0; i < length(me); ++i)
  			result &= openTemp(me[i], openMode);
  		return result;
      }
  
      template < typename TFileArray >
      inline bool _openTempFArray(TFileArray &me) {
  		return _openTempFArray(me, DefaultOpenTempMode<TFileArray>::VALUE);
  	}
  
      template < typename TFileArray >
      inline bool _reopenFArray(TFileArray &me, int openMode) {
  		bool result = true;
  		for(int i = 0; i < length(me); ++i)
  			result &= reopen(me[i], openMode);
  		return result;
      }
  
      template < typename TFileArray >
      inline bool _closeFArray(TFileArray &me) {
  		bool result = true;
  		for(int i = 0; i < length(me); ++i)
  			if (me[i]) result &= close(me[i]);
  		return result;
      }
  
      template < typename TFileArray >
      inline unsigned _sectorSizeFArray(TFileArray &me, int /*openMode*/) {
  		return sectorSize(me[0]);
      }
  
      template < typename TFileArray >
      inline typename Size<TFileArray>::Type
  	_sizeFArray(TFileArray &me) {
          typename Size<TFileArray>::Type sum = 0;
  		for(int i = 0; i < length(me); ++i)
  			sum += size(me[i]);
  		return sum;
      }
  
      template < typename TFileArray >
      inline bool _flushFArray(TFileArray &me) {
  		bool result = true;
  		for(int i = 0; i < length(me); ++i)
  			result &= flush(me[i]);
  		return result;
      }
  
      template < typename TFileArray, typename TRequest >
      inline bool _cancelFArray(TFileArray &me, TRequest &request) {
  		bool result = true;
  		for(int i = 0; i < length(me); ++i)
  			result &= cancel(me[i], &request);
  		return result;
      }
  
  
      //////////////////////////////////////////////////////////////////////////////
      // standard file array wrappers
  
      template < __int64 FILE_SIZE, typename TFile >
  	inline unsigned length(File< Chained<FILE_SIZE, TFile> > const &me) {
  		return me.fileCount();
  	}
  
      template < unsigned FileCount_, typename TFile >
  	inline unsigned length(File< Striped<FileCount_, TFile> > const &/*me*/) {
  		return FileCount_;
  	}
  
      template < __int64 FILE_SIZE, typename TFile >
  	inline bool open(File< Chained<FILE_SIZE, TFile> > &me, const char *fileName, int openMode) {
  		me.baseName = fileName;
  		me.openMode = openMode;
  		me.temporary = false;
  		me.tryOpen();
  		return true;
  	}
  
      template < __int64 FILE_SIZE, typename TFile >
  	inline bool openTemp(File< Chained<FILE_SIZE, TFile> > &me, int openMode) {
  		me.openMode = openMode;
  		me.temporary = true;
  		return true;
  	}
  
      template < unsigned FileCount_, typename TFile >
  	inline bool openTemp(File< Striped<FileCount_, TFile> > &me, int openMode) {
  		return _openTempFArray(me, openMode);
  	}
  
      template < __int64 FILE_SIZE, typename TFile >
  	inline bool close(File< Chained<FILE_SIZE, TFile> > &me) {
          _closeFArray(me);
          me.clearInternals();
          return true;
      }
  
      template < unsigned FileCount_, typename TFile >
  	inline bool close(File< Striped<FileCount_, TFile> > &me) {	return _closeFArray(me); }
  
      template < __int64 FILE_SIZE, typename TFile >
  	__int64 size(File< Chained<FILE_SIZE, TFile> > &me) {
  		return _sizeFArray(me);
  	}
  
      template < unsigned FileCount_, typename TFile >
  	__int64 size(File< Striped<FileCount_, TFile> > &me) {
  		return _sizeFArray(me);
  	}
  
      template < __int64 FILE_SIZE, typename TFile, typename TSize >
      inline void resize(File< Chained<FILE_SIZE, TFile> > &me, TSize new_length) {
  		me.resizeArray(new_length);
      }
  
      template < __int64 FILE_SIZE, typename TFile, typename TValue, typename TSize >
  	inline void allocate(File< Chained<FILE_SIZE, TFile> > const &me, TValue* &data, TSize count) {
  		allocate(me[0], data, count);
  	}
  
      template < __int64 FILE_SIZE, typename TFile, typename TValue, typename TSize >
  	inline void deallocate(File< Chained<FILE_SIZE, TFile> > const &me, TValue* &data, TSize count) {
  		deallocate(me[0], data, count);
  	}
  
      template < unsigned FileCount_, typename TFile, typename TValue, typename TSize >
  	inline void allocate(File< Striped<FileCount_, TFile> > const &me, TValue* &data, TSize count) {
  		allocate(me[0], data, count);
  	}
  
      template < unsigned FileCount_, typename TFile, typename TValue, typename TSize >
  	inline void deallocate(File< Striped<FileCount_, TFile> > const &me, TValue* &data, TSize count) {
  		deallocate(me[0], data, count);
  	}
  
  
      //////////////////////////////////////////////////////////////////////////////
      // read/write wrappers
  
      template < __int64 FILE_SIZE, typename TFile, typename TValue, typename TSize, typename TOffset >
      inline bool readAt(File< Chained<FILE_SIZE, TFile> > &me, TValue *memPtr, TSize count, TOffset offset) {
  		TOffset fileOfs = 0;
  		while (count) {
  			TFile &file = me.getFileAndOffset(offset, fileOfs, memPtr);
  			TSize xmitSize = _min(me.restAt(fileOfs, memPtr), (__int64)count);
  			if (!readAt(file, memPtr, xmitSize, fileOfs)) return false;
  			count -= xmitSize;
  			offset += xmitSize;
  			memPtr += xmitSize;
  		}
  		return true;
      }
      
      template < __int64 FILE_SIZE, typename TFile, typename TValue, typename TSize, typename TOffset >
      inline bool writeAt(File< Chained<FILE_SIZE, TFile> > &me, TValue const *memPtr, TSize count, TOffset offset) {
  		TOffset fileOfs = 0;
  		while (count) {
  			TFile &file = me.getFileAndOffset(offset, fileOfs, memPtr);
  			TSize xmitSize = _min(me.restAt(fileOfs, memPtr), (__int64)count);
  			if (!writeAt(file, memPtr, xmitSize, fileOfs)) return false;
  			count -= xmitSize;
  			offset += xmitSize;
  			memPtr += xmitSize;
  		}
  		return true;
      }
  
      template < __int64 FILE_SIZE, typename TFile, typename TValue, typename TSize, typename TOffset, typename TRequest >
      inline bool asyncReadAt(File< Chained<FILE_SIZE, TFile> > &me, TValue *memPtr, TSize count, TOffset offset, TRequest &req) {
  		TOffset fileOfs = 0;
  		while (count) {
  			TFile &file = me.getFileAndOffset(offset, fileOfs, memPtr);
  			TSize xmitSize = _min(me.restAt(fileOfs, memPtr), (__int64)count);
  			if (count != xmitSize) {
  				if (!readAt(file, memPtr, xmitSize, fileOfs)) return false;
  			} else
  				if (!asyncReadAt(file, memPtr, xmitSize, fileOfs, req)) return false;
  			count -= xmitSize;
  			offset += xmitSize;
  			memPtr += xmitSize;
  		}
  		return true;
      }
      
      template < __int64 FILE_SIZE, typename TFile, typename TValue, typename TSize, typename TOffset, typename TRequest  >
      inline bool asyncWriteAt(File< Chained<FILE_SIZE, TFile> > &me, TValue const *memPtr, TSize count, TOffset offset, TRequest &req) {
  		TOffset fileOfs = 0;
  		while (count) {
  			TFile &file = me.getFileAndOffset(offset, fileOfs, memPtr);
  			TSize xmitSize = _min(me.restAt(fileOfs, memPtr), (__int64)count);
  			if (count != xmitSize) {
  				if (!writeAt(file, memPtr, xmitSize, fileOfs)) return false;
  			} else
  				if (!asyncWriteAt(file, memPtr, xmitSize, fileOfs, req)) return false;
  			count -= xmitSize;
  			offset += xmitSize;
  			memPtr += xmitSize;
  		}
  		return true;
      }
  
  }
  
  #endif
  