#include "export.h"
#include "hub/location.h"
#include "util/gzstream.h"
#include "util/gaugemsg.h"

using namespace hub;
//
//	exportMap can run uninitialized, 
//	allocates internal map on request by Enlist()
//
StatDoubleReg <bool, Export&, BehavDescr&> Export::exportMap;

using namespace std;
// ===========================================================
ExportLang::TRegistry ExportLang::registry_;
// -----------------------------------------------------------
ExportLang* ExportLang::byName (const std::string& sought) {    // select ExportLang by name
    for (TRegistry::const_iterator lg = registry_.begin(); lg != registry_.end(); lg++) {
        if (sought == (*lg)->name()) return (*lg);
    }
    return NULL;
}
// -----------------------------------------------------------
ExportLang* ExportLang::bySuffix (const std::string& sought) {  // select ExportLang by suffix
    for (TRegistry::const_iterator lg = registry_.begin(); lg != registry_.end(); lg++) {
        if ((*lg)->hasSuffix(sought)) return (*lg);
    }
    return NULL;
}
// ------------------------------------------------------------
ExportLang* ExportLang::addSuffix (const std::string& added) { 
    suffixes_.push_back (added);
    return this;
}
// ------------------------------------------------------------
bool ExportLang::hasSuffix (const std::string& sought) const {
    for (vector <string>::const_iterator sf = suffixes_.begin(); sf != suffixes_.end(); sf++) {
        if ((*sf) == sought) return true;
    }
    return false;
}
// ------------------------------------------------------------
ExportLang::ExportLang (const std::string& n): name_(n) {}

// ------------------------------------------------------------
const string ExportLang::defaultSuffix (void) {
    if (suffixes_.empty()) return string("");
    return suffixes_[0];
}

// ===========================================================
ExportStream::TRegistry ExportStream::registry_;
ExportStream* ExportStream::default_;
// -----------------------------------------------------------
ExportStream* ExportStream::byName (const std::string& sought) {    // select ExportStream by name
    for (TRegistry::const_iterator lg = registry_.begin(); lg != registry_.end(); lg++) {
        if (sought == (*lg)->name()) return (*lg);
    }
    return NULL;
}
// -----------------------------------------------------------
ExportStream* ExportStream::bySuffix (const std::string& sought) {  // select ExportStream by suffix
    for (TRegistry::const_iterator lg = registry_.begin(); lg != registry_.end(); lg++) {
        if ((*lg)->hasSuffix(sought)) return (*lg);
    }
    return NULL;
}
// ------------------------------------------------------------
ExportStream* ExportStream::addSuffix (const std::string& added) { 
    suffixes_.push_back (added);
    return this;
}
// ------------------------------------------------------------
bool ExportStream::hasSuffix (const std::string& sought) const {
    for (vector <string>::const_iterator sf = suffixes_.begin(); sf != suffixes_.end(); sf++) {
        if ((*sf) == sought) return true;
    }
    return false;
}
// ------------------------------------------------------------
ExportStream::ExportStream (const std::string& n): name_(n) {}

// ============================================================
GzExportStream::GzExportStream (const std::string& n): ExportStream(n) {}

void GzExportStream::enregister (void) {
    registry_.push_back((new GzExportStream ("GZIP"))->addSuffix (".gz"));
}

std::ostream* GzExportStream::getStream (void) {
    MeteredBuf* gzbuf = new MeteredBuf;
    return new ostream (gzbuf);
}

std::ostream* GzExportStream::getStream (const std::string& n, msg::Talker* t) {
    MeteredBuf* gzbuf = new MeteredBuf;
    std::ostream* s = new ostream (gzbuf);
    if (!gzbuf->open (n,t)) s->setstate (ios::failbit);
    return s;
}

void GzExportStream::openStream (std::ostream* s, const std::string& n, msg::Talker* t) {
    MeteredBuf* gzbuf = dynamic_cast<MeteredBuf*>(s->rdbuf());
    if (!gzbuf->open (n,t)) s->setstate (ios::failbit);
}

void GzExportStream::closeStream (std::ostream* s) {
    MeteredBuf* gzbuf = dynamic_cast<MeteredBuf*>(s->rdbuf());
    s->clear();
    gzbuf->close();
}
// ============================================================
bool GzExportStream::MeteredBuf::open (const std::string& name, msg::Talker* t) {
    talker = t;
    if (!gzstreambuf::open (name.c_str(), std::ios::out)) return false;
    if (talker) {
        count=0;
        gmsg.gaugeType (GaugeMsg::tick);
        gmsg.range (1);
        gmsg.progress (0);
        talker->broadcast (&gmsg);
    }
    return true;
}
// ------------------------------------------------------------
int GzExportStream::MeteredBuf::overflow (int c) {
    if (talker) {
        count++;
        if ((count & 0x7) == 0) {
            talker->broadcast (&gmsg);
        }
    }
//  std::cout << "overflow" << std::endl;
    return gzstreambuf::overflow (c);
}

// ============================================================
PlainExportStream::PlainExportStream (const std::string& n): ExportStream(n) {}

void PlainExportStream::enregister (void) {
    default_ = new PlainExportStream ("none");
    registry_.push_back(default_);
}

std::ostream* PlainExportStream::getStream (void) {
    MeteredBuf* buf = new MeteredBuf;
    return new ostream (buf);
}

std::ostream* PlainExportStream::getStream (const std::string& n, msg::Talker* t) {
    MeteredBuf* buf = new MeteredBuf;
    std::ostream* s = new ostream (buf);
    if (!buf->open (n,t)) s->setstate (ios::failbit);
    return s;
}

void PlainExportStream::openStream (std::ostream* s, const std::string& n, msg::Talker* t) {
    MeteredBuf* buf = dynamic_cast<MeteredBuf*>(s->rdbuf());
    if (!buf->open (n,t)) s->setstate (ios::failbit);
}
void PlainExportStream::closeStream (std::ostream* s) {
    MeteredBuf* buf = dynamic_cast<MeteredBuf*>(s->rdbuf());
    s->clear();
    buf->close();
}
// ============================================================
bool PlainExportStream::MeteredBuf::open (const std::string& name, msg::Talker* t) {
    talker = t;
    if (!filebuf::open (name.c_str(), std::ios::out)) return false;
    if (talker) {
        count=0;
        gmsg.gaugeType (GaugeMsg::tick);
        gmsg.range (1);
        gmsg.progress (0);
        talker->broadcast (&gmsg);
    }
    return true;
}
// ------------------------------------------------------------
int PlainExportStream::MeteredBuf::overflow (int c) {
    if (talker) {
        count++;
        if ((count & 0x7) == 0) {
            talker->broadcast (&gmsg);
        }
    }
//  std::cout << "overflow" << std::endl;
    return filebuf::overflow (c);
}
// ============================================================
ExportCtx::ExportCtx (const std::string& lang): lang_(lang) {}
ExportCtx::ExportCtx (const ExportCtx& that): lang_(that.lang_) {}
std::string ExportCtx::tell (void) const { return "export to "+lang_; }
