/* flattypelist.cc
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2006-2008,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 "flattypelist.hh"
#include "wconfig.h"
#include "wcfiletype.hh"
#include <algorithm>
#include "aguix/fieldlistview.h"
#include "simplelist.hh"

FlatTypeList::FlatTypeList( List *types, const std::string &filter ) : m_filter( filter )
{
    m_filter = AGUIXUtils::tolower( m_filter );
    build( types );
}

FlatTypeList::~FlatTypeList()
{
}

void FlatTypeList::buildLV( FieldListView *lv,
                            WCFiletype *highlightft )
{
    int row;
    
    if ( lv == NULL ) return;
    
    lv->setSize( 0 );

    for ( int i = 0; i < (int)m_visible_entry.size(); i++ ) {
        int e = m_visible_entry[i];
        row = lv->addRow();
        lv->setText( row, 0, getStringForName( m_flat_list[e] ) );
        
        if ( m_flat_list[e].filetype == highlightft ) lv->setActiveRow( row );
    }
    lv->redraw();
}

FlatTypeList::flattypelist_t FlatTypeList::getEntry( int visible_row )
{
    int e;

    if ( visible_row < 0 || visible_row >= (int)m_visible_entry.size() ) {
        return flattypelist_t();
    }

    e = m_visible_entry[visible_row];
    return m_flat_list[e];
}

void FlatTypeList::build( List *types )
{
    flattypelist_t ftl;
    const std::list<WCFiletype*> *subtypes;
    int id;
    WCFiletype *ft;

    m_flat_list.clear();
    m_visible_entry.clear();
    
    if ( types == NULL ) return;
    
    id = types->initEnum();
    ft = (WCFiletype*)types->getFirstElement( id );
    while ( ft != NULL ) {
        ftl.filetype = ft;
        ftl.depth = 0;
        ftl.visible = checkFilter( ft );

        m_flat_list.push_back( ftl );

        ft->sortSubTypeList();
        subtypes = ft->getSubTypeList();
        if ( subtypes != NULL ) {
            if ( subtypes->size() > 0 ) {
                addSubTypes( subtypes, 1 );
            }
        }
        ft = (WCFiletype*)types->getNextElement( id );
    }
    types->closeEnum( id );

    std::list<int> visible_entries;

    for ( int i = 0; i < (int)m_flat_list.size(); i++ ) {
        if ( m_flat_list[i].visible == true ) {
            visible_entries.push_back( i );
        }
    }
    
    if ( m_filter.length() >= 1 ) {
        visible_entries.sort( [this]( const auto &lhs,
                                      const auto &rhs ) {
            if ( m_flat_list.at( lhs ).filetype->getName() < m_flat_list.at( rhs ).filetype->getName() ) return true;
            return false;
        });
    }

    m_visible_entry.clear();

    int j = 0;
    for ( std::list<int>::iterator it1 = visible_entries.begin();
          it1 != visible_entries.end();
          it1++ ) {
        m_visible_entry[ j++ ] = *it1;
    }
}

void FlatTypeList::addSubTypes( const std::list<WCFiletype*> *types, int depth )
{
    flattypelist_t ftl;
    std::list<WCFiletype*>::const_iterator it1;
    const std::list<WCFiletype*> *subtypes;
    
    if ( types == NULL ) return;
    
    for ( it1 = types->begin(); it1 != types->end(); it1++ ) {
        ftl.filetype = *it1;
        ftl.depth = depth;
        ftl.visible = checkFilter( *it1 );
        
        m_flat_list.push_back( ftl );

        (*it1)->sortSubTypeList();
        subtypes = (*it1)->getSubTypeList();
        if ( subtypes != NULL ) {
            if ( subtypes->size() > 0 ) {
                addSubTypes( subtypes, depth + 1 );
            }
        }    
    }
}

std::string FlatTypeList::getStringForName( flattypelist_t &type )
{
    if ( m_filter.length() >= 1 ) {
        return type.filetype->getName();
    }
    std::string s1( type.depth * 2, ' ' );
    s1 += type.filetype->getName();
    return s1;
}

int FlatTypeList::getNrOfEntries()
{
    return (int)m_visible_entry.size();
}

WCFiletype *FlatTypeList::findParent( int row )
{
    int d, e;
  
    if ( row < 0 || row >= getNrOfEntries() ) return NULL;
    
    d = getEntry( row ).depth;
    if ( d == 0 ) return NULL;

    e = m_visible_entry[row];
    while ( m_flat_list[e].depth >= d ) {
        e--;
        if ( e < 0 ) return NULL;
    }
    return m_flat_list[e].filetype;
}

bool FlatTypeList::checkFilter( WCFiletype *type )
{
    if ( m_filter.length() < 1 ) return true;

    std::string n = AGUIXUtils::tolower( type->getName() );

    if ( n.find( m_filter ) != std::string::npos ) return true;
    return false;
}
