// Change History:
// DART Data Transfer
// 01/08/04 AV Development: Remove MacroDef to fix bug #55
// 12/09/03 AV Development: Remove env param from Execute. Make LastEnv type of Env
// 12/09/03 AV Development: Run all processes sequentially. Add LastThreadId
// 01/03/03 AV Development: BC6 conversion. const/none const
// 11/13/03 AV Development: Add MacroInfo to keep track of reports and fill MacroID
// 10/24/03 AV Development: return num of sub fields from SetMultiFile func

#ifndef AT_DDProc_H
#define AT_DDProc_H

#include "ddp_vectdef.h"
#include "ddp_field.h"
#include "retrieve/at_retrieve.h"
#include "ddp_macrodef.h"
#include "ddp_params.h"
#include "ddp_printfile.h"

class DDP_Session;
////////////////////////////////////////////////////////
// DDP_Process class
////////////////////////////////////////////////////////
class DDP_Process
{
private:
    enum RunParameters { ARG_CNT = 3 };
    uint ID;
    void * hEvent;
    bool Active;
        
protected:
    class Env
    {
    private:
        uint VarCount;
        uint Size;
        byte ** _Env;
        enum EnvParams { ENV_MAXPARAMS = 50 };
        uint Num;
    public:
        Env();
        ~Env();

        byte ** GetEnv() const { return _Env; }

        bool PutEnvVar(const byte * key, const byte * val);
        const byte * GetEnvVar(const byte * key) const;
        void SetNum(uint n) { Num = n; }
        uint GetNum() const { return Num; }
        bool Reload(const byte * fn);
        void Clear();
    };

protected:
    // copy fields
    std::vector<DDP_Field *> ScalarFields;
    std::vector<DDP_VectorDef *> VectorFields;

    std::string ProcessName;
    std::string LogFileName;
    
    std::string MakeType;
    DDP_PrintFile ParamFile;
    const DDP_Session * Session;
    Env * Environment;

    void DoCleanup(const byte * fn);
    const byte * get_session_file() const;
    const byte * get_session_id() const;

    // fields helper
    virtual uint get_scalar_count() const { return ScalarFields.size(); }
    virtual void clear_scalar();
    virtual const DDP_Field * get_scalar(uint num) const { return num < get_scalar_count() ?
        ScalarFields[num] : NULL; }
    virtual const byte * get_caption(uint num, byte * buf, uint sz) const {
        const DDP_Field * field = get_scalar(num);
        if(!field || !buf) return NULL;
        PORT_strncpy((char *)buf, (const char *)field->GetCaption(), sz);
        return buf; }
        
    virtual const DDP_Field * find_scalar_field(const DDP_Field * ff, uint & pos) const;
    
    virtual uint get_vector_count() const { return VectorFields.size(); }
    virtual void clear_vector();    
    virtual const DDP_VectorDef * get_vector(uint num) const { return num < get_vector_count() ?
        VectorFields[num] : NULL; }
    virtual bool vector_has_address(uint num) const { const DDP_VectorDef * vector = get_vector(num);
        return vector ? vector->HasAddress() : false; }
    virtual bool write_vector(uint i);

    virtual const DDP_VectorDef * find_vector_field(const DDP_VectorDef * ff, uint & pos) const;

    // parameters helpers
    const DDP_Params * get_params();
    const DDP_Params * get_params() const;
        
protected:
    // print helpers
    virtual bool print_app_info();
    bool print_ui_params();
    virtual bool print_database_info();
    virtual uint print_layout_info();
    virtual uint print_vect_info();

protected:
    virtual const byte * GetParamFileName(byte * buf, uint sz) const
        { if(!buf || !sz) return NULL;
            PORT_snprintf_1(buf, sz, "DDP_%sParam.ini", MakeType.c_str());
            return buf; }
    virtual const byte * GetRecListFileName(byte * buf, uint sz) const
        { if(!buf || !sz) return NULL;
            PORT_snprintf_1(buf, sz, "DDP_%sRecList.dat", MakeType.c_str());
            return buf; }

protected:
    static void _cleanup(const byte * fn);

