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

#include <OB/CORBA.h>
#include <Types.h>
#include <GenUtil.h>
#include <GenCPP.h>

// ----------------------------------------------------------------------
// Generate code for the skeleton header file, general part
// ----------------------------------------------------------------------

void
IdlCPPGenerator::genCPlusPlusSkelH(CORBA_Container_ptr container,
				   IdlPrettyPrint& out)
{
    //
    // Get scope and prefix
    // (prefix needed if alternative module mapping is used)
    //
    CORBA_String_var scope;
    CORBA_String_var pre;
    getScopeAndPrefix(container, scope.out(), pre.out());

    //
    // Get container contents descriptions
    //
    CORBA_Container::DescriptionSeq_var seq =
	container -> describe_contents(CORBA_dk_all, true, -1);

    CORBA_ULong i, j;

    for(i = 0 ; i < seq -> length() ; i++)
    {
	//
	// Get container
	//
	CORBA_Container_var cont =
	    CORBA_Container::_narrow(seq[i].contained_object);

	switch(seq[i].kind)
	{
	case CORBA_dk_Module:
	{
	    //
	    // Module
	    //
	    CORBA_ModuleDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    // Don't add this here!!!
	    // if(!check(desc -> id))
	    //     continue;

	    CORBA_Identifier_var name = fixKwd(desc -> name);

 	    comment(desc -> id, out);

	    out.sep();

	    assert(!CORBA_is_nil(cont));
	    genCPlusPlusSkelH(cont, out);

	    break;
	}

	case CORBA_dk_Interface:
	{
	    //
	    // Interface
	    //
	    CORBA_InterfaceDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(!check(desc -> id))
		continue;

	    CORBA_Identifier_var name = fixKwd(desc -> name);

	    comment(desc -> id, out);
	    
	    out.sep();
	    out << "\nclass " << pre << name << "_skel : ";

	    unsigned int indent = out.getIndent();
	    out.setIndent(out.getPos());

	    if(!noVirtual_)
		out << "virtual ";

	    out << "public " << pre << name;

	    if(desc -> base_interfaces.length() > 0)
	    {
		for(j = 0 ; j < desc -> base_interfaces.length() ; j++)
		{
		    const char* id = desc -> base_interfaces[j];
		    CORBA_ScopedName_var absolute = getAbsolute(id);

		    out << ",\n";

		    if(!noVirtual_)
			out << "virtual ";

		    out << "public " << absolute << "_skel";
		}
	    }
	    else
	    {
		out << ",\n";
		
		if(!noVirtual_)
		    out << "virtual ";
		
		out << "public CORBA_Object_skel";
	    }

	    out.setIndent(indent);

	    out.start();

	    out << '\n' << pre << name << "_skel(const "
		<< pre << name << "_skel&);";
	    out << "\nvoid operator=(const " << pre << name << "_skel&);";

	    assert(!CORBA_is_nil(cont));
	    genCPlusPlusSkelHProtected(cont, out);

	    out.sep();
	    out.dec();
	    out << "\npublic:";
	    out.inc();
	    out.sep();
	    out << '\n' << pre << name << "_skel() { }";

	    out.sep();
	    out << '\n' << pre << name << "_ptr _this() { return "
		<< pre << name << "::_duplicate(this); }";
	    out.sep();
	    out << "\nvirtual OBDispatchStatus _OB_dispatch(const char*, "
		<< "OBBuffer&, bool, CORBA_ULong, CORBA_ULong);";

	    assert(!CORBA_is_nil(cont));
	    genCPlusPlusSkelH(cont, out);

	    out.end();
	    out << ';';

	    break;
	}

	case CORBA_dk_Attribute:
	{
	    //
	    // Attribute
	    //
	    CORBA_AttributeDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(!check(desc -> id))
		continue;

	    CORBA_Identifier_var name = fixKwd(desc -> name);

	    comment(desc -> id, out);

	    CORBA_String_var ret = getTypeString(scope, desc -> type,
						 GetTypeReturn);

	    out.sep();
	    out << "\nvirtual " << ret << ' ' << name << "() = 0;";
	    
	    if(desc -> mode == CORBA_ATTR_NORMAL)
	    {
		CORBA_String_var in = getTypeString(scope, desc -> type,
						    GetTypeIn);
		out << "\nvirtual void " << name << '(' << in
		    << ") = 0;";
	    }

	    break;
	}

	case CORBA_dk_Operation:
	{
	    //
	    // Operation
	    //
	    CORBA_OperationDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(!check(desc -> id))
		continue;

	    CORBA_Identifier_var name = fixKwd(desc -> name);

	    comment(desc -> id, out);

	    CORBA_String_var ret =
		getTypeString(scope, desc -> result, GetTypeReturn);
	    
	    out.sep();
	    out << "\nvirtual " << ret << ' ' << name << "(";
	    
	    unsigned int indent = out.getIndent();
	    out.setIndent(out.getPos());

	    for(j = 0 ; j < desc -> parameters.length() ; j++)
	    {
		GetType tt;
		switch(desc -> parameters[j].mode)
		{
		case CORBA_PARAM_IN:
		    tt = GetTypeIn;
		    break;

		case CORBA_PARAM_INOUT:
		    tt = GetTypeInOut;
		    break;

		case CORBA_PARAM_OUT:
		    tt = GetTypeOut;
		    break;
		}

		CORBA_String_var argName = fixKwd(desc -> parameters[j].name);

		CORBA_String_var s =
		    getTypeString(scope, desc -> parameters[j].type, tt,
				  false, argName);

		if(j > 0)
		    out << ",\n";

		out << s;
	    }

	    if(desc -> contexts.length() > 0)
	    {
		if(desc -> parameters.length() > 0)
		    out << ",\n";
		
		out << "CORBA_Context_ptr";
	    }

	    out << ") = 0;";

	    out.setIndent(indent);

	    break;
	}

	default:
	    break;
	}
    }
}

