1/*
2 * Copyright 1999, Be Incorporated.
3 * Copyright (c) 1999-2000, Eric Moon.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions, and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions, and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * 3. The name of the author may not be used to endorse or promote products
18 *    derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
24 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
28 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32
33////////////////////////////////////////////////////////////
34// MultiInvoker.cpp
35// ----------------
36// Implements the MultiInvoker class.
37//
38
39#include <Messenger.h>
40#include "MultiInvoker.h"
41
42MultiInvoker::MultiInvoker()
43{
44	m_message = 0;
45	m_timeout = B_INFINITE_TIMEOUT;
46	m_replyHandler = 0;
47}
48
49MultiInvoker::MultiInvoker(const MultiInvoker& src)
50{
51	Clone(src);
52}
53
54MultiInvoker::~MultiInvoker()
55{
56	Clear();
57}
58
59MultiInvoker& MultiInvoker::operator=(const MultiInvoker& src)
60{
61	if (this != &src) {
62		Clear();
63		Clone(src);
64	}
65	return *this;
66}
67
68void MultiInvoker::Clear()
69{
70	delete m_message;
71	int32 i=CountTargets();
72	while (--i >=0) {
73		RemoveTarget(i);
74	}
75}
76
77void MultiInvoker::Clone(const MultiInvoker& src)
78{
79	m_message = new BMessage(*src.Message());
80	int32 len=src.CountTargets();
81	for (int32 i=0; i<len; i++) {
82		AddTarget(src.TargetAt(i));
83	}
84	m_timeout = src.Timeout();
85	m_replyHandler = src.HandlerForReply();
86}
87
88void MultiInvoker::SetMessage(BMessage* message)
89{
90	delete m_message;
91	m_message = message;
92}
93
94BMessage* MultiInvoker::Message() const
95{
96	return m_message;
97}
98
99uint32 MultiInvoker::Command() const
100{
101	return (m_message) ? m_message->what : 0;
102}
103
104status_t MultiInvoker::AddTarget(const BHandler* h, const BLooper* loop)
105{
106	status_t err;
107	BMessenger* msgr = new BMessenger(h, loop, &err);
108	if (err == B_OK)
109		m_messengers.AddItem(msgr);
110	else
111		delete msgr;
112	return err;
113}
114
115status_t MultiInvoker::AddTarget(BMessenger* msgr)
116{
117	if (msgr) {
118		m_messengers.AddItem(msgr);
119		return B_OK;
120	} else {
121		return B_BAD_VALUE;
122	}
123}
124
125void MultiInvoker::RemoveTarget(const BHandler* h)
126{
127	int32 i = IndexOfTarget(h);
128	if (i >= 0)
129		RemoveTarget(i);
130}
131
132void MultiInvoker::RemoveTarget(int32 index)
133{
134	BMessenger* msgr = static_cast<BMessenger*>
135		(m_messengers.RemoveItem(index));
136	delete msgr;
137}
138
139int32 MultiInvoker::IndexOfTarget(const BHandler* h) const
140{
141	int32 len = CountTargets();
142	for (int32 i=0; i<len; i++) {
143		BMessenger* msgr = MessengerAt(i);
144		if (msgr && msgr->Target(0) == h) {
145			return i;
146		}
147	}
148	return -1;
149}
150
151int32 MultiInvoker::CountTargets() const
152{
153	return m_messengers.CountItems();
154}
155
156BHandler* MultiInvoker::TargetAt(int32 index, BLooper** looper) const
157{
158	BMessenger* msgr = MessengerAt(index);
159	if (msgr) {
160		return msgr->Target(looper);
161	} else {
162		if (looper) *looper = 0;
163		return 0;
164	}
165}
166
167BMessenger* MultiInvoker::MessengerAt(int32 index) const
168{
169	return static_cast<BMessenger*>
170		(m_messengers.ItemAt(index));
171}
172
173bool MultiInvoker::IsTargetLocal(int32 index) const
174{
175	BMessenger* msgr = MessengerAt(index);
176	return (msgr) ? msgr->IsTargetLocal() : false;
177}
178
179void MultiInvoker::SetTimeout(bigtime_t timeout)
180{
181	m_timeout = timeout;
182}
183
184bigtime_t MultiInvoker::Timeout() const
185{
186	return m_timeout;
187}
188
189void MultiInvoker::SetHandlerForReply(BHandler* h)
190{
191	m_replyHandler = h;
192}
193
194BHandler* MultiInvoker::HandlerForReply() const
195{
196	return m_replyHandler;
197}
198
199status_t MultiInvoker::Invoke(BMessage* msg)
200{
201	BMessage* sendMsg = (msg) ? msg : m_message;
202	if (! sendMsg)
203		return B_BAD_VALUE;
204
205	status_t err, finalResult=B_OK;
206	BMessage replyMsg;
207	int32 len = CountTargets();
208	for (int32 i=0; i<len; i++) {
209		BMessenger* msgr = MessengerAt(i);
210		if (msgr) {
211			err = msgr->SendMessage(sendMsg,
212				HandlerForReply(), m_timeout);
213			if (err != B_OK) finalResult = err;
214		}
215	}
216	return finalResult;
217}
218