/***************************************************************************
 *   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.             *
 ***************************************************************************/

#ifndef CBCANALYZER_CT_PARSER_H_INCLUDED
#define CBCANALYZER_CT_PARSER_H_INCLUDED

//#define BOOST_SPIRIT_DEBUG
//#define BOOST_SPIRIT_DEBUG_FLAGS BOOST_SPIRIT_DEBUG_FLAGS_NODES

#include <list>
#include <stdexcept>
#include <iostream>
#include <string>
#include <cassert>
#include <sstream>
#include <boost/cstdlib.hpp>
#include <boost/spirit/phoenix.hpp>
#include <boost/spirit/core.hpp>
#include <boost/spirit/symbols.hpp>
#include <boost/spirit/attribute.hpp>
#include <boost/spirit/dynamic.hpp>
#include <boost/spirit/core/primitives/primitives.hpp>
#include <boost/spirit/utility/grammar_def.hpp>
#include <boost/spirit/utility/lists.hpp>
#include <boost/spirit/utility/loops.hpp>
#include <boost/spirit/iterator/file_iterator.hpp>
#include <boost/spirit/iterator/position_iterator.hpp>
#include <boost/spirit/core/composite/epsilon.hpp>
#include <boost/spirit/actor/push_back_actor.hpp>
#include <boost/spirit/actor/clear_actor.hpp>
#include <boost/spirit/actor/increment_actor.hpp>
#include <boost/spirit/phoenix/binders.hpp>
#include <boost/ref.hpp>

#include "parser.h"
#include "spirit_helper.h"

using namespace boost;
using namespace phoenix;

/**
 * Simple ct_file grammar, this grammar generates a list of sequence info 
 * items, 
 */
struct ct_grammar 
:   public boost::spirit::grammar<ct_grammar>
{
  std::list<file_sequence> & entries;
  ct_grammar( std::list<file_sequence> & entries ) : entries(entries) {}
  
  /**
   * grammar definition
   */
  template<typename ScannerT>
  struct definition
  {
    typedef boost::spirit::rule<ScannerT> rule_t;

    rule_t cts, line, header;
    std::size_t num_nucs, counter;

    file_sequence::string_range current_range; ///< temporary storage for list entries 
    file_sequence current_sequence; ///< Sequence entry which gets parsed at the moment,


    definition(ct_grammar const& self)
    {
      using boost::spirit::uint_p;
      using boost::spirit::int_p;
      using boost::spirit::repeat_p;
      using boost::spirit::assign_a;
      using boost::spirit::increment_a;
      using boost::spirit::push_back_a;
      using boost::spirit::ch_p;
      using boost::spirit::real_p;
      using boost::spirit::blank_p;
      using boost::spirit::chset;
      using boost::spirit::eps_p;
      using boost::spirit::alpha_p;
      using boost::spirit::str_p;

      cts = 
        *(
        header 
        >> repeat_p( ref(num_nucs) )[line]
        >> eps_p
        [ boost::spirit::push_back_a(self.entries, current_sequence)]
        [ clear_a(current_sequence) ]
        >> *lf_p
        )
        ;

      header = 
        *blank_p
        >> uint_p[assign_a(num_nucs)] 
        >> *blank_p
        >> (
            (str_p("ENERGY") | "dG")
            >> *blank_p
            >> '='
            >> *blank_p
            >> int_p
            >> !(
              '.' 
              >> uint_p
              )
           )/*[ostream_a(std::cout, "|\n")]*/[assign_a(current_sequence.id)]
        >> *blank_p
        >> !(
            ch_p('[') 
            >> *( ~chset<>("\n\r]") )
            >> ( lf_p | ']' )
            )
        >> *blank_p
        >> !( (+( ~chset<>("\n\r") ))/*[ostream_a("|", std::cout,"|\n" )]*/[assign_a(current_sequence.id)] )
        >> *blank_p
        >> lf_p
        ;


      line = 
        *blank_p
        >> uint_p 
        >> *blank_p
        >> (
            alpha_p    // parsing a single sequence character
            >> eps_p
           )
        [increment_a( current_sequence.sequence_length ) ]
        [assign_a( current_range )]
        [push_back_a( current_sequence.sequence_data, current_range )]
        >> *blank_p
        >> uint_p
        >> *blank_p
        >> uint_p
        >> *blank_p
        >> uint_p [push_back_a( current_sequence.fold_data ) ]/*[ostream_a( std::cout )]*/
        >> *blank_p
        >> uint_p
        >> *blank_p
        >> *ch_p('.')
        >> lf_p
        ;

#ifdef BOOST_SPIRIT_DEBUG
      BOOST_SPIRIT_DEBUG_RULE( header );
      BOOST_SPIRIT_DEBUG_RULE( line );
      BOOST_SPIRIT_DEBUG_RULE( cts );
#endif
    }

    rule_t const& start() const
    {
      return cts;
    }
  };
};



#endif 

