1/*
2 * Copyright 2015, Haiku.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *			Joseph Groover <looncraz@looncraz.net>
7*/
8#ifndef AS_DELAYED_MESSAGE_H
9#define AS_DELAYED_MESSAGE_H
10
11
12#include <ObjectList.h>
13#include <OS.h>
14
15
16//! Method by which to merge DelayedMessages with the same code.
17enum DMMergeMode {
18	DM_NO_MERGE			= 0, // Will send this message, and the other(s)
19	DM_MERGE_REPLACE	= 1, // Replace older data with newer data
20	DM_MERGE_CANCEL		= 2, // keeps older data, cancels this message
21	DM_MERGE_DUPLICATES = 3  // If data is the same, cancel new message
22};
23
24
25//! Merge-mode data-matching, set which data must match to merge messages.
26enum {
27	DM_DATA_DEFAULT	= 0, // Match all for DUPLICATES & none for REPLACE modes.
28	DM_DATA_1		= 1 << 0,
29	DM_DATA_2		= 1 << 1,
30	DM_DATA_3		= 1 << 2,
31	DM_DATA_4		= 1 << 3,
32	DM_DATA_5		= 1 << 4,
33	DM_DATA_6		= 1 << 5
34};
35
36
37//! Convenient delay definitions.
38enum {
39	DM_MINIMUM_DELAY		= 500ULL,
40	DM_SHORT_DELAY			= 1000ULL,
41	DM_120HZ_DELAY			= 8888ULL,
42	DM_60HZ_DELAY			= 16666ULL,
43	DM_MEDIUM_DELAY			= 15000ULL,
44	DM_30HZ_DELAY			= 33332ULL,
45	DM_15HZ_DELAY			= 66664ULL,
46	DM_LONG_DELAY			= 100000ULL,
47	DM_QUARTER_SECOND_DELAY	= 250000ULL,
48	DM_HALF_SECOND_DELAY	= 500000ULL,
49	DM_ONE_SECOND_DELAY		= 1000000ULL,
50	DM_ONE_MINUTE_DELAY		= DM_ONE_SECOND_DELAY * 60,
51	DM_ONE_HOUR_DELAY		= DM_ONE_MINUTE_DELAY * 60
52};
53
54
55class DelayedMessageData;
56
57
58/*!	\class DelayedMessage
59	\brief Friendly API for creating messages to be sent at a future time.
60
61	Messages can be sent with a relative delay, or at a set time. Messages with
62	the same code can be merged according to various rules. Each message can
63	have any number of target recipients.
64
65	DelayedMessage is a throw-away object, it is to be created on the stack,
66	Flush()'d, then left to be destructed when out of scope.
67*/
68class DelayedMessage {
69	typedef void(*FailureCallback)(int32 code, port_id port, void* data);
70public:
71								DelayedMessage(int32 code, bigtime_t delay,
72									bool isSpecificTime = false);
73
74								~DelayedMessage();
75
76			// At least one target port is required.
77			bool				AddTarget(port_id port);
78
79			// Merge messages with the same code according to the following
80			// rules and data matching mask.
81			void				SetMerge(DMMergeMode mode, uint32 match = 0);
82
83			// Called for each port on which the message was failed to be sent.
84			void				SetFailureCallback(FailureCallback callback,
85									void* data = NULL);
86
87			template <class Type>
88			status_t			Attach(const Type& data);
89			status_t			Attach(const void* data, size_t size);
90
91			template <class Type>
92			status_t			AttachList(const BObjectList<Type>& list);
93
94			template <class Type>
95			status_t			AttachList(const BObjectList<Type>& list,
96									bool* whichArray);
97
98			status_t			Flush();
99
100		// Private
101			DelayedMessageData*	HandOff();
102			DelayedMessageData*	Data() {return fData;}
103
104private:
105		// Forbidden methods - these are one time-use objects.
106			void*				operator new(size_t);
107			void*				operator new[](size_t);
108
109			DelayedMessageData*	fData;
110			bool				fHandedOff;
111};
112
113
114// #pragma mark Implementation
115
116
117template <class Type>
118status_t
119DelayedMessage::Attach(const Type& data)
120{
121	return Attach(&data, sizeof(Type));
122}
123
124
125template <class Type>
126status_t
127DelayedMessage::AttachList(const BObjectList<Type>& list)
128{
129	if (list.CountItems() == 0)
130		return B_BAD_VALUE;
131
132	status_t error = Attach<int32>(list.CountItems());
133
134	for (int32 index = 0; index < list.CountItems(); ++index) {
135		if (error != B_OK)
136			break;
137
138		error = Attach<Type>(*(list.ItemAt(index)));
139	}
140
141	return error;
142}
143
144
145template <class Type>
146status_t
147DelayedMessage::AttachList(const BObjectList<Type>& list, bool* which)
148{
149	if (list.CountItems() == 0)
150		return B_BAD_VALUE;
151
152	if (which == NULL)
153		return AttachList(list);
154
155	int32 count = 0;
156	for (int32 index = 0; index < list.CountItems(); ++index) {
157		if (which[index])
158			++count;
159	}
160
161	if (count == 0)
162		return B_BAD_VALUE;
163
164	status_t error = Attach<int32>(count);
165
166	for (int32 index = 0; index < list.CountItems(); ++index) {
167		if (error != B_OK)
168			break;
169
170		if (which[index])
171			error = Attach<Type>(*list.ItemAt(index));
172	}
173
174	return error;
175}
176
177
178#endif // AS_DELAYED_MESSAGE_H
179