// **********************************************************************
//
// Copyright (c) 1999
// Object Oriented Concepts, Inc.
// Billerica, MA, USA
//
// All Rights Reserved
//
// **********************************************************************

#include <OB/CORBA.h>
#include <OB/Util.h>

#include <Types.h>
#include <GenCPP.h>

#include <stdlib.h>
#include <stdio.h>

static void
usage(const char* progName)
{
    cerr << "Usage:\n";
    cerr << progName << " [options] name-base\n"
      "\n"
      "Options:\n"
      "-h, --help               Show this message.\n"
      "-v, --version            Show ORBacus version.\n"
      "--no-skeletons           Don't generate skeletons.\n"
      "--no-type-codes          Don't generate type codes and insertion and\n"
      "                         extraction functions for the any type.\n"
      "--locality-constrained   Create locality-constrained objects.\n"
      "--no-virtual-inheritance Don't use virtual inheritance.\n"
      "--tie                    Generate tie classes.\n"
      "--c-suffix SUFFIX        Use SUFFIX as suffix for source files.\n"
      "                         The default value is `.cpp'.\n"
      "--h-suffix SUFFIX        Use SUFFIX as suffix for header files.\n"
      "                         The default value is `.h'.\n"
      "--header-dir DIR         Make #include statements for header files\n"
      "                         relative to DIR.\n"
      "--other-header-dir DIR   Make #include statements for header files\n"
      "                         for included IDL files relative to DIR.\n"
      "--output-dir DIR         Write generated files to directory DIR.\n"
      "--dll-import DEF         Put DEF in front of every symbol that needs\n"
      "                         an explicit DLL import statement.\n"
	;
}

