#ifndef IMPORT_H
#define IMPORT_H
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include "hub/hub.h"
#include "hub/location.h"
#include "util/msg.h"
#include "util/gaugemsg.h"
#include "util/gzstream.h"

// ===========================================================
//	common import interface
// -----------------------------------------------------------
class Import {
public:
    typedef std::vector<hub::Location> Destinations;
    virtual void operator() (std::istream*, const std::string&, Destinations&)=0;
    virtual ~Import (){}
};

// ===========================================================
//  import start scenario
//  0. interactive: available languages list with suffixes (&compressions) generated for tk_getOpenFile
//  1. filename with suffix
//  2. based on the suffix, an ImportLang object is selected
//              - user error: language not available
//  3. interactive: compression list generated, default compression derived from filename suffix
//  4. compression scheme obtained
//  5. imput stream / decompression stream opened
//              - user error: file access, wrong compression
//  6. the ImportLang generates default DestLocationNames for destination, partly based on the filename
//  7. the ImportLang generates default DestLocationNames for primitives library if required
//  8. existing parameters and/or user input are projected into both DestLocationNames
//              - user warning/error: fixed fields overwritten
//  9. all DestLocationNames are turned into DestLocation
//              - user error: required fields missing
// 10. the Importlang provides an Import object
// 11. the Import object accepts all DestLocations
// 12. that object is run
// ===========================================================
class ImportLang {
public:
    typedef std::vector <ImportLang*> TRegistry;
private:
    std::string name_;
    std::vector <std::string> suffixes_;
protected:
    static TRegistry registry_;
public:
    static ImportLang*  byName    (const std::string&);  // select ImportLang by name
    static ImportLang*  bySuffix  (const std::string&);  // select ImportLang by suffix
           ImportLang*  addSuffix (const std::string&);  // add a suffix and return ptr fro ude in enregister
     const std::string& name (void) const { return name_; }
      bool hasSuffix             (const std::string&) const;
   virtual Import*      getImporter (hub::Hub*)=0;
   virtual void         getDefaults (hub::Hub*, const std::string&, Import::Destinations&)=0;
           ImportLang            (const std::string&);
    static const TRegistry& exportRegistry (void) { return registry_; }
    static std::string bareName (const std::string&);
    virtual ~ImportLang() {};
};
// ===========================================================
class ImportStream {
public:
    typedef std::vector <ImportStream*> TRegistry;
private:
    std::string name_;
    std::vector <std::string> suffixes_;
protected:
    static TRegistry registry_;
    static ImportStream* default_;
public:
    static ImportStream* getDefault (void) { return default_; }
    static ImportStream* byName     (const std::string&);    // select stream by name
    static ImportStream* byExistence      (std::string&);    // select existing stream and return the real name
    static ImportStream* bySuffix   (const std::string&);    // select stream by suffix
           ImportStream* addSuffix  (const std::string&);    // add a suffix and return ptr fro ude in enregister
    const std::string&   name        (void) const { return name_; }
    bool                 hasSuffix  (const std::string&) const;
    std::string          hasFile    (const std::string&);
    ImportStream (const std::string&);
    static const TRegistry& exportRegistry (void) { return registry_; }
    virtual std::istream* getStream (void)=0;
    virtual std::istream* getStream (const std::string&, msg::Talker* = NULL)=0;
    virtual void openStream (std::istream*, const std::string&, msg::Talker* = NULL)=0;
    virtual void closeStream (std::istream*)=0;
    virtual ~ImportStream() {};
};
// ===========================================================
class PlainImportStream: public ImportStream {
public:
    PlainImportStream (const std::string&);
    static void enregister (void);
    virtual std::istream* getStream (void);
    virtual std::istream* getStream (const std::string&, msg::Talker* = NULL);
    virtual void openStream (std::istream*, const std::string&, msg::Talker* = NULL);
    virtual void closeStream (std::istream*);
    class MeteredBuf: public std::filebuf {
        msg::Talker* talker;
        GaugeMsg gmsg;
    public:
        MeteredBuf (msg::Talker* t=NULL): talker (t) {};
        bool open (const std::string&, msg::Talker* = NULL);
        virtual int underflow(); 
        virtual int uflow(); 
    };
};
// ===========================================================
class GzImportStream: public ImportStream {
public:
    GzImportStream (const std::string&);
    static void enregister (void);
    virtual std::istream* getStream (void);
    virtual std::istream* getStream (const std::string&, msg::Talker* = NULL);
    virtual void openStream (std::istream*, const std::string&, msg::Talker* = NULL);
    virtual void closeStream (std::istream*);
    class MeteredBuf: public gzstreambuf {
        msg::Talker* talker;
        GaugeMsg gmsg;
        size_t count;
    public:
        MeteredBuf (msg::Talker* t=NULL): talker (t), count (0) {};
        bool open (const std::string&, msg::Talker* = NULL);
        virtual int underflow(); 
        virtual int uflow(); 
    };
};
// ===========================================================
class ImportCtx {
    std::string lang_;
public:
    ImportCtx (const std::string&);
    ImportCtx (const ImportCtx&);
    ImportCtx (int);
    std::string tell (void) const;
};
#endif
