// EPathFinder.h
#ifndef PATHFINDER_H
#define PATHFINDER_H

/**********************************************************************
 ** Author: stephan beal (stephan@wanderinghorse.net).  
 ** License: See LICENSE file in this directory.
 **
 **********************************************************************/

#include <string>
#include <list>
#include <map>
#include "EStringList.h"
using namespace std; // todo: explicitely std:: all members.
class EPathFinder 
{
public:
        /*
          operator << adds this object's path to os.
        */
        friend ostream & operator << (ostream &os, const EPathFinder &);
        friend string & operator << (string &os, const EPathFinder &);

        /*
          Add p to this object's path.
        */
        friend EPathFinder & operator += (EPathFinder &list, const string &p);


        /**
           Creates object with the given path/extension list and path separator.
        */
        EPathFinder( const string &path = string(), const string &ext = string(), const string &pathsep = ":" );

        virtual ~EPathFinder() {};

        /**
           Returns a getPathSeparator()-separated string of all paths
           added via add/setPath().

           This /should/ be static, i think, but it's not, for reasons
           i'm not yet certain about.
        */
        string getPathString() const;
        const EStringList &getPath();

        void setPathSeparator( const string &sep );
        const string &getPathSeparator() const;

        /**
           Sets the path to p, which should be a ":"-delimited string.
           Returns the number of path elements parsed from p.
        */
        virtual int setPath( const string &p );
        virtual int setPath( const EStringList &p );

        /**
           Adds p to our path. May be ":"-delimited
        */
        virtual void addPath( const string &p );

        /**
           Adds a "search extension." Sample:

           finder.addExtension( ".txt:README" );

           Will now try all path combinations with the rightmost
           characters matching ext. Be sure to include a period if you
           want that searched (that is so this class can be used to
           find non-files or files without traditional-style
           extensions).
        */
        virtual void addExtension( const string &ext = string() );

        /**
           like addExtension(), but overwrites extension list.
        */
        virtual int setExtensions( const string &ext );
        virtual int setExtensions( const EStringList &p );

        /**
           Returns the getPathSeparator()-delimited listed of file
           suffixes to use when searching for a path.
        */
        string getExtensionsString() const;
        const EStringList &getExtensions();


        static bool isAccessible( const string &path );

        /**
           Returns the "base name" of the given string: any part
           following the final directory separator character.
         */
        static std::string basename( const std::string & );


        static string getDirectorySeparator() { return string("/"); }
    
        /**
           Returns the full path of the given resource, provided it could be found
           in all paths or with all extensions added and provided it is readable.
           Note that this might return a relative path, especially if the
           resourcename passed to it immediately resolves to an existing resource.
           It returns an empty string if the resourcename cannot be found in
           the filesystem tree (or is otherwise unaccessible).
        */
        string find( const string &resourcename ) const;

private:
        EStringList paths;
        EStringList exts;
        string pathseparator;

        typedef std::map<std::string,std::string> StringStringMap;
        typedef StringStringMap::iterator StringStringIterator;

        mutable StringStringMap hitcache;

};

#include <stdlib.h>
class BinPathFinder : public EPathFinder
{
public:
        BinPathFinder() : EPathFinder( getenv( "PATH" ) ) {};
        virtual ~BinPathFinder(){};
};
#endif // PATHFINDER_H