int
run(int argc, char* argv[])
{
    //
    // Create ORB
    //
    CORBA_ORB_var orb = CORBA_ORB_init(argc, argv);

    //
    // Set program name
    //
    const char* progName = argv[0];

    //
    // Get options
    //
    bool noTC = false;
    bool local = false;
    bool noVirtual = false;
    bool noSkel = false;
    bool tie = false;
    CORBA_String_var relativeTo = CORBA_string_dup("");
    CORBA_String_var cSuff = CORBA_string_dup(".cpp");
    CORBA_String_var hSuff = CORBA_string_dup(".h");
    CORBA_String_var headerDir = CORBA_string_dup("");
    CORBA_String_var otherHeaderDir = CORBA_string_dup("");
    CORBA_String_var outDir = CORBA_string_dup("");
    CORBA_String_var dllImport = CORBA_string_dup("");

    CORBA_Long i;
    for(i = 1 ; i < argc && *argv[i] == '-' ; i++)
    {
	if(strcmp(argv[i], "--help") == 0 ||
	   strcmp(argv[i], "-h") == 0)
	{
	    usage(progName);
	    return 0;
	}
	else if(strcmp(argv[i], "--version") == 0 ||
		strcmp(argv[i], "-v") == 0)
	{
	    cerr << "ORBacus " << OBVersion << endl;
	    return 0;
	}
	else if(strcmp(argv[i], "--no-type-codes") == 0)
	{
	    noTC = true;
	}
	else if(strcmp(argv[i], "--locality-constrained") == 0)
	{
	    local = true;
	}
	else if(strcmp(argv[i], "--no-virtual-inheritance") == 0)
	{
	    noVirtual = true;
	}
	else if(strcmp(argv[i], "--no-skeletons") == 0)
	{
	    noSkel = true;
	}
	else if(strcmp(argv[i], "--tie") == 0)
	{
	    tie = true;
	}
	else if(strcmp(argv[i], "--c-suffix") == 0)
	{
	    if(++i < argc)
		cSuff = CORBA_string_dup(argv[i]);
	    else
	    {
		cerr << progName << ": argument expected for `"
		     << argv[i - 1] << "'" << endl;
		return 1;
	    }
	}
	else if(strcmp(argv[i], "--h-suffix") == 0)
	{
	    if(++i < argc)
		hSuff = CORBA_string_dup(argv[i]);
	    else
	    {
		cerr << progName << ": argument expected for `"
		     << argv[i - 1] << "'" << endl;
		return 1;
	    }
	}
	else if(strcmp(argv[i], "--header-dir") == 0)
	{
	    if(++i < argc)
		headerDir = CORBA_string_dup(argv[i]);
	    else
	    {
		cerr << progName << ": argument expected for `"
		     << argv[i - 1] << "'" << endl;
		return 1;
	    }
	}
	else if(strcmp(argv[i], "--other-header-dir") == 0)
	{
	    if(++i < argc)
		otherHeaderDir = CORBA_string_dup(argv[i]);
	    else
	    {
		cerr << progName << ": argument expected for `"
		     << argv[i - 1] << "'" << endl;
		return 1;
	    }
	}
	else if(strcmp(argv[i], "--output-dir") == 0)
	{
	    if(++i < argc)
		outDir = CORBA_string_dup(argv[i]);
	    else
	    {
		cerr << progName << ": argument expected for `"
		     << argv[i - 1] << "'" << endl;
		return 1;
	    }
	}
	else if(strcmp(argv[i], "--dll-import") == 0)
	{
	    if(++i < argc)
		dllImport = CORBA_string_dup(argv[i]);
	    else
	    {
		cerr << progName << ": argument expected for `"
		     << argv[i - 1] << "'" << endl;
		return 1;
	    }
	}
	else
	{
	    cerr << progName << ": unknown option `"
		 << argv[i] << "'\n" << endl;
	    usage(progName);
	    return 1;
	}
    }

    CORBA_Object_var obj;
    try
    {
        obj = orb -> resolve_initial_references("InterfaceRepository");
    }
    catch(CORBA_ORB::InvalidName&)
    {
    }
    if(CORBA_is_nil(obj))
    {
	cerr << "No `InterfaceRepository' initial reference." << endl;
	return 1;
    }

    CORBA_Repository_var repository = CORBA_Repository::_narrow(obj);
    if(CORBA_is_nil(repository))
    {
	cerr << "`InterfaceRepository' initial reference is not a repository."
             << endl;
	return 1;
    }
    
    
    if(i == argc)
    {
	cerr << progName << ": no file name base" << endl;
	usage(progName);
	return 1;
    }

    CORBA_String_var base = (const char*)argv[i++];

    if(i < argc)
    {
	cerr << progName << ": too many command line arguments" << endl;
	usage(progName);
	return 1;
    }

    IdlStringSeq_var fileNameSeq = new IdlStringSeq;

    //
    // Generate C++ mapping
    //
    IdlCPPGenerator generator(progName, repository, fileNameSeq, noTC,
			      local, noVirtual,
			      headerDir, otherHeaderDir,
			      dllImport, hSuff, cSuff);

// #ifdef WIN32
// 	    const char* name1 = strrchr(base, '\\');
// 	    const char* name2 = strrchr(base, '/');
// 	    const char* name = name1 > name2 ? name1 : name2;
// #else
// 	    const char* name = strrchr(base, '/');
// #endif
//     if(name)
//   	name++;
//     else
//  	name = base;

    const char* name = base;

    if(strlen(outDir))
    {
#ifdef WIN32
	outDir += '\\';
#else
	outDir += '/';
#endif
    }

    int status = generator.gen(outDir, name);
    
    if(status == 0 && !noSkel)
	status = generator.genSkel(outDir, name);
    
    if(status == 0 && tie)
	generator.genTie(outDir, name);

    return status;
}

int
main(int argc, char* argv[], char*[])
{
    int status;

    try
    {
	//
	// Generate code
	//
	status = run(argc, argv);
    }
    catch(CORBA_SystemException& ex)
    {
	OBPrintException(ex);
	status = 1;
    }

    return status;
}
