/* string_completion.cc
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2011 Ralf Hoffmann.
 * You can contact me at: ralf@boomerangsworld.de
 *   or http://www.boomerangsworld.de/worker
 *
 * 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.
 *
 * This program is 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "string_completion.hh"
#include "stringmatcher_fnmatch.hh"
#include "aguix/utf8.hh"

StringCompletion::StringCompletion( RefCount< StringMatcherFNMatch > matcher ) : m_matcher( matcher )
{
}

StringCompletion::~StringCompletion()
{
}

std::string StringCompletion::findCompletion( const std::string matching_string,
                                              const std::list< std::string > &strings )
{
    if ( strings.empty() ) return "";
    if ( m_matcher.get() == NULL ) return "";

    std::string base_string = strings.front();
    std::string start_match = matching_string;

    /* remove trailing * */
    if ( start_match.length() > 0 && start_match[ start_match.length() - 1 ] == '*' ) {
        start_match.resize( start_match.length() - 1 );
    }

    m_matcher->setMatchString( start_match + "*" );

    int pos = findShortestMatch( base_string );
    int longest_match = pos;

    for ( ;; ) {
        int next_pos = longest_match;

        if ( UTF8::movePosToNextChar( base_string.c_str(), next_pos ) < 1 ) break;

        std::string sub = base_string.substr( pos, next_pos - pos );

        std::string new_matcher = start_match;
        new_matcher += sub;
        new_matcher += "*";

        m_matcher->setMatchString( new_matcher );

        std::list< std::string >::const_iterator it1;

        for ( it1 = strings.begin();
              it1 != strings.end();
              it1++ ) {
            if ( ! m_matcher->match( *it1 ) ) {
                break;
            }
        }

        if ( it1 != strings.end() ) {
            break;
        }

        longest_match = next_pos;
   }

    return base_string.substr( pos, longest_match - pos );
}

size_t StringCompletion::findShortestMatch( const std::string &s )
{
    if ( m_matcher.get() == NULL ) return 0;

    std::string my_s = s;
    int pos = my_s.length();

    while ( pos > 0 ) {
        int new_pos = pos;

        if ( UTF8::movePosToPrevChar( my_s.c_str(), new_pos ) < 1 ) {
            break;
        }

        my_s.resize( new_pos );

        if ( m_matcher->match( my_s ) ) {
            pos = new_pos;
        } else {
            break;
        }
    }

    return pos;
}
