/**
 * Creates structured events representing weather reports and pushes them to
 * an event channel.
 */

#include "WeatherStation.h"
#include <orbsvcs/Shutdown_Utilities.h>

class Service_Shutdown_Functor : public Shutdown_Functor
{
public:
  Service_Shutdown_Functor (CORBA::ORB_ptr orb)
    : orb_ (CORBA::ORB::_duplicate (orb))
  {
  }

  void operator() (int which_signal)
  {
    ACE_DEBUG ((LM_DEBUG,
                ACE_TEXT ("shutting down on signal %d\n"),
                which_signal));
    (void) this->orb_->shutdown ();
  }

private:
  CORBA::ORB_var orb_;
};

namespace
{
  // All the possible elements of weather information that may go into a report.
  const int MAX_CITIES = 7;
  const int MAX_NEWS   = 2;
  const char * const allNews[MAX_CITIES][MAX_NEWS] =
    {
      { ACE_TEXT ("San Francisco"), ACE_TEXT ("80 miles/hour storm")    },
      { ACE_TEXT ("Houston"),       ACE_TEXT ("4 inches of snow")       },
      { ACE_TEXT ("New York"),      ACE_TEXT ("Clouds and 43 degrees")  },
      { ACE_TEXT ("Seattle"),       ACE_TEXT ("A bit of rain")          },
      { ACE_TEXT ("Atlanta"),       ACE_TEXT ("Sun and 89 degrees")     },
      { ACE_TEXT ("Newcastle"),     ACE_TEXT ("Rain and mist")          },
      { ACE_TEXT ("Louisianna"),    ACE_TEXT ("Twister destroys homes") }
    };
}

CosNotification::StructuredEvent *
WeatherStation::createNextEvent (void)
{
  CosNotification::StructuredEvent *pEvent = 0;
  ACE_NEW_THROW_EX (pEvent,
                    CosNotification::StructuredEvent (),
                    CORBA::NO_MEMORY ());
  CosNotification::StructuredEvent_var holder (pEvent);

  const char *city = allNews[rand () % MAX_CITIES][0];
  const char *news = allNews[rand () % MAX_CITIES][1];

  // Event header.
  CosNotification::EventType type;
  type.domain_name = CORBA::string_dup (ACE_TEXT ("News"));
  type.type_name = CORBA::string_dup (ACE_TEXT ("Weather"));

  CosNotification::FixedEventHeader fixedHeader;
  fixedHeader.event_type = type;
  fixedHeader.event_name = CORBA::string_dup (ACE_TEXT ("message"));

  CosNotification::PropertySeq varHeader;
  pEvent->header.fixed_header = fixedHeader;
  pEvent->header.variable_header = varHeader;

  // Filterable data.
  CosNotification::PropertySeq filterable;
  filterable.length (2);
  filterable[0].name = CORBA::string_dup (ACE_TEXT ("bureau"));
  filterable[0].value <<=
    CORBA::String_var (CORBA::string_dup (ACE_TEXT ("Station North")));
  filterable[1].name = CORBA::string_dup (ACE_TEXT ("city"));
  filterable[1].value <<=
    CORBA::String_var (CORBA::string_dup (city));
  pEvent->filterable_data = filterable;

  // Remainder-of-body
  pEvent->remainder_of_body <<=
    CORBA::String_var (CORBA::string_dup (news));

  return holder._retn ();
}

int
main (int argc, char **argv)
{
  try
    {
      // Initialise the ORB instance.
      CORBA::ORB_var orbVar =
        CORBA::ORB_init (argc, argv, ACE_TEXT (""));

      // Cleaning guard.
      Service_Shutdown_Functor killer (orbVar.in ());
      Service_Shutdown kill_contractor (killer);

      // Create the weather station.
      WeatherStation *pWeatherStation = 0;
      ACE_NEW_THROW_EX (pWeatherStation,
                        WeatherStation (orbVar.in ()),
                        CORBA::NO_MEMORY ());
      PortableServer::ServantBase_var holder (pWeatherStation);

      // Connect to the event channel.
      pWeatherStation->connectToChannel ();

      // Send events.
      pWeatherStation->broadcast ();

      orbVar->destroy ();
    }
  catch (const CORBA::Exception &ex)
    {
      ex._tao_print_exception (ACE_TEXT ("ERROR: Exception in WeatherStation.cpp:"));
      return 1;
    }

  return 0;
}
