/***************************************************************************
 *   Copyright (C) 2005 by Andreas Pokorny                                 *
 *   andreas.pokorny@biozentrum.uni-wuerzburg.de                           *
 *                                                                         *
 *   This file is part of profdist and cbcanalyzer                         *
 *                                                                         *
 *   Both profdist and cbcanalyzer are free software; you can redistribute * 
 *   it and/or modify it under the terms of the GNU General Public License * 
 *   as published by the Free Software Foundation; either version 2 of the * 
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 *   Profdist and cbcanalyzer are distributed in the hope that it will be  *
 *   useful, but WITHOUT ANY WARRANTY; without even the implied warranty   *
 *   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the      *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

/**
 * @file spirit_helper.h contains simple helper structures to improve spirit parsing
 * @author Andreas Pokorny
 * @data 14.12.2004 
 */

#ifndef PROFDIST_SPIRIT_HELPER_INCLUDED
#define PROFDIST_SPIRIT_HELPER_INCLUDED

#include <boost/spirit/utility/chset.hpp>
#include <boost/spirit/actor/ref_value_actor.hpp>
#include <boost/spirit/actor/ref_const_ref_actor.hpp>
/**
 * Accepts line feed characters, use +lf_p to accept \n\r \r \r\n and \n
 */
struct lf_parser : public boost::spirit::char_parser<lf_parser>
{
  typedef lf_parser self_t;

  lf_parser() {}

  template <typename CharT>
    bool test(CharT ch) const
    { return ch == '\n' || ch == '\r'; 	}
};

lf_parser const lf_p = lf_parser();


class ostream_actor
{
  private:
    std::ostream & ref;
    std::string prefix, suffix;

  public:
    ostream_actor( std::ostream & ref_, std::string const& addition = "" ) 
      : ref( ref_ ), suffix(addition) {};
    ostream_actor( std::string prefix, std::ostream & ref_, std::string const& addition = "" ) 
      : ref( ref_ ), prefix(prefix), suffix(addition) {};
 
    template<typename T2> void operator()(T2 const& val ) const { ref << prefix << val << suffix; }

    template<typename IteratorT>
    void operator()( IteratorT const& first, IteratorT const& last ) const { ref << prefix << std::string(first, last) << suffix; }
};

inline ostream_actor ostream_a( std::string const& prefix, std::ostream & ref, std::string const& suffix ="" ) 
{ return ostream_actor(prefix, ref, suffix); }
inline ostream_actor ostream_a( std::ostream & ref, std::string const& suffix= ""  ) 
{ return ostream_actor(ref, suffix ); }

template<typename T, typename U, typename ActionT>
class ref_ref_actor : public ActionT
{
  private:
    T& st_ref;
    U& nd_ref;
  public:
    ref_ref_actor(T& stref_, U& ndref_) : st_ref(stref_), nd_ref(ndref_){}

    template<typename T2> void operator()(T2 const& /*val*/) const
    {
      this->act( st_ref, nd_ref); // defined in ActionT
    }

    template<typename IteratorT> void operator()( IteratorT const& /*first*/, IteratorT const& /*last*/) const
    {
      this->act( st_ref, nd_ref); // defined in ActionT
    }
};


struct begin_action { template<typename T, typename U> void act( T& ref_, U & con_ ) const { ref_ = con_.begin();  } };

template<typename T, typename U>
inline ref_ref_actor<T,U,begin_action> begin_a(T& ref_, U& con_)
{ return ref_ref_actor<T,U,begin_action>(ref_, con_ ); }


template<typename ContainerT,typename ValueT>
struct lazy_push_back_actor
{
  public:
    mutable ContainerT cont;
    ValueT const& val;

    lazy_push_back_actor( ContainerT const& c, ValueT const& v ) : cont( c ), val( v ) {}

    template<typename T> void operator()(T const& val ) const { cont().push_back( val() ); }

    template<typename IteratorT>
    void operator()( IteratorT const& first, IteratorT const& last ) const { cont().push_back( val() ); }

};

template<typename ContainerT, typename ValueT>
lazy_push_back_actor<ContainerT,ValueT> l_push_back_a( ContainerT const& con, ValueT const& val )
{ return lazy_push_back_actor<ContainerT,ValueT>(con, val );}


struct set_insert_action
{
  template<typename T,typename ValueT>
  void act(T& ref_, ValueT const& value_) const
  { ref_.insert( value_ ); }
  template<typename T,typename IteratorT>
  void act(T& ref_, IteratorT const& first_, IteratorT const& last_ ) const
  { 
    typedef typename T::value_type value_type;
    value_type value(first_,last_);

    ref_.insert( value );
  }
};
template<typename T>
inline boost::spirit::ref_value_actor<T,set_insert_action> 
set_insert_a(T& ref_)
{ return boost::spirit::ref_value_actor<T,set_insert_action>(ref_); }

template<typename T,typename ValueT>
inline boost::spirit::ref_const_ref_actor<T,ValueT,set_insert_action>  
push_back_a( T& ref_, ValueT const& value_ )
{ return boost::spirit::ref_const_ref_actor<T,ValueT,set_insert_action>(ref_,value_); }

#endif

