/**********************************************************************
 ** Copyright (C) 2002 stephan beal (stephan@wanderinghorse.net).  
 ** All rights reserved.
 **
 ** This file may be distributed and/or modified under the terms of the
 ** See LICENSE file in this directory. version 2 as published by the Free Software
 ** Foundation and appearing in the file LICENSE.GPL included in the
 ** packaging of this file.
 **
 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 **
 **********************************************************************/

#include "EPathFinder.h"
#include <iostream>
#include <unistd.h>

        ostream &
        operator<<(ostream &os, const EPathFinder &obj)
        {
                os << obj.getPathString();
                return os;
        }
        string &
        operator<<(string &os, const EPathFinder &obj)
        {
                os += obj.getPathString();
                return os;
        }

        EPathFinder &
        operator +=(EPathFinder &obj, const string &os)
        {
                obj.addPath( os );
                return obj;
        }


        EPathFinder::EPathFinder( const string &p, const string &e, const string &pathsep )
        {
                this->setPathSeparator( pathsep );
                this->setPath( p );
                this->setExtensions( e );
        }


        const string &
        EPathFinder::getPathSeparator() const
        {
                return ((EPathFinder *)this)->pathseparator;
        }

        void
        EPathFinder::setPathSeparator( const string &sep )
        {
                this->pathseparator = sep;
        }

        string
        EPathFinder::getPathString() const
        {
                return this->paths.toString( this->pathseparator );
        }

        const EStringList &
        EPathFinder::getPath()
        {
                return this->paths;
        }

        string
        EPathFinder::getExtensionsString() const
        {
                return this->exts.toString( this->pathseparator );
        }

        const EStringList &
        EPathFinder::getExtensions()
        {
                return this->exts;
        }

        int
        EPathFinder::setPath( const string &p ) 
        { 
                return this->setPath( EStringList::split( p, this->pathseparator ) );
        }

        int
        EPathFinder::setPath( const EStringList &p ) 
        { 
                this->paths = p;
                return this->paths.count();
        }

        void
        EPathFinder::addPath( const string &p ) 
        { 
                //if( p.empty() ) return;
                this->paths += p;
                //CERR << "addPath( " << p << " ); path="<<this->paths.toString(":")<<endl;
        }


        int
        EPathFinder::setExtensions( const string &p ) 
        { 
                const EStringList & newp = EStringList::split( p, this->pathseparator );
                return this->setExtensions( newp );
        }

        int
        EPathFinder::setExtensions( const EStringList &e ) 
        {
                this->exts = e;
                //CERR << "setExtensions( " << this->exts << " );"<<endl;
                return this->exts.count();
        }

        void
        EPathFinder::addExtension( const string &p ) 
        { 
                this->exts += p;
                //CERR << "addExtension( " << p << " ); extensions="<<this->exts<<endl;
        }

        // static
        bool
        EPathFinder::isAccessible( const string &path ) 
        { 

                int err = access( path.c_str(), R_OK );
                if( err != 0 )
                {
                        // LIBE_VERBOSE << "exists("<<path<<"): access() returned error: "<<err<<endl;
                }
                return err == 0;
        }


        string
        EPathFinder::basename( const std::string & name )
        {
                string::size_type slashat = name.find_last_of( EPathFinder::getDirectorySeparator() );
                if( slashat == string::npos ) return name;
                return name.substr( slashat + 1 );
        }



        string 
        EPathFinder::find( const string & resource ) const
        {
                static const std::string NOT_FOUND = "EPathFinder::find() : no findie";
                if( resource.empty() ) return string();
                string checkat;

#define CHECKPATH(CHECKAT) checkat = CHECKAT; \
        if( ! checkat.empty() && EPathFinder::isAccessible( checkat ) ) \
        { this->hitcache[resource] = checkat; return checkat; }

                //LIBE_VERBOSE << "find( " << resource << " )" << endl;
                checkat = this->hitcache[resource];
                if( checkat == NOT_FOUND ) return string();
                if( ! checkat.empty() ) return checkat;

                CHECKPATH(resource);

                EStringList::const_iterator piter = this->paths.begin();
                EStringList::const_iterator eiter = this->exts.begin();
    
                string path;
                string ext;

                if( EPathFinder::isAccessible( resource ) ) return resource;

                piter = this->paths.begin();
                string checkhere;
                while( piter != this->paths.end() )
                {
                        path = (*piter);
                        if( ! path.empty() )
                        {
                                path += EPathFinder::getDirectorySeparator();
                        }
                        ++piter;
                        checkhere = path + resource; 
                        //LIBE_VERBOSE << "find( " << resource << " ) checking " << checkhere << endl;
                        CHECKPATH( checkhere );
                        eiter = this->exts.begin();
                        while( eiter != this->exts.end() )
                        {
                                ext = (*eiter);
                                ++eiter;
                                checkhere = path + resource + ext;
                                //LIBE_VERBOSE << "find( " << resource << " ) checking " << checkhere << endl;
                                CHECKPATH( checkhere );
                        }
                }
                //LIBE_VERBOSE << "find( "<<resource<<" ): not found :(" << endl;
                this->hitcache[resource] = NOT_FOUND;
                return string();
        }    
