/***************************************************************************
 *   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_TRANSFORM_H_INCLUDED
#define CBCANALYZER_CT_TRANSFORM_H_INCLUDED
#include <algorithm>
#include <iomanip>
#include <boost/iterator/iterator_facade.hpp>
#include <cctype>
#include <cmath>
#include <iostream>
#include "parsed_sequence.h"
#include "concepts.h"
#include "rai_adaptor.h"


template<typename IteratorT, typename StreamT>
void to_marna( std::list<sequence<IteratorT> > const& seqs, StreamT & out );

template<typename IteratorT, typename StreamT>
void to_mixed_fasta( std::list<sequence<IteratorT> > const& seqs, StreamT & out );

template<typename IteratorT, typename StreamT>
void to_marna( std::list<sequence<IteratorT> > const& seqs, StreamT & out )
{
  // print name print sequence 
  // print name print sequence 
  // print name print sequence 
  // print name print sequence 
  //
  // print name print transformation ??
}

namespace detail {
  template<typename Iterator> 
  std::size_t get_next_ct( Iterator begin, Iterator current, Iterator end, std::size_t pos )
  {
          std::size_t stack = 0;
    switch(*current)
    {
      case '(':
        while( current != end ) 
        {
          ++current;
          ++pos;
          if( *current == ')' )
            if( stack == 0 )
              return  pos;
            else --stack;
          else
            stack += (*current == '(');
        }
        break;
      case ')':
        do
        {
          --current;
          --pos;
          if( *current == '(' )
            if( stack == 0 )
              return  pos;
            else --stack;
          else 
            stack += (*current == ')' );
        }
        while( current != begin );
        break;
    }
    return 0;
  }
}

template<typename IteratorT>
void to_ct( sequence_data< brace_fold_data< num_nuc<name_data<base_adaptor<IteratorT> > > > > const&  seqs, std::ostream & out )
{
  typedef sequence_data< brace_fold_data< num_nuc< name_data<base_adaptor<IteratorT> > > > > source_type;
  for( typename source_type::const_sequence_id id = seqs.begin(), e = seqs.end(); 
      id != e; ++id )
  {
    std::size_t num = seqs.get_num_nuc( id );
    out  << "  " << num;
    
    std::string name( seqs.get_name( id ).first, seqs.get_name( id ).second );
    if( name.find_first_of("ENERGY",0) != 0 )
      out << "  ENERGY = 0 " << name << '\n';
    else
      out << "  " << name << '\n';


    std::size_t i = 0, fs = std::size_t(std::log10(float(num)) )+1;
    
    typename source_type::const_brace_iterator f_it = seqs.brace_begin( id )
      , f_e = seqs.brace_end( id )
      , f_b = seqs.brace_begin( id ); 
    for( typename source_type::const_sequence_iterator s_it = seqs.sequence_begin( id ), s_e = seqs.sequence_end( id ); 
        s_it != s_e && f_it != f_e;  
        ++s_it, ++f_it, ++i )
    {
        out << "  " 
          << std::setw(fs) << i + 1 << ' ' 
          << char(std::toupper(*s_it)) << "     " 
          << std::setw(fs) << i << "  "
          << std::setw(fs) << (i + 2)%(num + 1) << "  "
          << std::setw(fs) << detail::get_next_ct(f_b, f_it, f_e, i + 1 ) << "  "
          << std::setw(fs) << i+1 << '\n';
    }
  }
}

namespace hidden {
  
  template<typename It>
  struct to_upper_iterator 
    : public boost::iterator_facade<to_upper_iterator<It>, const char, boost::bidirectional_traversal_tag, char const> 
  {
    It it_;
    to_upper_iterator( It const& it ) : it_(it) {}
    inline char const dereference() const { return std::toupper(*it_); }
    inline bool equal( to_upper_iterator<It> const& y ) const { return it_ == y.it_; }
    inline void increment() { ++it_; }
    inline void decrement() { --it_; }
  };
  template<typename I>
  to_upper_iterator<I> g_tup_it( I const & ref ) { return to_upper_iterator<I>(ref); }
}

template<typename IteratorT, typename StreamT>
void to_mixed_fasta( std::list<sequence<IteratorT> > const& seqs, StreamT & out )
{
  for( typename std::list<sequence<IteratorT> >::const_iterator it = seqs.begin(), e = seqs.end(); it != e; )
  {
    typename sequence<IteratorT>::string_range cp = it->id;
    out << "> " << std::string( cp.first, cp.second ) << '\n';
    for( typename std::list<typename sequence<IteratorT>::string_range>::const_iterator _it = it->sequence_data.begin(),
        _e = it->sequence_data.end();
        _it != _e; ++_it )
      out << std::string( hidden::g_tup_it(_it->first), hidden::g_tup_it(_it->second) );
    out << '\n';
    do
    {
      std::size_t i = 1;
      for( typename std::list<std::size_t>::const_iterator _it = it->fold_data.begin(),
          _e = it->fold_data.end();
          _it != _e; ++_it, ++i )
        out << ((*_it == 0)?'.':(*_it>i)?'(':')');
      out << '\n';
    }
    while( ++it != e && compare_range( it->id, cp ) );
    out << '\n';
  }
}



#endif

