//==========================================================================
//  AIDA Detector description implementation 
//--------------------------------------------------------------------------
// Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
// All rights reserved.
//
// For the licensing terms see $DD4hepINSTALL/LICENSE.
// For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
//
// Author     : M.Frank
//
//==========================================================================
#ifndef PARSERS_SPIRIT_TOSTREAM_H
#define PARSERS_SPIRIT_TOSTREAM_H 1
// ============================================================================
// Include files
#include "Parsers/config.h"
// ============================================================================
// STD & STL
// ============================================================================
#include <iostream>
#include <iomanip>
#include <vector>
#include <map>
#include <set>
#include <list>
#include <deque>
#include <string>
#include <sstream>

// ============================================================================
/** @file dd4hep/ToStream.h
 *  implemenattiono fvarioud functions for streaming.
 *  this functionality is essenital for usag eof varuodu types as property for
 *  the various dd4hep components
 *  @attention the implemenation of the specific specializations must be done
 *                    before the inclusion of this file
 *  @todo ToStream.h : reimplement in terms of functors, to allow
 *                     easier especializations
 */
// ============================================================================

/// Namespace for the AIDA detector description toolkit
namespace dd4hep {
  // ==========================================================================
  /// Utility namespace to support boost::spirit
  namespace Parsers {

    template <class TYPE>
    std::ostream& toStream(const TYPE& obj, std::ostream& s);

