/*
 * See the files COPYING and README for copyright information and how to reach
 * the author.
 *
 *  $Id: filter.h,v 1.5 2006/09/16 18:33:36 lordjaxom Exp $
 */

#ifndef VDR_BURN_FILTER_H
#define VDR_BURN_FILTER_H

#include "common.h"
#include <iterator>

namespace vdr_burn
{

   template<typename FwdIt, typename Pred>
   class filter_iterator:
   public std::iterator<std::forward_iterator_tag, typename FwdIt::value_type> {
   public:
      typedef typename FwdIt::value_type value_type;
      typedef typename FwdIt::reference reference;
      typedef typename FwdIt::pointer pointer;

      filter_iterator(FwdIt first, FwdIt last, Pred pred);

      bool operator==(const filter_iterator& rhs) { return m_current == rhs.m_current;}
      bool operator!=(const filter_iterator& rhs) { return m_current != rhs.m_current;}
      filter_iterator& operator++() { move_next(); return *this;}
      filter_iterator operator++(int) { filter_iterator temp( *this ); move_next(); return temp;}

      reference operator*() { return *m_current;}
      pointer operator->() { return &*m_current;}

   protected:
      void move_next();

   private:
      FwdIt m_current;
      FwdIt m_last;
      Pred m_pred;
   };

   template<typename FwdIt, typename Pred>
   filter_iterator<FwdIt, Pred>::filter_iterator(FwdIt first, FwdIt last, Pred pred):
   m_current( first ),
   m_last( last ),
   m_pred( pred )
   {
      if( m_current != m_last && !m_pred(*m_current) )
         move_next();
   }

   template<typename FwdIt, typename Pred>
   void filter_iterator<FwdIt, Pred>::move_next()
   {
      m_current = std::find_if(++m_current, m_last, m_pred);
   }

   class track_predicate {
   public:
      enum used_filter {
         unused = 0,
         used   = 1,
         all    = 2
      };

      track_predicate(track_info::streamtype content, used_filter used_):
      m_content( content ), m_used( used_ ) {}

      bool operator()(const track_info& track)
      {
         return(m_content == track_info::streamtype( 0 ) ||
                m_content == track.type) &&
         (m_used == all || m_used == track.used);
      }

   private:
      track_info::streamtype m_content;
      used_filter m_used;
   };

   template<typename List, typename It>
   class track_filter_t {
   public:
      typedef filter_iterator<It, track_predicate> iterator;

      track_filter_t(List& list, track_info::streamtype content, track_predicate::used_filter used_);
      track_filter_t(List& list, track_predicate::used_filter used_);

      iterator begin();
      iterator end();

   private:
      List& m_list;
      track_info::streamtype m_content;
      track_predicate::used_filter m_used;
   };

   template<typename List, typename It>
   track_filter_t<List, It>::track_filter_t(List& list, track_info::streamtype content, track_predicate::used_filter used_):
   m_list( list ),
   m_content( content ),
   m_used( used_ )
   {
   }

   template<typename List, typename It>
   track_filter_t<List, It>::track_filter_t(List& list, track_predicate::used_filter used_):
   m_list( list ),
   m_content( track_info::streamtype( 0 ) ),
   m_used( used_ )
   {
   }

   template<typename List, typename It>
   typename track_filter_t<List, It>::iterator track_filter_t<List, It>::begin()
   {
      return iterator( m_list.begin(), m_list.end(), track_predicate( m_content, m_used ) );
   }

   template<typename List, typename It>
   typename track_filter_t<List, It>::iterator track_filter_t<List, It>::end()
   {
      return iterator( m_list.end(), m_list.end(), track_predicate( m_content, m_used ) );
   }

   typedef track_filter_t<track_info_list, track_info_list::iterator> track_filter;
   typedef track_filter_t<const track_info_list, track_info_list::const_iterator>
   const_track_filter;

}

#endif // VDR_BURN_FILTER_H