// ----------------------------------------------------------------------
// Generate code for the skeleton header file, "protected" part
// ----------------------------------------------------------------------

void
IdlCPPGenerator::genCPlusPlusSkelHProtected(CORBA_Container_ptr container,
					    IdlPrettyPrint& out)
{
    //
    // Get scope and prefix
    // (prefix needed if alternative module mapping is used)
    //
    CORBA_String_var scope;
    CORBA_String_var pre;
    getScopeAndPrefix(container, scope.out(), pre.out());

    //
    // Get container contents descriptions
    //
    CORBA_Container::DescriptionSeq_var seq =
	container -> describe_contents(CORBA_dk_all, true, -1);

    CORBA_ULong i;
    bool first = true;

    for(i = 0 ; i < seq -> length() ; i++)
    {
	//
	// Get container
	//
	CORBA_Container_var cont =
	    CORBA_Container::_narrow(seq[i].contained_object);

	switch(seq[i].kind)
	{
	case CORBA_dk_Attribute:
	{
	    if(first)
	    {
		out.sep();
		out.dec();
		out << "\nprotected:";
		out.inc();
		first = false;
	    }

	    //
	    // Attribute
	    //
	    CORBA_AttributeDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(!check(desc -> id))
		continue;

	    CORBA_Identifier_var name = fixKwd(desc -> name);

	    comment(desc -> id, out);

	    //
	    // Don't use name here instead of desc -> name. We need
	    // the name "unfixed".
	    //
	    out.sep();
	    out << "\nOBDispatchStatus _OB_get_" << desc -> name
		<< "(OBBuffer&, bool, CORBA_ULong, CORBA_ULong);";
	    if(desc -> mode == CORBA_ATTR_NORMAL)
		out << "\nOBDispatchStatus _OB_set_" << desc -> name
		    << "(OBBuffer&, bool, CORBA_ULong, CORBA_ULong);";

	    break;
	}

	case CORBA_dk_Operation:
	{
	    if(first)
	    {
		out.sep();
		out.dec();
		out << "\nprotected:";
		out.inc();
		first = false;
	    }

	    //
	    // Operation
	    //
	    CORBA_OperationDescription* desc;
	    CORBA_Boolean b = seq[i].value >>= desc;
	    assert(b);

	    if(!check(desc -> id))
		continue;

	    CORBA_Identifier_var name = fixKwd(desc -> name);

	    comment(desc -> id, out);

	    //
	    // Don't use name here instead of desc -> name. We need
	    // the name "unfixed".
	    //
	    out.sep();
	    out << "\nOBDispatchStatus _OB_op_" << desc -> name
		<< "(OBBuffer&, bool, CORBA_ULong, CORBA_ULong);";
	    CORBA_String_var ret =
		getTypeString(scope, desc -> result, GetTypeReturn);

	    break;
	}

	default:
	    break;
	}
    }
}
