/* menutree.cc
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2013-2015,2017 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 "menutree.hh"

MenuTree::MenuTree() : m_root( "root", "", "" ),
                       m_current_node( &m_root )
{
}

MenuTreeNode *MenuTree::getRootNode()
{
    return &m_root;
}

int MenuTree::setFilter( const std::string &filter )
{
    m_filter = filter;
    m_matcher.setMatchString( filter );

    return checkVisibility( "", m_current_node );
}

std::string MenuTree::createPath( const std::string &separator )
{
    return createPath( &m_root, m_current_node, separator );
}

std::string MenuTree::createPath( MenuTreeNode *node,
                                  const std::string &separator )
{
    return createPath( &m_root, node, separator );
}

std::string MenuTree::createPath( MenuTreeNode *me, MenuTreeNode *node,
                                  const std::string &separator )
{
    std::string res;

    if ( me == node ) {
        res = me->getName();
        return res;
    }

    for ( const auto it : *me ) {
        res = createPath( it, node, separator );

        if ( ! res.empty() ) {
            if ( me->getParent() != NULL ) {
                std::string res2 = me->getName();
                res2 += separator;
                res2 += res;
                return res2;
            } else {
                return res;
            }
        }
    }
    return "";
}

std::string MenuTree::createFullname( MenuTreeNode *node,
                                      const std::string &separator )
{
    if ( ! node ) return "";

    if ( ! node->getParent() ) {
        return "";
    }

    std::string res;

    res = createFullname( node->getParent(), separator );
    if ( ! res.empty() ) {
        res += separator;
    }
    res += node->getName();

    return res;
}

void MenuTree::setCurrentNode( MenuTreeNode *node )
{
    m_current_node = node;
}

MenuTreeNode *MenuTree::getCurrentNode() const
{
    return m_current_node;
}

void MenuTree::fillFullname( std::list< std::pair< std::string, MenuTreeNode * > > &entries )
{
    fillFullname( m_current_node, "", entries );
}

void MenuTree::fillFullname( MenuTreeNode *node,
                             const std::string &prefix,
                             std::list< std::pair< std::string, MenuTreeNode * > > &entries )
{
    for ( const auto it1 : *node ) {
        std::string new_prefix = prefix;

        new_prefix += it1->getName();

        if ( it1->hasChildren() ) {
            new_prefix += "/";
        }

        if ( it1->getMatched() ) {
            entries.push_back( std::make_pair( new_prefix, it1 ) );
        }

        fillFullname( it1,
                      new_prefix,
                      entries );
    }
}

int MenuTree::checkVisibility( const std::string &prefix,
                               MenuTreeNode *node,
                               bool root )
{
    if ( root ) node->clearMatchedFlag();

    int visible_elements = 0;

    if ( m_visible_list.get() == NULL && root && m_filter.empty() ) {
        for ( const auto it1 : *node ) {
            it1->setMatched( true );
            visible_elements++;
        }
    }

    if ( ! m_filter.empty() || m_visible_list.get() != NULL ) {
        for ( const auto it1 : *node ) {
            bool matched = false;
            std::string fullname = prefix;
            if ( ! fullname.empty() ) fullname += "/";
            fullname += it1->getName();

            int visible_pos = -1;

            if ( m_visible_list.get() ) {
                visible_pos = m_visible_list->findPosition( createFullname( it1, "/" ) );
                if ( visible_pos >= 0 ) {
                    matched = true;
                }
            } else {
                matched = true;
            }

            if ( matched ) {
                matched =m_matcher.match( it1->getName() );
            }
            
            if ( matched ) {
                it1->setMatched( true );
                it1->setVisiblePos( visible_pos );
                visible_elements++;
                
                visible_elements += checkVisibility( fullname, it1, false );
            } else {
                it1->setMatched( false );
                it1->setVisiblePos( -1 );
                visible_elements += checkVisibility( fullname, it1, false );
            }
        }
    }

    return visible_elements;
}

int MenuTree::setVisibleList( std::shared_ptr< PersistentStringList > list )
{
    m_visible_list = list;

    return 0;
}
