/**
 * @file form_out_stream.h
 *
 * FormOutStream - Stream class for specially formatted text output.
 *
 * Copyright: 2002-2003 Thomas Wintergerst. All rights reserved.
 *
 * $FreeBSD$
 * $Id: form_out_stream.h,v 1.1.2.1 2006/02/28 21:35:42 thomas Exp $
 * Project  CAPI for BSD
 * Target   capitrace - Tracing CAPI calls and messages
 * @date    01.12.2002
 * @author  "Thomas Wintergerst" <twinterg@gmx.de>
 * <p>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 THE AUTHOR OR CONTRIBUTORS 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.
 *
 * </p>
 */

#include <iostream>
#include <sstream>
#include <fstream>

#ifndef __FORM_OUT_STREAM_H
#define __FORM_OUT_STREAM_H





// === Public declarations ===============================================





// === Class declarations ================================================





/**
 * Stream class for specially formatted text output.
 */
class CFormOutStream: public std::ostringstream
{
   public:
      /**
       * Constructor.
       */
      CFormOutStream (void);
      
      /**
       * Destructor.
       */
      ~CFormOutStream (void);
      
      /**
       * Switch output to a regular file.
       */
      void open
         (const char         *pszFileName,
          std::ios::openmode  mode = std::ios::out | std::ios::trunc,
          int                 iProt = 0664);
      
      /**
       * Switch output back to cout.
       */
      void close (void);
      
      /**
       * Query if output is redirected to a regular file.
       */
      bool is_open (void);
      
      /**
       * Start a new line with formatting.
       *
       * This function assumes the internal stream buffer is filled with a
       * single line of output (not ending with a cr, lf or eos). According to
       * the current settings for the left and right margin the line is written
       * to the current output stream (the file stream member or cout if the
       * file stream is not open).
       *
       * First as many spaces as the left margin is set to are written to the
       * output stream. If the right margin is set to a position right of the
       * left margin (i.e. it is greater than the left margin) the line will be
       * separated into parts (hopefully) fitting into the margin settings. We
       * start searching for a whitespace character from the right margin string
       * position to the beginning. If none is found the search goes right to
       * the next whitespace character. At the position found this way we insert
       * a newline character into the line string. The remaining characters of
       * the line are print the same way between the two margins.
       *
       * @param None.
       *
       * @return The reference to this stream object.
       */
      std::ostream &newl (void);
      
      /**
       * Set the left margin for the current output line.
       */
      void leftmargin
         (unsigned uNewMargin,
          bool     fDelayed = false);
      
      /**
       * Read the current left margin setting.
       */
      unsigned leftmargin (void);

      /**
       * Set the right margin for the current output line.
       */
      void rightmargin
         (unsigned uNewMargin);
      
      /**
       * Read the current right margin setting.
       */
      unsigned rightmargin (void);

      /**
       * Perform a hex dump output.
       */
      void hexdump
         (const void *pData,
          size_t      nLenData);
      
      /**
       * Print out an array of bytes as a byte sequence.
       */
      void byte_sequence
         (const void *pData,
          size_t      nLenData);
   
   
   
   protected:
      /// The file stream to write the data into if it is opened.
      std::ofstream m_ofs;
      
      /// The current setting for the left margin.
      unsigned m_uLeftMargin;
      
      /// The left margin setting to use after the next newl call if
      /// m_fLeftMarginDelayed is true.
      unsigned m_uNextLeftMargin;
      
      /// If this member is true, there is a new setting for the left margin
      /// that shall be enabled after the next newl call.
      bool m_fLeftMarginDelayed;
      
      /// The current setting for the right margin.
      unsigned m_uRightMargin;
      
      
      
      /**
       * Find the separation position in a line string.
       */
      size_t find_separator_pos
         (const std::string &line,
          size_t             nMargin);
      
      /**
       * Write out a string line to the current output stream.
       */
      void write_string
         (const std::string &line);
   
   
   
   private:
   
   
   
}; // CFormOutStream





/**
 * Helper class to save and restore a stream output configuration.
 */
class CStreamConfigGuard
{
   public:
      /**
       * Constructor.
       */
      CStreamConfigGuard
         (CFormOutStream &os):
         m_os (os)
         {
            m_Flags        = os.flags ();
            m_cFill        = os.fill ();
            m_uLeftMargin  = os.leftmargin ();
            m_uRightMargin = os.rightmargin ();
         }
      
      /**
       * Destructor.
       */
      ~CStreamConfigGuard (void)
         {
            m_os.flags (m_Flags);
            m_os.fill (m_cFill);
            m_os.leftmargin (m_uLeftMargin);
            m_os.rightmargin (m_uRightMargin);
         }



   private:
      CFormOutStream     &m_os;
      std::ios::fmtflags  m_Flags;
      char                m_cFill;
      unsigned            m_uLeftMargin;
      unsigned            m_uRightMargin;
      
      
      
}; // CStreamConfigGuard





// === Prototypes of interface functions =================================





/**
 * A function to call CFormOutStream::newl() as a stream manipulator.
 */
extern std::ostream &newl (std::ostream &ros);





#endif // __FORM_OUT_STREAM_H
