//
// FILE:
// parseOfx.C
//
// FUNCTION:
// Parses OFX dtd's
//
// HISTORY:
// Written by Linas Vepstas March 1998

#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <time.h>

#include "config.h"
#include "DtdParser.h"
#include "OutputCharStream.h"

#include "pfxBaseTypes.h"
#include "pfxCompTypes.h"
#include "pfxLangOut.h"
#include "pfxUtils.h"


// output messages is used to set up the SP parser
// to dump it's error messages to stderr
#define OUTPUT_MESSAGES

#ifdef OUTPUT_MESSAGES
#include "sptchar.h"
#include "MessageReporter.h"
#include "MessageTable.h"
#endif /* OUTPUT_MESSAGES */

#ifdef SP_NAMESPACE
namespace SP_NAMESPACE {
#endif

#ifdef OUTPUT_MESSAGES
#ifdef SP_MANUAL_INST

#define SP_DEFINE_TEMPLATES
#include "Owner.h"
#undef SP_DEFINE_TEMPLATES

#include "Message.h"

#ifdef SP_ANSI_CLASS_INST
template class Owner< Messenger>;
#else
typedef Owner< Messenger> Dummy_0;
#endif

#endif /* SP_MANUAL_INST */
#endif /* OUTPUT_MESSAGES */


static FileOutputByteStream standardOutput(1, 0);
static FileOutputByteStream standardError(2, 0);

#ifdef OUTPUT_MESSAGES

class MyMessageReporter
: public MessageReporter
{
  public:
    MyMessageReporter( const InputCodingSystem *, OutputCharStream *);
  private:
    Boolean getMessageText( const MessageFragment &, StringC &);
    const InputCodingSystem * codingSystem_;
};

MyMessageReporter::
MyMessageReporter( const InputCodingSystem * codesys,
                   OutputCharStream * errorStream)
: MessageReporter( errorStream),
  codingSystem_( codesys)
{
}

Boolean
MyMessageReporter::
getMessageText( const MessageFragment & frag, StringC & text)
{
  String<SP_TCHAR> str;
  if (!MessageTable::instance()->getText(frag, str))
    return 0;
#ifdef SP_WIDE_SYSTEM
  text.assign((const Char *)str.data(), str.size());
#else
  str += 0;
  text = codingSystem_->convertIn(str.data());
#endif
  return 1;
}

#endif /* OUTPUT_MESSAGES */

// ===========================================================

extern "C"

void Usage (char *progname)
{
    printf ("Usage: %s <dtdfile> \n", progname);
    exit (1);
}

int
main( int argc, char ** argv)
{
    if ( argc < 2) Usage (argv[0]);

    DtdParser parser;

    pfxCompoundType compoundTypeHandler;

#ifdef OUTPUT_MESSAGES
    Owner< Messenger> mgr;
    if ( argv[ 1][ 0] != '-' || argv[ 1][ 1] != 's' || argv[ 1][ 2] != '\0') {
        mgr = new MyMessageReporter( parser.codingSystem(),
                                     new EncodeOutputCharStream( &standardError,
                                                                 parser.codingSystem()));
        parser.setMessenger( mgr.pointer());
    }
#endif

    StringC sysid;
    parser.makeSystemId( argc - 1, argv + 1, sysid);
    ConstPtr< Dtd> dtd = parser.parseDtd( sysid);

    if ( dtd.isNull()) {
        printf ("Error: specified dtd %s was null \n", argv[1]);
        return 1;
    }

    // ----------------------------------------------------

    compoundTypeHandler.prtout = new pfxOutDecl;

    // ----------------------------------------------------
    // print everything
    time_t now = time (0);
    char * cnow = ctime (&now);

    printf ("//\n");
    printf ("// This file automatically generated by %s \n", argv[0]);
    printf ("// Do not edit -- your changes will be lost! \n");
    printf ("// Generated on %s \n", cnow);
    printf ("//\n");
    printf ("//\n");
    compoundTypeHandler.PrintBaseTypes (0);


    printf ("//----------------------------------------------\n");
    printf ("//\n");
    printf ("// Forward declarations of classes\n");
    printf ("//\n");
    printf ("//\n");
    const ElementType * type;
    Dtd::ConstElementTypeIter e( dtd->elementTypeIter());
    type = e.next();
    while ( type) {

        // see if is a base type
        char * varname = compoundTypeHandler.AddBaseVar (type);

        if (!varname) { 
            compoundTypeHandler.AddCompoundType (type);

            switch ( type->definition()->declaredContent()) {
              case ElementDefinition::modelGroup:
                break;
              case ElementDefinition::any: 
                break;
              default: {
                 char * vname = pfxCharify (type->name());
                 printf ("unexpected duuuuuuuuuuuuuuuuuuude: %s \n", vname);
                 delete vname;
              }
           }
        } 

        const AttributeDefinitionList * attlist = type->attributeDefTemp();
        if ( attlist) {
           printf (" attribute lists duuuuuuuuuuuuuuuuuuuuuuuuuude \n");
        }

        if ( !( type = e.next()))
          break;
        continue;
    }

    // ----------------------------------------------------
    // print  classes
    printf ("//----------------------------------------------\n");
    printf ("//\n");
    printf ("// Class declarations\n");
    printf ("//\n");
    printf ("//\n");

    Dtd::ConstElementTypeIter ee( dtd->elementTypeIter());
    type = ee.next();
    while ( type) {

        // see if is a base type
        char * varname = compoundTypeHandler.AddBaseVar (type);

        if (!varname) { 
            compoundTypeHandler.PrintClass (type);
        }

        type = ee.next();
    }

    // ----------------------------------------------------
    // print  constructors
    printf ("//----------------------------------------------\n");
    printf ("//\n");
    printf ("// Constructors\n");
    printf ("//\n");
    printf ("//\n");

    compoundTypeHandler.prtout = new pfxOutConstructor;

    Dtd::ConstElementTypeIter eee( dtd->elementTypeIter());
    type = eee.next();
    while ( type) {

        // see if is a base type
        char * varname = compoundTypeHandler.AddBaseVar (type);

        if (!varname) { 
            compoundTypeHandler.PrintClass (type);
        }

        type = eee.next();
    }
    return 0;
}

#ifdef SP_NAMESPACE
}
#endif
