/* searchop_resultstore.cc
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2006-2024 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 "resultstore.hh"

ResultStore::ResultStore( const std::string &searchname, bool follow_symlinks, bool search_vfs, bool search_same_fs )
{
  _dir = new NWC::VirtualDir( searchname, follow_symlinks, false, search_same_fs );
  _res = new std::list<SearchThread::SearchResult>;

  m_p = NULL;
}

ResultStore::~ResultStore()
{
  delete _dir;
  delete _res;
}

NWC::VirtualDir *ResultStore::getDir()
{
  //TODO returning pointer sucks
  return _dir;
}

std::list<SearchThread::SearchResult> *ResultStore::getRes()
{
  //TODO returning pointer sucks
  return _res;
}

NWC::VirtualDir *ResultStore::getClonedDir() const
{
  NWC::VirtualDir *d = NULL;
  NWC::FSEntry *fse = _dir->clone();
  
  if ( fse != NULL ) {
    d = dynamic_cast<NWC::VirtualDir*>( fse );
  }
  
  if ( d == NULL ) {
      d = new NWC::VirtualDir( "searchdir1", _dir->getFollowSymlinks(), false, _dir->getSearchSameFS() );
  }
  return d;
}

void ResultStore::setSearchSettings( const SearchSettings &sets )
{
  _settings = sets;
  _dir->setFollowSymlinks( sets.getFollowSymlinks() );
  _dir->setSearchVFS( false );
  _dir->setSearchSameFS( sets.getSearchSameFS() );
}

SearchSettings ResultStore::getSearchSettings() const
{
  return _settings;
}

void ResultStore::setActiveRow( int row )
{
  _settings.setActiveRow( row );
}

void ResultStore::removeEntries( const std::list< std::pair< std::string, int > > &entry_list )
{
    for ( std::list< std::pair< std::string, int > >::const_iterator it = entry_list.begin();
        it != entry_list.end();
        it++ ) {
        removeEntriesIf( [&it]( auto &fullname, auto line_nr ) {
            if ( it->first != fullname ) return false;
            if ( it->second < 0 || line_nr == it->second ) return true;
            return false;
        } );
  }
}

void ResultStore::removeEntriesIf( std::function< bool ( const std::string &fullname, int line_nr ) > predicate )
{
    // keep track of entries with same fullname to be able to remove
    // it from the virtual dir as well if all entries (with different
    // line numbers) have been removed
    std::string current_fullname;
    size_t current_fullname_count = 0;
    size_t current_fullname_removed = 0;

    for ( std::list<SearchThread::SearchResult>::iterator it = _res->begin();
          it != _res->end(); ) {
        if ( it->getFullname() != current_fullname ) {
            if ( ! current_fullname.empty() &&
                 current_fullname_count == current_fullname_removed ) {
                // no other entry with same full name left so remove it from the list
                _dir->removeFromList( current_fullname );
            }

            current_fullname = it->getFullname();
            current_fullname_removed = 0;
            current_fullname_count = 1;
        } else {
            current_fullname_count++;
        }

        if ( predicate( it->getFullname(), it->getLineNr() ) ) {
            std::list<SearchThread::SearchResult>::iterator erase_it = it;
            it++;

            _res->erase( erase_it );

            current_fullname_removed++;

            m_removed++;
        } else {
            it++;
        }
    }

    if ( ! current_fullname.empty() &&
         current_fullname_count == current_fullname_removed ) {
        // no other entry with same full name left so remove it from the list
        _dir->removeFromList( current_fullname );
    }
}

bool ResultStore::set_exclusive( void *p )
{
    if ( m_p != NULL ) return false;

    m_p = p;

    return true;
}

void ResultStore::unset_exclusive( void *p )
{
    if ( m_p == p ) {
        m_p = NULL;
    }
}

bool ResultStore::is_exclusive() const
{
    if ( m_p ) return true;

    return false;
}

size_t ResultStore::get_excluded() const
{
    return m_excluded;
}

size_t ResultStore::get_removed() const
{
    return m_removed;
}

void ResultStore::set_excluded( size_t v )
{
    m_excluded = v;
}

void ResultStore::set_removed( size_t v )
{
    m_removed = v;
}
