// PatMaN DNA pattern matcher
// (C) 2007 Kay Pruefer, Udo Stenzel
//
// This program is 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.  See the LICENSE file for details.

#ifndef INCLUDED_PREFIX_TREE_H
#define INCLUDED_PREFIX_TREE_H

#include <deque>
#include <string>

#ifndef NDEBUG
#include <istream>
#endif

#include "global.h"

struct probe_s {
	probe_s *next ;
	std::string name ;
	int length ;
	char strand ; // + or -
} ;

struct node {
	node* childs[5] ;
	node* suffix ;
	probe_s *probes ;
	unsigned char drop[5] ;
	unsigned char drop_suffix ;
	unsigned char depth ;
#ifndef NDEBUG
	std::string label ;
#endif

	node() : suffix(0), probes(0), drop_suffix(0), depth(0)
	{
		for( int i = 0 ; i != 5 ; ++i )
		{
			childs[i] = 0 ;
			drop[i] = 0 ;
		}
	}
} ;

/* Mismatch pointers (elsewhere called "walkers") point into the prefix
 * trie, track the history of an alignment and are advanced according to
 * the read database.
 *
 * We will keep mismatch pointers in a queue, implemented as singly
 * linked list, and because we splice inside that list, it's probably
 * best to implement it directly (instead of encapsulating everything
 * behind an object).  Unused nodes will be collected in another list
 * (the junk heap).
 */
struct mismatch_ptr {
	struct mismatch_ptr *next ;
	const node *ptr ;
	unsigned char mismatch ;
	unsigned char first ;
	unsigned char matched ;
	unsigned char isgap : 1 ;
	unsigned char gaps : 7 ;
} ;

class prefix_tree 
{
	public:
		prefix_tree( ) ;
		void add_seq( const std::string& seq, const std::string& name, bool ambi_codes ) ;
		mismatch_ptr *compare( char c, mismatch_ptr *ptrs ) const ;
		void add_suffix_links() ;
		mismatch_ptr *init( mismatch_ptr* ) const ; 

#ifndef NDEBUG
		void debug( std::ostream& s ) const { debug( s, nodes[0] ) ; }
		void debug( std::ostream&, const node& ) const ;
#endif

	private:
		node* create_go_node( node* n, int pos ) ;
		mismatch_ptr *seed() const ; 
		void add_recursion( const std::string& seq, const std::string& name, node* ptr, size_t i, char strand ) ;
		void add_recursion_ambiguity( const std::string& seq, const std::string& name, node* ptr, size_t i, char strand ) ;

		std::deque<node> nodes ;
} ;

#endif
