#! /usr/bin/perl
#
#  rp-openr-stubgen2-body
#  Stub Generator preprocessor for Romote Processing OPEN-R
#  Copyright 2002 Sony Corporation
#

require 'getopts.pl';

sub CheckFuncname {
    $funcname = $_[0];
    $funcname =~ s/\s*$//; # remove the trailing whitespace
    if ( $funcname eq "null" ){
        return $funcname;
    } elsif ( $funcname !~ /\(\)\Z/ ){
        die "Missing () for function name.\n";
    } else {
        $funcname = $`;
        $funcname =~ s/\s*$//; # remove the trailing whitespace
        return $funcname;
    }
}

do Getopts('g');

if ( $opt_g ) {
    $use_gtk = 1;
    $msgflg = "IPC_NOWAIT";
    $msgfunc_ret = "gint";
    $msgfunc_arg = "gpointer ptr";
} else {
    $use_gtk = 0;
    $msgflg = "0";
    $msgfunc_ret = "int";
    $msgfunc_arg = "";
}

$countSubject = 0;
$countObserver = 0;
while ( <> ){
    chomp;
    if ( /^\s*ObjectName\s*:\s*(\S+)\s*/ ) {
        $objectName = $1;
    } elsif ( /^\s*NumOfOSubject\s*:\s*(\S+)\s*/ ) {
        $numOfOSubject = $1;
    } elsif ( /^\s*NumOfSubject\s*:\s*(\S+)\s*/ ) {
        $numOfOSubject = $1;
    } elsif ( /^\s*NumOfOObserver\s*:\s*(\S+)\s*/ ) {
        $numOfOObserver = $1;
    } elsif ( /^\s*NumOfObserver\s*:\s*(\S+)\s*/ ) {
        $numOfOObserver = $1;
    } elsif ( /^\s*Service\s*:\s*/ ) {
        @lineService = split( /\s*,\s*/, $' );
        $serviceName = shift(@lineService);
        @serviceElement = split( /\./, $serviceName );
        if ( $serviceElement[3] =~ /^S\"$/ ) { #"
            $subjectService[$countSubject] = $serviceName;
            $subjectSubname[$countSubject] = $serviceElement[1];
            $controlFunc[$countSubject] = CheckFuncname(shift(@lineService));
            $readyFunc[$countSubject] = CheckFuncname(shift(@lineService));
            $countSubject++;
        } elsif ( $serviceElement[3] =~ /^O\"$/ ) { #"
            $observerService[$countObserver] = $serviceName;
            $observerSubname[$countObserver] = $serviceElement[1];
            $connectFunc[$countObserver] = CheckFuncname(shift(@lineService));
            $notifyFunc[$countObserver]  = CheckFuncname(shift(@lineService));
            $countObserver++;
        }
    }
}

if ( $numOfOSubject == 0 ) {
    die "At least one Subject-Service should be specified.\n";
} elsif ( $numOfOSubject != $countSubject ) {
    die "Inconsitency found between service and numOfOSubject.\n";
}

if ( $numOfOObserver == 0 ) {
    die "At least one Observer-Service should be specified.\n";
} elsif ( $numOfOObserver != $countObserver ) {
    die "Inconsitency found between service and numOfOObserver.\n";
}


#
#  print on terminal
#
print "Object = $objectName\n";
print "numOfSubject  = $numOfOSubject\n";
print "numOfObserver = $numOfOObserver\n";
for ($i=0; $i<$numOfOSubject; $i++){
    print "Service name = $subjectService[$i]\n";
    print "\tControl Function = $controlFunc[$i]\n";
    print "\tReady Function   = $readyFunc[$i]\n";
}
for ($i=0; $i<$numOfOObserver; $i++){
    print "Service name = $observerService[$i]\n";
    print "\tConnect Function = $connectFunc[$i]\n";
    print "\tNotify Function  = $notifyFunc[$i]\n";
}


###
###  Output def.h
###
open(OUT, ">def.h");
print OUT <<def_h_section1;
//
//  def.h
//  This file is generated by stubgen.
//

//
// Copyright 2002 Sony Corporation
//

#ifndef _def_h_DEFINED
#define _def_h_DEFINED

//
//  Object name
//
const char* const objectName = "$objectName";

//
//  Number of OObserver & OSubeject instances
//
const int numOfSubject  = $numOfOSubject;
const int numOfObserver = $numOfOObserver;

//
//  Service name
//
const char* const subjectService[numOfSubject] =
{
def_h_section1

for ($i = 0; $i < $numOfOSubject; $i++){
    print OUT "\t$subjectService[$i]";
    if ( $i+1 < $numOfOSubject ){
        print OUT ",\n";
    } else {
        print OUT "\n";
    }
}

print OUT <<def_h_section2;
};

const char* const observerService[numOfObserver] =
{
def_h_section2

for ($i = 0; $i < $numOfOObserver; $i++){
    print OUT "\t$observerService[$i]";
    if ( $i+1 < $numOfOObserver ){
        print OUT ",\n";
    } else {
        print OUT "\n";
    }
}

print OUT <<def_h_section3;
};

//
//  OSubject Index
//
def_h_section3

for ($i = 0; $i < $numOfOSubject; $i++){
    print OUT "const int sbj$subjectSubname[$i] = $i;\n";
}

print OUT <<def_h_section4;

//
//  OObserver Index
//
def_h_section4

for ($i = 0; $i < $numOfOObserver; $i++){
    print OUT "const int obs$observerSubname[$i] = $i;\n";
}

print OUT "\n\n#endif // _def_h_DEFINED\n";

close(OUT);


###
###  Output entry.h
###
open(OUT, ">entry.h") || die "entry.h : $!\n";

print OUT <<entry_h_section1;
//
//  entry.h
//
//  This file is generated by stubgen
//

//
// Copyright 2002 Sony Corporation
//

#ifndef _entry_h_DEFINED
#define _entry_h_DEFINED

#include <Types.h>
#include "def.h"

const int numOfHook = 4;

const Selector Entry_Hook   [numOfHook]     = { 0, 1, 2, 3 };
entry_h_section1

$countEntry = 4;

print OUT "const Selector Entry_Control[numOfSubject]  = { ";
for ($i=$numOfOSubject; $i>0; $i--){
    print OUT "$countEntry"; $countEntry++;
    if ( $i > 1 ){
        print OUT ", ";
    }
}
print OUT " };\n";

print OUT "const Selector Entry_Ready[numOfSubject]    = { ";
for ($i=$numOfOSubject; $i>0; $i--){
    print OUT "$countEntry"; $countEntry++;
    if ( $i > 1 ){
        print OUT ", ";
    }
}
print OUT " };\n";

print OUT "const Selector Entry_Connect[numOfObserver] = { ";
for ($i=$numOfOObserver; $i>0; $i--){
    print OUT "$countEntry"; $countEntry++;
    if ( $i > 1 ){
        print OUT ", ";
    }
}
print OUT " };\n";

print OUT "const Selector Entry_Notify[numOfObserver]  = { ";
for ($i=$numOfOObserver; $i>0; $i--){
    print OUT "$countEntry"; $countEntry++;
    if ( $i > 1 ){
        print OUT ", ";
    }
}
print OUT " };\n";

print OUT <<entry_h_section3;

//
//  Number of entries is
//      numOfHook + (numOfSubject + numOfObserver) * 2
//
entry_h_section3

$numOfEntries = ($numOfOSubject + $numOfOObserver) * 2 + 4;
print OUT "const longword numOfEntries = $numOfEntries;\n";

print OUT "\n#endif // _entry_h_DEFINED\n";

close(OUT);


###
###   Output xxxxStub.cc
###
open(OUT, ">".$objectName."Stub.cc");

print OUT "//\n";
print OUT "//  ".$objectName."Stub.cc\n";
print OUT <<stub_cc_section1;
//  This file is generated by stubgen
//

//
// Copyright 2002 Sony Corporation
//

#include <sys/types.h>
#include <sys/msg.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h> // for perror
#include <iostream>
#include <MCOOP.h>
stub_cc_section1

if ( $use_gtk ) {
    print OUT "#include <gtk/gtk.h>\n"
}

print OUT <<stub_cc_section2;
#include "entry.h"
#include "$objectName.h"
using namespace std;


float stubgenVersion = 2.2;

int msqid;
$objectName* pSelf;


$msgfunc_ret
check_message_queue($msgfunc_arg)
{
    $objectName& Self = *pSelf;

    if ( msgrcv(msqid, (msgbuf*)&currentMsg, currentMsg.Size(), msgType, $msgflg) > 0 ) {
        void* pMsg = &currentMsg.data;

        // Stub Function
        switch( currentMsg.sel ){

        case 0:
            {
                OReasonMessage* reasonMsg = (OReasonMessage *)pMsg;
                Self.Init( OSystemEvent(reasonMsg->reason, reasonMsg->param,
                                        reasonMsg->paramSize) );
            }
            break;

        case 1:
            {
                OReasonMessage* reasonMsg = (OReasonMessage *)pMsg;
                Self.Start( OSystemEvent(reasonMsg->reason, reasonMsg->param,
                                         reasonMsg->paramSize) );
            }
            break;


        case 2:
            {
                OReasonMessage* reasonMsg = (OReasonMessage *)pMsg;
                Self.Stop( OSystemEvent(reasonMsg->reason, reasonMsg->param,
                                        reasonMsg->paramSize) );
            }
            break;

        case 3:
            {
                OReasonMessage* reasonMsg = (OReasonMessage *)pMsg;
                Self.Destroy( OSystemEvent(reasonMsg->reason,reasonMsg->param,
                                           reasonMsg->paramSize) );
            }
            break;

stub_cc_section2

$countEntry = 4;   #  numOfHook
for ($i=0; $i<$numOfOSubject; $i++){
    if ($controlFunc[$i] eq "null"){
	print OUT <<stub_cc_section_control_nofunc;
        case $countEntry:
            {
                OControlMessage* msg = (OControlMessage *)pMsg;
                Self.subject[$i]->ControlHandler( *msg );
            }
            break;
stub_cc_section_control_nofunc
    } else {
	print OUT <<stub_cc_section_control;
        case $countEntry:
            {
                OControlMessage* msg = (OControlMessage *)pMsg;
                Self.$controlFunc[$i](OControlEvent($i, msg->observerID, msg->subName, msg->command));
                Self.subject[$i]->ControlHandler( *msg );
            }
            break;
stub_cc_section_control
    }
    $countEntry = $countEntry + 1;
}

for ($i=0; $i<$numOfOSubject; $i++){
    if ($readyFunc[$i] eq "null"){
	print OUT <<stub_cc_section_ready_nofunc;
        case $countEntry:
            {
                OReadyMessage* msg = (OReadyMessage *)pMsg;
                Self.subject[$i]->ReadyHandler( *msg );
            }
            break;
stub_cc_section_ready_nofunc
    } else {
	print OUT <<stub_cc_section_ready;
        case $countEntry:
            {
                OReadyMessage* msg = (OReadyMessage *)pMsg;
                Self.subject[$i]->ReadyHandler( *msg );
                Self.$readyFunc[$i](OReadyEvent($i, msg->observerID, msg->command));
            }
            break;
stub_cc_section_ready
    }
    $countEntry = $countEntry + 1;
}

for ($i=0; $i<$numOfOObserver; $i++){
    if ($connectFunc[$i] eq "null"){
	print OUT <<stub_cc_section_connect_nofunc;
        case $countEntry:
            {
                OConnectMessage* msg = (OConnectMessage *)pMsg;
                Self.observer[$i]->ConnectHandler( *msg );
            }
            break;
stub_cc_section_connect_nofunc
    } else {
	print OUT <<stub_cc_section_connect;
        case $countEntry:
            {
                OConnectMessage* msg = (OConnectMessage *)pMsg;
                Self.$connectFunc[$i]( OConnectEvent($i, msg->subName, msg->command) );
                Self.observer[$i]->ConnectHandler( *msg );
            }
            break;
stub_cc_section_connect
    }
    $countEntry = $countEntry + 1;
}

for ($i=0; $i<$numOfOObserver; $i++){
    if ($notifyFunc[$i] eq "null"){
	print OUT <<stub_cc_section_notify_nofunc;
        case $countEntry:
            {
                ONotifyMessage* msg = (ONotifyMessage *)pMsg;
                ONotifyEvent event;
                event.SetIndex($i);
                Self.observer[$i]->NotifyHandler( *msg, &event );
            }
            break;
stub_cc_section_notify_nofunc
    } else {
	print OUT <<stub_cc_section_notify;
        case $countEntry:
            {
                ONotifyMessage* msg = (ONotifyMessage *)pMsg;
                ONotifyEvent event;
                event.SetIndex($i);
                Self.observer[$i]->NotifyHandler( *msg, &event );
                Self.$notifyFunc[$i](event);
            }
            break;
stub_cc_section_notify
    }
    $countEntry = $countEntry + 1;
}

print OUT <<stub_cc_section3;

        default:
            cout << "Invalid selector[" << currentMsg.sel << "] "
                 << "access in " << myname << endl;
            return 0;
        }
    }

    return 1;
}


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

if ( $use_gtk  ) {
    print OUT <<stub_cc_section_gtk_init;
    // GTK+ setting
    gtk_set_locale();
    gtk_init(&argc, &argv);

stub_cc_section_gtk_init
}

print OUT <<stub_cc_section4;
    strcpy(myname, argv[0]);
    SetRegistryManagerKey(argv[1]);

    // Buffer Creation
    key_t msgkey = (key_t)getpid();
    msqid = msgget(msgkey, IPC_CREAT|IPC_EXCL|0666);
    if (msqid < 0){
        cerr << "!!! ERROR Message queue creation failed in " << myname;
        ::perror("msgget()");
        exit(1);
    }

#if 0
    cout << "starting " << myname
         << ", OID = " << msqid << " (0x" << hex << msqid << dec << ")" << endl;
#endif

    // Signal Setting
    signal(SIGINT, Terminate);
    signal(SIGSEGV, Terminate);
    signal(SIGTERM, Terminate);

    // Create OPEN-R Object
    pSelf = new $objectName();

    // Main Routine
stub_cc_section4

if ( $use_gtk  ) {
    print OUT "    gtk_timeout_add(100, check_message_queue, NULL);\n";
    print OUT "    gtk_main();\n";
} else {
    print OUT "    while (check_message_queue())\n";
    print OUT "        ;\n";
}

print OUT <<stub_cc_section5;

    return 0;
}
stub_cc_section5

close(OUT);