    // ========================================================================
    /** the generic implementation of the printout to the std::ostream
     *  @author Alexander MAZUROV Alexander.Mazurov@gmail.com
     *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
     *  @date 2006-05-12
     */
    template <class TYPE>
    std::ostream& toStream_(const TYPE& obj, std::ostream& s);
    // ========================================================================
    /// the helper function to print the sequence
    /** @param first (INPUT)  begin-iterator for the sequence
     *  @param last  (INPUT)  end-iterator for the sequence
     *  @param s     (UPDATE) the stream itself
     *  @param open  (INPUT)  "open"-symbol
     *  @param close (INPUT)  "close"-symbol
     *  @param delim (INPUT)  "delimiter"-symbol
     *  @return the stream
     *  @author Vanya BELYAEV Ivan.BElyaev@nikhef.nl
     *  @date 2009-09-15
     */
    template <class ITERATOR>
    inline std::ostream& toStream_(ITERATOR first, // begin of the sequence
                                  ITERATOR last,                            //   end of the sequence
                                  std::ostream& s,                          //            the stream
                                  const std::string& open,                  //               opening
                                  const std::string& close,                 //               closing
                                  const std::string& delim);                //             delimiter
    // ========================================================================
    /// the printtout of the strings.
    /** the string is printed a'la Python using the quotes
     *  @author Alexander MAZUROV Alexander.Mazurov@gmail.com
     *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
     *  @date 2006-05-12
     */
    inline std::ostream& toStream_(const std::string& obj, std::ostream& s) {
      if (std::string::npos == obj.find('\'')) {
        s << "\'" << obj << "\'";
      }
      else {
        s << "\"" << obj << "\"";
      }
      return s;
    }
    /// the printout of boolean values "a'la Python"
    /** @author Vanya BELYAEV ibelyaev@physics.syr.edu
     *  @date 2006-09-09
     */
    inline std::ostream& toStream_(const bool obj, std::ostream& s) {
      return s << (obj ? "True" : "False");
    }
    /// the printout of float values with the reasonable precision
    /** @author Vanya BELYAEV ibelyaev@physics.syr.edu
     *  @date 2006-09-09
     */
    inline std::ostream& toStream_(const float obj, std::ostream& s, const int prec = 6) {
      const int p = s.precision();
      return s << std::setprecision(prec) << obj << std::setprecision(p);
    }
    /// the printout of double values with the reasonable precision
    /** @author Vanya BELYAEV ibelyaev@physics.syr.edu
     *  @date 2006-09-09
     */
    inline std::ostream& toStream_(const double obj, std::ostream& s, const int prec = 8) {
      const int p = s.precision();
      return s << std::setprecision(prec) << obj << std::setprecision(p);
    }
    /// the printout of long double values with the reasonable precision
    /** @author Vanya BELYAEV ibelyaev@physics.syr.edu
     *  @date 2006-09-09
     */
    inline std::ostream& toStream_(const long double obj, std::ostream& s, const int prec = 10) {
      const int p = s.precision();
      return s << std::setprecision(prec) << obj << std::setprecision(p);
    }
    // ========================================================================
    /** the partial template specialization of
     *  <c>std::pair<KTYPE,VTYPE></c> printout
     *  the pair is printed a'la Python tuple: " ( a , b )"
     *  @author Alexander MAZUROV Alexander.Mazurov@gmail.com
     *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
     *  @date 2006-05-12
     */
    template <class KTYPE, class VTYPE>
    inline std::ostream& toStream_(const std::pair<KTYPE, VTYPE>& obj, std::ostream& s) {
      s << "( ";
      toStream_(obj.first, s);
      s << " , ";
      toStream_(obj.second, s);
      return s << " )";
    }
    // ========================================================================
    /** the partial template specialization of <c>std::vector<TYPE,ALLOCATOR></c>
     *  printout. The vector is printed a'la Python list: "[ a, b, c ]"
     *  @author Alexander MAZUROV Alexander.Mazurov@gmail.com
     *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
     *  @date 2006-05-12
     */
    template <class TYPE, class ALLOCATOR>
    inline std::ostream& toStream_(const std::vector<TYPE, ALLOCATOR>& obj, std::ostream& s) {
      return toStream_(obj.begin(), obj.end(), s, "[ ", " ]", " , ");
    }
    // ========================================================================
    /** the partial template specialization of <c>std::list<TYPE,ALLOCATOR></c>
     *  printout. The vector is printed a'la Python list: "[ a, b, c ]"
     *  @author Alexander MAZUROV Alexander.Mazurov@gmail.com
     *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
     *  @date 2007-04-08
     */
    template <class TYPE, class ALLOCATOR>
    inline std::ostream& toStream_(const std::list<TYPE, ALLOCATOR>& obj, std::ostream& s) {
      return toStream_(obj.begin(), obj.end(), s, "[ ", " ]", " , ");
    }
    // ========================================================================
    /** the partial template specialization of <c>std::deque<TYPE,ALLOCATOR></c>
     *  printout. The vector is printed a'la Python list: "[ a, b, c ]"
     *  @author Alexander MAZUROV Alexander.Mazurov@gmail.com
     *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
     *  @date 2006-05-12
     */
    template <class TYPE, class ALLOCATOR>
    inline std::ostream& toStream_(const std::deque<TYPE, ALLOCATOR>& obj, std::ostream& s) {
      return toStream_(obj.begin(), obj.end(), s, "[ ", " ]", " , ");
    }
    // ========================================================================
    /** the partial template specialization of <c>std::set<TYPE,CMP,ALLOCATOR></c>
     *  printout. The vector is printed a'la Python list: "[ a, b, c ]"
     *  @author Alexander MAZUROV Alexander.Mazurov@gmail.com
     *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
     *  @date 2006-05-12
     */
    template <class TYPE, class CMP, class ALLOCATOR>
    inline std::ostream& toStream_(const std::set<TYPE, CMP, ALLOCATOR>& obj, std::ostream& s) {
      return toStream_(obj.begin(), obj.end(), s, "[ ", " ]", " , ");
    }
    // ========================================================================
    /** the partial template specialization of
     *  <c>std::map<KTYPE,VTYPE,CMP,ALLOCATOR></c> printout
     *  the map is printed a'la Python dict: " ( a : b , c: d , e : f )"
     *  @author Alexander MAZUROV Alexander.Mazurov@gmail.com
     *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
     *  @date 2006-05-12
     */
    template <class KTYPE, class VTYPE, class CMP, class ALLOCATOR>
    inline std::ostream& toStream_(const std::map<KTYPE, VTYPE, CMP, ALLOCATOR>& obj, std::ostream& s) {
      s << "{ ";
      for (typename std::map<KTYPE, VTYPE, CMP, ALLOCATOR>::const_iterator cur = obj.begin(); obj.end() != cur; ++cur) {
        if (obj.begin() != cur) {
          s << " , ";
        }
        toStream_(cur->first, s);
        s << " : ";
        toStream_(cur->second, s);
      }
      return s << " }";
    }

