/*
 * call-seq:
 *      multicast(message, groups, service_type, [msg_type], [self_discard]) -> nil
 *
 * Broadcast +message+ to +groups+, using the service type
 * +service_type+. +groups+ is either a String specifying a single
 * group name, or an Array of Strings specifying the list of group
 * names. +service_type+ specifies the desired ordering guarantee for
 * the message (which are available as constants in the Spread
 * module). For more information on the delivery guarantees provided
 * by Spread, see the Spread documentation.
 *
 * +msg_type+ is the "message type" of the message; this is an
 * arbitrary application-defined value. If not specified, it defaults
 * to 0. The message type of a received data message can be accessed
 * via Spread::DataMessage#msg_type.
 *
 * If +self_discard+ is +true+, the message will not be delivered to
 * the sending node. Otherwise, the message will be delivered if the
 * sending node belongs to the group it is sending the message to.
 *
 * rb_spread imposes no upper limit on message size. By default,
 * Spread itself will reject messages larger than about 144,000 bytes;
 * this limit can be raised by recompiling Spread. If a message is
 * larger than Spread's maximum message size,
 * Spread::Error::MessageTooLong will be raised.
 */
static VALUE
spconn_multicast(int argc, VALUE *argv, VALUE obj)
{
    VALUE message, group, st, mtype, self_discard;
    struct SpreadConnection *sp;
    int n;
    int service_type;

    Data_Get_Struct(obj, struct SpreadConnection, sp);
    rb_scan_args(argc, argv, "32", &message, &group, &st, &mtype, &self_discard);
    if (NIL_P(mtype))
        mtype = INT2FIX(0);

    service_type = NUM2INT(st);
    if (RTEST(self_discard))
        service_type |= SELF_DISCARD;

    SafeStringValue(message);

    if (TYPE(group) == T_ARRAY)
    {
        char groupnames[MAX_GROUPS][MAX_GROUP_NAME];
        int i;

        if (RARRAY(group)->len == 0)
            return Qnil;
        if (RARRAY(group)->len >= MAX_GROUPS)
            rb_raise(rb_eArgError, "too many groups for multicast");

        for (i = 0; i < RARRAY(group)->len; i++)
        {
            VALUE tmp = RARRAY(group)->ptr[i];
            snprintf(groupnames[i], MAX_GROUP_NAME, "%s",
                     StringValuePtr(tmp));
        }
        if ((n = SP_multigroup_multicast(sp->mbox, service_type,
                                         RARRAY(group)->len,
                                         (const char (*)[]) groupnames,
                                         NUM2INT(mtype),
                                         RSTRING(message)->len,
                                         RSTRING(message)->ptr)) < 0)
            raise_sp_error(n);
    }
    else
    {
        /* `group' must be a string or equivalent, raise type error if not */
        if ((n = SP_multicast(sp->mbox,
                              service_type,
                              StringValuePtr(group),
                              NUM2INT(mtype),
                              RSTRING(message)->len,
                              RSTRING(message)->ptr)) < 0)
            raise_sp_error(n);
    }

    return Qnil;
}