/***************************************************************************
 *   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_BDB_PARSER_H_INCLUDED
#define CBCANALYZER_BDB_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/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 "parser.h"
#include "spirit_helper.h"



/**
 * Simple mixed bracket-dot-bracket with fasta sequence format grammar, 
 * items, 
 */
struct bdb_grammar 
:   public boost::spirit::grammar<bdb_grammar>
{
  std::list<file_sequence> & entries;
  bdb_grammar( std::list<file_sequence> & entries ) : entries(entries) {}
  
  /**
   * grammar definition
   */
  template<typename ScannerT>
  struct definition
  {
    typedef boost::spirit::rule<ScannerT> rule_t;

    rule_t bdb, name, fold, seq_string;
    std::size_t empty;

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


    definition(bdb_grammar const& self)
      : empty(0)
    {
      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;

      chset<> ws_lbr("\n\r\t ");
      chset<> lbr("\n\r");
      
      bdb = 
        *ws_lbr
        >> +( 
            name 
            >> seq_string
            >> +fold
            >> *ws_lbr
            )
        ;
            
      name =
        '>' 
        >> *blank_p
        >> (+(~lbr))[ assign_a(current_sequence.id) ]
        >> *ws_lbr
        ;
      
      fold = 
        eps_p 
        [ clear_a(current_sequence.char_fold_data) ]
        >> 
        *ws_lbr
        >> (+chset<>(".()-"))
        [ assign_a(current_range) ]
        [ push_back_a( current_sequence.char_fold_data, current_range) ]
        [ boost::spirit::push_back_a( self.entries, current_sequence ) ]
        >> *blank_p
        >> *lbr
        ;

      seq_string =
        eps_p
        [ clear_a(current_sequence.sequence_data) ]
        [ assign_a(current_sequence.sequence_length, empty) ]
        >> +(
            *ws_lbr
            >> (+(
                chset<>("AaBbCcDdGgHhKkMmNnOoUuSsTtVvWwYy-")
                [ increment_a(current_sequence.sequence_length )]
                ) )
            [ assign_a(current_range) ]
            [ push_back_a( current_sequence.sequence_data, current_range) ]
            >> *blank_p
            >> +lbr
            )
        ;
        
   
#ifdef BOOST_SPIRIT_DEBUG
      BOOST_SPIRIT_DEBUG_RULE( seq_string );
      BOOST_SPIRIT_DEBUG_RULE( fold );
      BOOST_SPIRIT_DEBUG_RULE( name );
      BOOST_SPIRIT_DEBUG_RULE( bdb );
#endif
    }

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



#endif 

