#ifndef EXPORT_H
#define EXPORT_H
#include <iostream>
#include <fstream>
#include <string>
#include "hub/hub.h"
#include "util/indent.h"
#include "util/gaugemsg.h"
#include "util/gzstream.h"
#include "hub/location.h"
#include "hub/behavioral.h"

// #define dbg
#include "hub/reg.h"		        // export bimethods
// #undef dbg
// ===========================================================
//	common export interface
// -----------------------------------------------------------
class Export {

public:								// because of output representers
    typedef hub::Location Source;
    std::ostream* out_;
    newline_base  nlbase_;
    newline nl_;

    Export (void): nl_ (nlbase_) {}
    virtual void operator() (std::ostream* os, hub::Location* src)=0;

    virtual ~Export() {}
	static hub::StatDoubleReg <bool, Export&, hub::BehavDescr&> exportMap;
};

// ===========================================================
//  export start scenario
//  0. interactive: available languages list generated for radiobuttons etc.
//  1. interactive: available compression schemes listed
//  2. based on button/name, an ExportLang object is selected
//              - user error: language not available
//  3. the ExportLang generates default SourceLocationNames for source
//  4. existing parameters and/or user input are projected into SourceLocationNames
//  5. SourceLocationNames are turned into SourceLocation
//              - user error: required fields missing
//              - user error: location does not exist
//  6. Default suffix obtained
//  6. compression scheme obtained, default suffix
//  7. interactive: a list of file types with suffixes and compression generated for tk_getSaveDialog
//  6. complete filename obtained
//  7. output stream opened with compression
//              - user error: file access
//  7. the Exportlang provides an Export object
//  9. that object is run
// ===========================================================
class ExportLang {
public:
    typedef std::vector <ExportLang*> TRegistry;
private:
    std::string name_;
    std::vector <std::string> suffixes_;
protected:
    static TRegistry registry_;
public:
    static ExportLang* byName (const std::string&);    // select ExportLang by name
    static ExportLang* bySuffix (const std::string&);  // select ExportLang by suffix
    ExportLang* 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;
    ExportLang (const std::string&);
    static const TRegistry& exportRegistry (void) { return registry_; };
    const std::vector <std::string>& exportSuffixes (void) { return suffixes_; };
    const std::string defaultSuffix (void);
    virtual Export* getExporter (hub::Hub&)=0;
    virtual void getDefaults (hub::Hub* h, const std::string& fn, Export::Source&)=0;
    virtual ~ExportLang() {};
};

// ===========================================================
class ExportStream {
public:
    typedef std::vector <ExportStream*> TRegistry;
private:
    std::string name_;
    std::vector <std::string> suffixes_;
protected:
    static TRegistry registry_;
    static ExportStream* default_;
public:
    static ExportStream* getDefault (void) { return default_; }
    static ExportStream* byName (const std::string&);    // select stream by name
    static ExportStream* bySuffix (const std::string&);  // select stream by suffix
    ExportStream* 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;
    ExportStream (const std::string&);
    static const TRegistry& exportRegistry (void) { return registry_; }
    const std::vector <std::string>& exportSuffixes (void) { return suffixes_; }
    virtual std::ostream* getStream (void)=0;
    virtual std::ostream* getStream (const std::string&, msg::Talker* = NULL)=0;
    virtual void openStream (std::ostream*, const std::string&, msg::Talker* = NULL)=0;
    virtual void closeStream (std::ostream*)=0;
    virtual ~ExportStream() {};
};
// ===========================================================
class PlainExportStream: public ExportStream {
public:
    PlainExportStream (const std::string&);
    static void enregister (void);
    virtual std::ostream* getStream (void);
    virtual std::ostream* getStream (const std::string&, msg::Talker* = NULL);
    virtual void openStream (std::ostream*, const std::string&, msg::Talker* = NULL);
    virtual void closeStream (std::ostream*);
    class MeteredBuf: public std::filebuf {
        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 overflow(int c = EOF); 
    };
};
// ===========================================================
class GzExportStream: public ExportStream {
public:
    GzExportStream (const std::string&);
    static void enregister (void);
    virtual std::ostream* getStream (void);
    virtual std::ostream* getStream (const std::string&, msg::Talker* = NULL);
    virtual void openStream (std::ostream*, const std::string&, msg::Talker* = NULL);
    virtual void closeStream (std::ostream*);
    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 overflow(int c = EOF); 
    };
};
// ===========================================================
class ExportCtx {
    std::string lang_;
public:
    ExportCtx (const std::string&);
    ExportCtx (const ExportCtx&);
    std::string tell (void) const;
};
#endif