    // environment variables-
    static const byte * GetPrefix() { return (const byte *)"~ATF~"; }
    static const byte * GetEnvNum() { return (const byte *)"ENV_NUM"; }
    static const byte * GetLaunchTime() { return (const byte *)"LAUNCH_TIME"; }
    static const byte * GetWorkPath() { return (const byte *)"WORK_PATH"; }
    static const byte * GetApplId() { return (const byte *)"APPL_ID"; }
    static const byte * GetParamFile() { return (const byte *)"PARAM_FILE"; }
    static const byte * GetMakeType() { return (const byte *)"MAKE_TYPE"; }
    static const byte * GetLogFile() { return (const byte *)"LOG_FILE"; }

    static const byte * GetDefaultEng() { return (const byte *)"AT_UIFactory.exe"; }
    static const byte * GetDefaultMake() { return (const byte *)"DDP_Make.fmk"; }

protected:
    // environment    
    bool new_env();
    Env * get_env() const { return Environment; }

  // ----------------------
  friend DDP_Session;

  // ------------------------
protected:
    // process interface
    virtual uint GetRecordCount() const { const DDP_Params * params = get_params();
        return params ? params->GetInt((const byte *)"RecordCount") : 0; }
      
public:
    DDP_Process(const byte * make, const byte * process, const DDP_Session * session);
    virtual ~DDP_Process();

    const DDP_Session * GetSession() const { return Session; }

    const byte * GetMake() const { return PORT_c_str(MakeType); }
    const byte * GetProcess() const { return PORT_c_str(ProcessName); }
    const byte * GetProcessLogFile(bool env = false) const { const Env * e = get_env();
        const byte * s = env && e ? e->GetEnvVar(GetLogFile()) : PORT_c_str(LogFileName);
        return s ? s : PORT_c_str(LogFileName); }
    uint64 GetProcessLogFileSize(bool env = false) const {
        const byte * fname = GetProcessLogFile(env);
        return  fname ? ARL_GetFileSize(fname) : 0;
    }

    bool ReloadEnv();

    uint GetID() const { return ID; }
    void SetID(uint id) { ID = id; }

    bool IsActive() const { return Active; }
    void SetActive(bool active) { Active = active; }
    
    virtual bool InitEnv();

    virtual bool AddScalar(const DDP_Field * Field);
    virtual bool AddVector(const DDP_VectorDef * Vector);
    virtual bool SetScalarFields(const DDP_ExportDef ** Fields);
    virtual bool SetVectorFields(const DDP_ExportDef ** Vectors);

    bool DumpParams(const DDP_ExportDef** Fields,
        const DDP_ExportDef** Vectors);
    virtual bool Dump();
    
    virtual byte ** GetArgs(uint & cnt) const;
    virtual Env * GetEnv() const   { return get_env(); }
    virtual byte * GetCleanupFile(byte * fn, uint sz, bool CleanTemp);
    const byte * GetProcessTime() const { const Env * e = get_env();
        return e ? e->GetEnvVar(GetLaunchTime()) : NULL; }

    void ReleaseEnv();

    bool RaiseEvent();
    void * GetEvent() const { return hEvent; }
    bool CloseEvent();
    bool Execute();
    
    virtual bool Cleanup(bool tempOnly = false);

    // helpers
    static uint _spawn(bool wait, byte ** exe_args, byte ** env, DDP_Process * process);
    static void Run(void * arg);
    static uint TimeStamp(byte * buf, uint size);
    uint FilePrefix(byte * buf, uint sz, bool Temp = true);
};

////////////////////////////////////////////////////////
// DDP_Report class
////////////////////////////////////////////////////////
class DDP_RecListProcess : public DDP_Process
{
protected:
    const AT_Record_List * RecList;

    virtual bool IsKeepOrder() const { return false; }

protected:
    // override:
    virtual bool print_app_info();    

public:
    DDP_RecListProcess(const byte * make, const byte * process, const DDP_Session * session) :
        DDP_Process(make, process, session), RecList(NULL) {}
    virtual ~DDP_RecListProcess() {}

