/*
 * TailedSubstring.h
 *
 *  Created on: 19. 3. 2020
 *      Author: Jan Jirak
 */

#pragma once

#include <alib/measure>

#include <alib/set>
#include <alib/vector>

#include <string/LinearString.h>


namespace stringology {

    namespace exact {


/**
 * Implementation of the TailedSubstring algorithm from article “ IT’S ECONOMY, STUPID! ” : SEARCHING FOR A SUBSTRING
 * WITH CONSTANT EXTRA SPACE COMPLEXITY
 * Domenico Cantone and Simone Faro
 */
        class TailedSubstring{
        public:
            /**
             * Search for pattern in linear string.
             * @return set set of occurences
             */
            template < class SymbolType >
            static ext::set < unsigned > match ( const string::LinearString < SymbolType > & subject, const string::LinearString < SymbolType > & pattern );

        };

        template < class SymbolType >
        ext::set < unsigned > TailedSubstring::match ( const string::LinearString < SymbolType > & subject, const string::LinearString < SymbolType > & pattern ) {
            ext::set<unsigned> occ;
            const auto & text = subject.getContent();
            const auto & pat = pattern.getContent();
            long int n = text.size(), m = pat.size();

            long int s = 0;
            long int delta = 1;
            long int i , k;
            i = k = m - 1;

            measurements::start ( "Algorithm", measurements::Type::ALGORITHM );
            // Phase 1
            while ( s <= n - m && i - delta >= 0 ) {
                if ( pat[i] != text[s + i] ) s = s + 1;
                else {
                    long int j = 0;
                    while ( j < m && pat[j] == text[s + j] ) ++j;
                    if ( j == m ) occ.insert(s);
                    long int h = i - 1;
                    while ( h >= 0 && pat[h] != pat[i] ) --h;
                    if ( delta < i - h ){
                        delta = i - h;
                        k = i;
                    }
                    s = s + i - h;
                    i = i - 1;
                }
            }

            // Phase 2
            while ( s <= n - m ){
                if ( pat[k] != text[s+k] ) ++ s;
                else {
                    long int j = 0 ;
                    while ( j < m && pat[j] == text[s+j]) ++j;
                    if ( j == m ) occ.insert(s);
                    s += delta;
                }
            }
            measurements::end();
            return occ;
        }


    } /* namespace exact */

} /* namespace stringology */

