/* bookmarkdbproxy.cc
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2008-2009,2012-2013 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 "bookmarkdbproxy.hh"
#include "bookmarkdb.hh"
#include "bookmarkdbentry.hh"
#include "worker.h"

BookmarkDBProxy::BookmarkDBProxy( std::unique_ptr<BookmarkDB> bookmarks ) : m_serial_nr( 0 ),
                                                                            m_bookmarks( std::move( bookmarks ) ),
                                                                          m_pt( "/" )
{
}

BookmarkDBProxy::~BookmarkDBProxy()
{
}

void BookmarkDBProxy::addEntry( const BookmarkDBEntry &entry )
{
    m_bookmarks->addEntry( entry );
    bookmarksChanged();
}

void BookmarkDBProxy::delEntry( const BookmarkDBEntry &entry )
{
    m_bookmarks->delEntry( entry );
    bookmarksChanged();
}

void BookmarkDBProxy::updateEntry( const BookmarkDBEntry &entry,
                                   const BookmarkDBEntry &newentry )
{
    m_bookmarks->updateEntry( entry, newentry );
    bookmarksChanged();
}

std::unique_ptr<BookmarkDBEntry> BookmarkDBProxy::getEntry( const std::string &name )
{
    return m_bookmarks->getEntry( name );
}

std::list<std::string> BookmarkDBProxy::getCats()
{
    return m_bookmarks->getCats();
}

std::list<BookmarkDBEntry> BookmarkDBProxy::getEntries( const std::string &cat )
{
    return m_bookmarks->getEntries( cat );
}

std::list< std::string > BookmarkDBProxy::getNamesOfEntries( const std::string &cat )
{
    return m_bookmarks->getNamesOfEntries( cat );
}

int BookmarkDBProxy::read()
{
    int res = m_bookmarks->read();
    if ( res == 0 ) {
        bookmarksChanged();
    }
    return res;
}

int BookmarkDBProxy::write()
{
    return m_bookmarks->write();
}

void BookmarkDBProxy::registerChangeCallback( GenericCallback<int> *cb )
{
    m_change_callbacks.push_back( cb );
}

void BookmarkDBProxy::unregisterChangeCallback( GenericCallback<int> *cb )
{
    m_change_callbacks.remove( cb );
}

void BookmarkDBProxy::bookmarksChanged()
{
    m_serial_nr++;

    std::list< BookmarkDBEntry > cached_entries = m_bookmarks->getEntries( "" );

    m_pt = PathTree< RefCount<BookmarkDBEntry> >( "/" );

    for ( std::list< BookmarkDBEntry >::const_iterator it1 = cached_entries.begin();
          it1 != cached_entries.end();
          ++it1 ) {
        m_pt.addPath( it1->getName(), RefCount<BookmarkDBEntry>( new BookmarkDBEntry( *it1 ) ) );
    }

    for ( std::list< GenericCallback<int>* >::iterator it1 = m_change_callbacks.begin();
          it1 != m_change_callbacks.end();
          ++it1 ) {
        (*it1)->callback();
    }
}

BookmarkDBProxy::check_path_res_t BookmarkDBProxy::checkPath( const std::string &path,
                                                              std::list<BookmarkDBEntry> &return_entries )
{
    bool prefix_hit = false;
    check_path_res_t res = NO_HIT;

    const PathTree< RefCount<BookmarkDBEntry> > *node = m_pt.findNode( path );
    if ( node != NULL ) {
        std::list< RefCount<BookmarkDBEntry> > node_datas;
        node->getNodeDataRecursiveForHits( node_datas );

        std::list< RefCount<BookmarkDBEntry> >::iterator it2;
        for ( it2 = node_datas.begin();
              it2 != node_datas.end();
              it2++ ) {
            if ( it2->get() != NULL ) {
                return_entries.push_back( **it2 );
            }
        }
        
        if ( node->getIsExactHit() == true ) {
            //TODO node should be front in return_entries
            //     getNodeDataRecursiveForHits does this currently
            //     but I don't check it
            res = FULL_HIT;
        } else {
            prefix_hit = true;
        }
    }

    if ( res != NO_HIT ) return res;

    if ( prefix_hit == true ) return PREFIX_HIT;

    return NO_HIT;
}