    void SetRecList(const AT_Record_List * rl);
    bool DumpRecList(const byte * file);
};

////////////////////////////////////////////////////////
// DDP_Report class
////////////////////////////////////////////////////////
class DDP_Report : public DDP_RecListProcess
{
private:
    std::string ReportFile;
    std::string ReportINI;
    std::string SubReportFields;
    std::string SubReportFieldWidths;
    uint AddressCount;

protected:
    DDP_PrintFile RptViewerINI;

    virtual bool vector_has_address(uint num) const { const DDP_VectorDef * vector = get_vector(num);
        return vector && vector->HasFormula() ? false :
            DDP_RecListProcess::vector_has_address(num); }

    virtual bool write_vector(uint i);            
    virtual bool print_database_info();
    virtual uint print_layout_info();
    virtual uint print_vect_info();

    //-----------------------Report-----------------------------------------------
    static const byte * GetReportFileName() { return (const byte *)"DDP_Report.dat"; }
    static const byte * GetRptViewFileName() { return (const byte *)"DDP_RptView.ini"; }
public:
    DDP_Report(const DDP_Session * session) :
        DDP_RecListProcess((const byte *)"Rpt", (const byte *)"Report Builder", session) {}
    virtual ~DDP_Report() {}

    virtual bool InitEnv();
    virtual bool Dump();
    virtual bool AddScalar(const DDP_Field * Field);
    virtual bool AddVector(const DDP_VectorDef * Vector);
};

////////////////////////////////////////////////////////
// DDP_Export class
////////////////////////////////////////////////////////
class DDP_Export : public DDP_RecListProcess
{
protected:
    std::string ExportType;
    std::string ExportFile;

protected:
    virtual const byte * get_caption(uint num, byte * buf, uint sz) const;
    virtual uint get_vector_count() const;
    virtual bool vector_has_address(uint num) const { return true; }

    virtual uint print_layout_info();
    virtual uint print_vect_info();

public:
    DDP_Export(const byte * make, const byte * process, const DDP_Session * session) :
        DDP_RecListProcess(make, process, session) {}
    virtual ~DDP_Export() {}

    bool SetExportType(const byte * type)
        { if(!type) return false; ExportType = (char *)type; return true; }
    void SetExportFile(const byte * file)
        { if(!file) ExportFile = "NULL";
            else ExportFile = (char *)file; }
};

////////////////////////////////////////////////////////
// DDP_Export class
////////////////////////////////////////////////////////
class DDP_DataExport : public DDP_Export
{
private:
    std::vector<const DDP_Field *> SplitFileFields;
    std::vector<const DDP_Field *> SplitTableFields;
    
    std::vector<const DDP_Field *> SortFields;
    std::vector<const DDP_VectorDef *> SortVectorFields;

    bool AutoSave;

    bool MakeLogFileName();

protected:
    virtual uint print_layout_info();
    virtual uint print_vect_info();
        
    virtual bool print_app_info();
    virtual bool print_field(DDP_Field * field, const byte * skey);

    virtual bool IsKeepOrder() const { return !(SortFields.size() || SortVectorFields.size()); }

public:
    DDP_DataExport(const DDP_Session * session) :
        DDP_Export((const byte *)"Exp", (const byte *)"Export", session), AutoSave(true) {}
    virtual ~DDP_DataExport();

    uint SetMultiFile(const DDP_Field** fields);
    void SetAutoSave(bool as) { AutoSave = as; }

    virtual bool Dump();
};

////////////////////////////////////////////////////////
// DDP_BrowseExport class
////////////////////////////////////////////////////////
class DDP_BrowseExport : public DDP_Export
{
private:
    const AT_Index * Index;
    
protected:
    // overrides:
    virtual bool print_app_info() { return DDP_Process::print_app_info(); }

public:
    DDP_BrowseExport(const DDP_Session * session) :
        DDP_Export((const byte *)"Exp", (const byte *)"Browse Export", session),
            Index(NULL) {}
    virtual ~DDP_BrowseExport() {}

    virtual void SetIndex(const AT_Index * index);
};


#endif

