/***********************************************************************
  Copyright (c) 1998 Telelogic AB 

  File:   om2cpp.cc

  This file is provided strictly on an as-is basis
  
  All rights reserved. No part of this document or computer program
  may be reproduced, transmitted, transcribed, or translated into any
  language in any form by any means without prior written permission
  of Telelogic AB, in accordance with the terms and conditions
  stipulated in the agreement or contract under which the program(s)
  have been supplied.

  Information in this document or computer program is subject to
  change without notice.
************************************************************************/

#include "stlmini.h"
#include "omaccess.h"

#ifndef EXIT_SUCCESS    
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
#endif


void GenerateClassDeclaration (const OMModule &omModule,
                               const Class &omClass,
                               ostream &os)
{
  const char *tab = "  ";
  
  // Class names
  os << "// class " << omClass.name << "\n\n";
  os << "class " << omClass.name;
  
  list<string> superClassList;
  GetSuperClassList (omModule, omClass.name, &superClassList);

  if (! superClassList.empty ())
    os << " :";
  
  bool first = true;
  for (list<string>::iterator si = superClassList.begin();
       si != superClassList.end();
       si++)
  {
    if (! first)
      os << ",";
    first = false;
    os << " public " << *si; // ERROR - discriminator
  }

  os << " {\n";
  
  if (! omClass.operationList.empty ())
    os << "public:\n";

  for (list<Operation>::const_iterator oi = omClass.operationList.begin();
       oi != omClass.operationList.end();
       oi++)
  {
    const Operation &operation = *oi;
    
    os << tab;
    if (operation.returnType.size() > 0)
      os << operation.returnType << " ";
    else if (operation.name != omClass.name)
      os << "void ";
    // else no output - Special syntax for constructor/destructor

    os << operation.name << "(";

    list<Parameter>::const_iterator pi = operation.parameterList.begin();
    while (pi != operation.parameterList.end())
    {
      const Parameter &parameter = *pi;
      
      if (parameter.type.size() > 0)
        os << parameter.type << " ";
      os << parameter.name;
      pi++;
      if (pi != operation.parameterList.end())
        os << ", ";
    }
    os << ");\n";
  }

  if (! omClass.attributeList.empty())
    os << "\nprivate:\n";
  
  for (list<Attribute>::const_iterator ai = omClass.attributeList.begin();
       ai != omClass.attributeList.end();
       ai++)
  {
    const Attribute &attribute = *ai;

    os << tab;
    if (attribute.type.size() > 0)
      os << attribute.type << " ";

    os << attribute.name << ";\n";
  }

  os << "};\n\n";
}

#ifndef EXIT_SUCCESS
#define EXIT_SUCCESS 1
#endif
#ifndef EXIT_FAILURE
#define EXIT_FAILURE 0
#endif

main (int argc, char **argv) {
  if (argc != 3) {
    cout << "Usage: " << argv[0] << " <bufferId|filename> <filename>" << endl;
    return EXIT_FAILURE;
  }

  cout << "-" << argv[0] << "-" << argv[1] << "-" << argv[2] << endl;
  
  string bufferId = argv[1];
  string filename = argv[2];
  
  
  PMConnection pmConnection;
  string error;
  if (! pmConnection.Open(&error)) {
    cout << error << endl;
    return EXIT_FAILURE;
  }
  
  // Check if buffer id or file name
  if (! ((bufferId[0] >= '0') && (bufferId[0] <= '9'))) {
    // Its not a number, assume a file name and load it in OM editor
    
    // Make sure the diagram is loaded in the OM editor and get the buffer id
    OMEditorTool omeTool;
    if (! omeTool.RPCStart ()) {
      cout << "Could not connect to OM Editor" << endl
           << omeTool.GetErrorText() << endl;
      return EXIT_FAILURE;
    }

    cout << "Loading '" << bufferId << "' in OM Editor" << endl;
    
    int omBufferId;
    if (! omeTool.RPCLoad (bufferId, &omBufferId)) {
      cout << "Could not load file " << bufferId << " in OM Editor" << endl
           << omeTool.GetErrorText() << endl;
      return false;
    }

    // Calculate OM diagram bufferId as string
    ostrstream os;
    os << omBufferId << ends;
    bufferId = os.str();
  }
  
  OMAccessTool omTool;
  if (! omTool.RPCStart ()) {
    cout << "Could not connect to OM InfoServer." << endl
         << omTool.GetErrorText() << endl;
    return EXIT_FAILURE;
  }
  
  OMModule omModule;
  if (! omTool.RPCGetObjects (bufferId, &omModule)) {
    cout << "Could not get module objects." << endl
         << omTool.GetErrorText() << endl;
    return EXIT_FAILURE;
  }
  
  ofstream ofs (filename.c_str());
  if (! ofs) {
    cout << "Could not create output file: " << filename << endl
         << omTool.GetErrorText() << endl;
    return EXIT_FAILURE;
  }
  
  
  ofs << "// UML-Generated C++ header file\n\n";
  ofs << "// Forward declarations\n\n";
  
  for (list<Class>::iterator ci1 = omModule.classList.begin();
       ci1 != omModule.classList.end();
       ci1++)
  {
    const Class &omClass = *ci1;
    ofs << "class " << omClass.name << ";\n";
  }

  ofs << "\n";
  ofs << "// Class definitions\n\n";
  
  for (list<Class>::iterator ci = omModule.classList.begin();
       ci != omModule.classList.end();
       ci++)
  {
    const Class &omClass = *ci;
    GenerateClassDeclaration (omModule, omClass, ofs);
  }
  ofs << endl;
  ofs.close();

  cout << "Starting TE" << endl;
  
  TextEditorTool textTool;
  if (! textTool.RPCStart ()) {
    cerr << "Could not start text editor" << endl
         << textTool.GetErrorText() << endl;
    return EXIT_FAILURE;
  }
  
  cout << "loading TE" << endl;
  
  int textBufferId;
  if (! textTool.RPCLoadCopy (filename, &textBufferId)) {
    cerr << "Could not load file in text editor" << endl
         << textTool.GetErrorText() << endl;
    return EXIT_FAILURE;
  }

  cout << "showing TE" << endl;
  
  if (! textTool.RPCShow (textBufferId, "")) {
    cerr << "Could not show file in text editor" << endl
         << textTool.GetErrorText() << endl;
    return EXIT_FAILURE;
  }

  cout << "success" << endl;
  
  return EXIT_SUCCESS;
}

// end of file
