1package hub
2
3import (
4	"time"
5
6	pdebug "github.com/lestrrat/go-pdebug"
7)
8
9func NewPayload(data interface{}) *payload {
10	p := &payload{data: data}
11	return p
12}
13
14// Data returns the underlying data
15func (p payload) Data() interface{} {
16	return p.data
17}
18
19// Done marks the request as done. If Hub is operating in
20// asynchronous mode (default), it's a no op. Otherwise it
21// closes the reply channel to finish up the synchronous communication
22func (p payload) Done() {
23	if p.done == nil {
24		return
25	}
26	close(p.done)
27}
28
29// NewHub creates a new Hub struct
30func New(bufsiz int) *Hub {
31	return &Hub{
32		isSync:      false,
33		queryCh:     make(chan Payload, bufsiz),
34		drawCh:      make(chan Payload, bufsiz),
35		statusMsgCh: make(chan Payload, bufsiz),
36		pagingCh:    make(chan Payload, bufsiz),
37	}
38}
39
40// Batch allows you to synchronously send messages during the
41// scope of f() being executed.
42func (h *Hub) Batch(f func(), shouldLock bool) {
43	if pdebug.Enabled {
44		g := pdebug.Marker("Batch %t", shouldLock)
45		defer g.End()
46	}
47	if shouldLock {
48		// lock during this operation
49		h.mutex.Lock()
50		defer h.mutex.Unlock()
51	}
52
53	// temporarily set isSync = true
54	o := h.isSync
55	h.isSync = true
56	defer func() { h.isSync = o }()
57
58	// ignore panics
59	defer func() { recover() }()
60
61	f()
62}
63
64// low-level utility
65func send(ch chan Payload, r *payload, needReply bool) {
66	if needReply {
67		r.done = make(chan struct{})
68		defer func() { <-r.done }()
69	}
70
71	ch <- r
72}
73
74// QueryCh returns the underlying channel for queries
75func (h *Hub) QueryCh() chan Payload {
76	return h.queryCh
77}
78
79// SendQuery sends the query string to be processed by the Filter
80func (h *Hub) SendQuery(q string) {
81	send(h.QueryCh(), NewPayload(q), h.isSync)
82}
83
84// DrawCh returns the channel to redraw the terminal display
85func (h *Hub) DrawCh() chan Payload {
86	return h.drawCh
87}
88
89// SendDrawPrompt sends a request to redraw the prompt only
90func (h *Hub) SendDrawPrompt() {
91	send(h.DrawCh(), NewPayload("prompt"), h.isSync)
92}
93
94// SendDraw sends a request to redraw the terminal display
95func (h *Hub) SendDraw(options interface{}) {
96	pdebug.Printf("START Hub.SendDraw %v", options)
97	defer pdebug.Printf("END Hub.SendDraw %v", options)
98	send(h.DrawCh(), NewPayload(options), h.isSync)
99}
100
101// StatusMsgCh returns the channel to update the status message
102func (h *Hub) StatusMsgCh() chan Payload {
103	return h.statusMsgCh
104}
105
106// SendStatusMsg sends a string to be displayed in the status message
107func (h *Hub) SendStatusMsg(q string) {
108	h.SendStatusMsgAndClear(q, 0)
109}
110
111type statusMsgReq struct {
112	msg   string
113	delay time.Duration
114}
115
116func (r statusMsgReq) Message() string {
117	return r.msg
118}
119
120func (r statusMsgReq) Delay() time.Duration {
121	return r.delay
122}
123
124func newStatusMsgReq(s string, d time.Duration) *statusMsgReq {
125	return &statusMsgReq{
126		msg:   s,
127		delay: d,
128	}
129}
130
131// SendStatusMsgAndClear sends a string to be displayed in the status message,
132// as well as a delay until the message should be cleared
133func (h *Hub) SendStatusMsgAndClear(q string, clearDelay time.Duration) {
134	msg := newStatusMsgReq(q, clearDelay)
135	send(h.StatusMsgCh(), NewPayload(msg), h.isSync)
136}
137
138func (h *Hub) SendPurgeDisplayCache() {
139	send(h.DrawCh(), NewPayload("purgeCache"), h.isSync)
140}
141
142// PagingCh returns the channel to page through the results
143func (h *Hub) PagingCh() chan Payload {
144	return h.pagingCh
145}
146
147// SendPaging sends a request to move the cursor around
148func (h *Hub) SendPaging(x interface{}) {
149	send(h.PagingCh(), NewPayload(x), h.isSync)
150}
151