/*=========================================================================

  Program:   CMake - Cross-Platform Makefile Generator
  Module:    $RCSfile$
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.

     This software is distributed WITHOUT ANY WARRANTY; without even 
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#ifndef cmGeneratedFileStream_h
#define cmGeneratedFileStream_h

#include "cmStandardIncludes.h"
#include "cmSystemTools.h"

/** \class cmGeneratedFileStream
 * \brief Output stream for generated files that does copy-if-different.
 *
 * Many files generated by CMake don't change each time they are generated.
 * This class can be used in place of std::ofstream to open a file and
 * write output to it.  The class will automatically write output to a
 * temporary file and copy it over an existing file only if the generated
 * file has changed.
 */
class cmGeneratedFileStream
{
public:
  /**
   * The constructor takes the name of the file to be generated.  It
   * automatically generates a name for the temporary file.
   */
  cmGeneratedFileStream(const char* name):
    m_Name(name),
    m_TempName(m_Name+".tmp"),
    m_Stream(m_TempName.c_str()),
    m_Copied(false),
    m_AlwaysCopy(false)
    {}
  
  /**
   * The destructor ensures that the file has been closed and copied if
   * it has changed.
   */
  ~cmGeneratedFileStream() { this->DoCopy(); }
  
  /**
   * Get the real output stream.
   */
  std::ostream& GetStream() { return m_Stream; }
  
  /**
   * Allow a test for whether the file is open.
   */
  operator bool() { return m_Stream.good(); }
  
  /**
   * Close the file stream.  This will cause the copy-if-different to the
   * real file name to occur.
   */
  void close() { this->DoCopy(); }
  /**
   * If always copy is true, then copy the file all the time without
   *  checking for differences.  The default is false.
   */
  bool SetAlwaysCopy(bool v) { m_AlwaysCopy = v; return v;}
private:
  /**
   * The name of the real file where output will be copied if it has changed.
   */
  std::string m_Name;
  
  /**
   * The name of the temporary file.
   */
  std::string m_TempName;
  
  /**
   * The real output stream used to write to the file.
   */
  std::ofstream m_Stream;
  
  /**
   * Whether the temporary file has already been copied to the real file.
   */
  bool m_Copied;

  /**
   *  If always copy is true, then copy the file all the time without
   *  checking for differences.  The default is false.
   */
  bool m_AlwaysCopy;
  
  /**
   * Closes the temporary file and does the copy-if-different to the
   * real file.
   */
  void DoCopy()
    {
    if(!m_Copied)
      {
      m_Stream.close();
      if(m_AlwaysCopy)
        {
        cmSystemTools::cmCopyFile(m_TempName.c_str(), m_Name.c_str());
        }
      else
        {
        cmSystemTools::CopyFileIfDifferent(m_TempName.c_str(),
                                           m_Name.c_str());
        }
      cmSystemTools::RemoveFile(m_TempName.c_str());
      m_Copied = true;
      }
    }
};


/**
 * Allow a cmGeneratedFileStream to be used just as a real std::ostream
 * would be.
 */
template <class T>
std::ostream& operator << (cmGeneratedFileStream& l, const T& r)
{
  std::ostream& os = l.GetStream();
  os << r;
  return os;
}



#endif