    // ========================================================================
    /** the specialization for C-arrays, a'la python tuple
     *  @author Vanya BELYAEV Ivan.Belyaev@nikhenf.nl
     *  @date 2009-10-05
     */
    template <class TYPE, unsigned int N>
    std::ostream& toStream_(TYPE (&obj)[N], std::ostream& s) {
      return toStream_(obj, obj + N, s, "( ", " )", " , ");
    }
    // ========================================================================
    /** the specialization for C-arrays, a'la python tuple
     *  @author Vanya BELYAEV Ivan.Belyaev@nikhenf.nl
     *  @date 2009-10-05
     */
    template <class TYPE, unsigned int N>
    std::ostream& toStream_(const TYPE (&obj)[N], std::ostream& s) {
      return toStream_(obj, obj + N, s, "( ", " )", " , ");
    }
    // ========================================================================
    /** the specialization for C-string, a'la python tuple
     *  @author Vanya BELYAEV Ivan.Belyaev@nikhenf.nl
     *  @date 2009-10-05
     */
    template <unsigned int N>
    std::ostream& toStream_(char (&obj)[N], std::ostream& s) {
      return toStream_(std::string(obj, obj + N), s);
    }
    // ========================================================================
    /** the specialization for C-string, a'la python tuple
     *  @author Vanya BELYAEV Ivan.Belyaev@nikhenf.nl
     *  @date 2009-10-05
     */
    template <unsigned int N>
    std::ostream& toStream_(const char (&obj)[N], std::ostream& s) {
      return toStream_(std::string(obj, obj + N), s);
    }
    // ========================================================================
    /** the specialization for C-string, a'la python tuple
     *  @author Vanya BELYAEV Ivan.Belyaev@nikhenf.nl
     *  @date 2009-10-05
     */
    inline std::ostream& toStream_(const char* obj, std::ostream& s) {
      return toStream_(std::string(obj), s);
    }
    // ========================================================================
    /** the generic implementation of the printout to the std::ostream
     *  @author Alexander MAZUROV Alexander.Mazurov@gmail.com
     *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
     *  @date 2006-05-12
     */
    template <class TYPE>
    inline std::ostream& toStream_(const TYPE& obj, std::ostream& s) {
      return s << obj;
    }
    // ========================================================================
    /** the helper function to print the sequence
     *  @param first (INPUT)  begin-iterator for the sequence
     *  @param last  (INPUT)  end-iterator for the sequence
     *  @param s     (UPDATE) the stream itself
     *  @param open  (INPUT)  "open"-symbol
     *  @param close (INPUT)  "close"-symbol
     *  @param delim (INPUT)  "delimiter"-symbol
     *  @return the stream
     *  @author Vanya BELYAEV Ivan.BElyaev@nikhef.nl
     *  @date 2009-09-15
     */
    template <class ITERATOR>
    inline std::ostream& toStream_(ITERATOR first,     // begin of the sequence
                                  ITERATOR last,                                //   end of the sequence
                                  std::ostream& s,                              //            the stream
                                  const std::string& open,                      //               opening
                                  const std::string& close,                     //               closing
                                  const std::string& delim)                     //             delimiter
    {
      s << open;
      for (ITERATOR curr = first; curr != last; ++curr) {
        if (first != curr) {
          s << delim;
        }
        toStream_(*curr, s);
      }
      s << close;
      //
      return s;
    }
    // ========================================================================
    /** the generic implementation of the type conversion to the string
     *  @author Alexander MAZUROV Alexander.Mazurov@gmail.com
     *  @author Vanya BELYAEV ibelyaev@physics.syr.edu
     *  @date 2006-05-12
     *  @see dd4hep::Parsers::toStream_
     *  @todo need to be compared with boost::lexical_cast
     */
    template <class TYPE>
    inline std::string toString(const TYPE& obj) {
      std::ostringstream s;
      std::ios::fmtflags orig_flags = s.flags();
      s.setf(std::ios::showpoint);   // to display correctly floats
      toStream_(obj, s);
      s.flags(orig_flags);
      return s.str();
    }
    // ========================================================================
  }//                                          end of namespace dd4hep::Parsers
  // ==========================================================================
}//                                                     end of namespace dd4hep

#ifndef DD4HEP_PARSERS_NO_ROOT
#include "Math/Point3D.h"
#include "Math/Vector3D.h"
#include "Math/Vector4D.h"
#include "Math/RotationZYX.h"

/// Namespace for the AIDA detector description toolkit
namespace dd4hep {
  // ==========================================================================
  /// Utility namespace to support boost::spirit
  namespace Parsers {
    // ============================================================================
    /// print XYZ point
    std::ostream& toStream_(const ROOT::Math::XYZPoint& obj, std::ostream& s);
    // print XYZ-vector
    std::ostream& toStream_(const ROOT::Math::XYZVector& obj, std::ostream& s);
    /// print Lorentz vector
    std::ostream& toStream_(const ROOT::Math::PxPyPzEVector& obj, std::ostream& s);
    /// print RotationZYX
    std::ostream& toStream_(const ROOT::Math::RotationZYX& obj, std::ostream& s);
    // ========================================================================
  }//                                          end of namespace dd4hep::Parsers
  // ==========================================================================
}//                                                     end of namespace dd4hep
#endif
// ============================================================================
// The END
// ============================================================================
#endif
// ============================================================================

