#ifndef __DCL_TEXT_TEMPLATE_H__
#define __DCL_TEXT_TEMPLATE_H__     20060104

#ifndef __DCL_STRING_H__
#include <dcl/core/String.h>
#endif
#ifndef __DCL_OBJECT_H__
#include <dcl/core/Object.h>
#endif
#ifndef __DCL_EXCEPTION_H__
#include <dcl/core/Exception.h>
#endif
#ifndef __DCL_STREAM_H__
#include <dcl/core/Stream.h>
#endif
#ifndef __DCL_COLLECTION_VECTOR_H__
#include <dcl/core/CollectionVector.h>
/*
struct DCLCAPI StrStrAssoc
{
    String  key;
    String  value;

    StrStrAssoc() {}
    StrStrAssoc(const String& key, const String& value)
    {
        this->key = key;
        this->value = value;
    }
};
*/
#endif
#ifndef __DCL_SQL_H__
#include <dcl/core/SQL.h>
// class SQLFields
#endif

// sub block
// <!-- BEGIN name -->
// <!-- END name -->
__DCL_BEGIN_NAMESPACE

class DCLCAPI TextTemplate : public Object
{
    DECLARE_CLASSINFO(TextTemplate)
public:
    TextTemplate();
    TextTemplate(const TextTemplate& src);
    TextTemplate(const String& strFileName)
            __DCL_THROWS1(IOException*);

    virtual ~TextTemplate();

    TextTemplate& operator = (const TextTemplate& src);

    // main ==> strFileName
    void open(const String& strFileName)
            __DCL_THROWS1(IOException*);    

    // strName ==> strFileName, insert sub template
    void open(const String& strName, const String& strFileName)
            __DCL_THROWS1(IOException*);

    void clear();

    void reset();

    void erase(const char* pszMacro);

    // RETURN : assigned count
    int assign(const char* pszMacro, const String& strValue);
    int assign(const char* pszMacro, const TextTemplate& t);
    int assign(const char* pszMacro);
    int assign(const StrStrAssocVector& vStrToStr);
    int assign(_CONST SQLFields& fields, const String& strFieldIsNull);

    int append(const char* pszMacro, const String& strValue);
    int append(const char* pszMacro, const TextTemplate& t);
    int append(const char* pszMacro);
    int append(const StrStrAssocVector& vStrToStr);
    int append(_CONST SQLFields& fields, const String& strFieldIsNull);

#ifdef __DCL_DEBUG
    void showNullMacro(bool bShow, bool bWithSubTemplate);
#endif
    void printTo(OutputStream& out) const
            __DCL_THROWS1(IOException*);

    // REF sub Template Object, strName이 없으면 새로운 객체 리턴
    TextTemplate& operator [] (const String& strName);
    // strName이 있으면 객체의 주소, 없으면 NULL
    TextTemplate* atP(const String& strName) const;
    bool exists(const String& strName, bool bSubTemplate = true) const;

protected:
    // override members
    virtual String onSQLFieldValue(_CONST SQLField& field, const String& strFieldIsNull);

protected:
    void*   m_pTextList;
    void*   m_pSubTemplateMap;
#ifdef __DCL_DEBUG
    bool    m_bShowNullMacro;
#endif

    // sub 템플릿을 분할할하고 parseHelper를 호출하여
    // 분할된 블럭에서 sub 템플릿을 구성한다.
    // char* psz : parse는 regex를 사용한다. regexec는 NULL 종료
    // 문자열을 사용하기 때문에 parse 중간에 데이터를 NULL 종결 문자열로
    // 만들어서 처리한다.
    void parseHelper(const char* psz);
    void parse(char* psz);

    int append(const char* pszMacro, const String& strValue, bool bClearExists);
    int append(const char* pszMacro, const TextTemplate& t, bool bClearExists);
    int append(const StrStrAssocVector& vStrToStr, bool bClearExists);
    int append(_CONST SQLFields& fields, const String& strFieldIsNull, bool bClearExists);
};

DCLCAPI inline OutputStream& operator << (OutputStream& out, TextTemplate& t)
{
    t.printTo(out);
    return out;
}

inline int TextTemplate::assign(const char* pszMacro, const String& strValue)
{
    return append(pszMacro, strValue, true);
}

inline int TextTemplate::assign(const char* pszMacro, const TextTemplate& t)
{
    return append(pszMacro, t, true);
}

inline int TextTemplate::assign(const char* pszMacro)
{
    return append(pszMacro, (*this)[pszMacro], true);
}

inline int TextTemplate::assign(const StrStrAssocVector& vStrToStr)
{
    return append(vStrToStr, true);
}

inline int TextTemplate::assign(_CONST SQLFields& fields, const String& strFieldIsNull)
{
    return append(fields, strFieldIsNull, true);
}

inline int TextTemplate::append(const char* pszMacro, const String& strValue)
{
    return append(pszMacro, strValue, false);
}

inline int TextTemplate::append(const char* pszMacro, const TextTemplate& t)
{
    return append(pszMacro, t, false);
}

inline int TextTemplate::append(const char* pszMacro)
{
    return append(pszMacro, (*this)[pszMacro], false);
}

inline int TextTemplate::append(const StrStrAssocVector& vStrToStr)
{
    return append(vStrToStr, false);
}

inline int TextTemplate::append(_CONST SQLFields& fields, const String& strFieldIsNull)
{
    return append(fields, strFieldIsNull, false);
}

__DCL_END_NAMESPACE


#endif  // __DCL_TEXT_TEMPLATE_H__