1/*
2 * Copyright (C) 2011 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#import "config.h"
27#import "WKConnection.h"
28#import "WKConnectionInternal.h"
29
30#import "ObjCObjectGraph.h"
31#import "WKConnectionRef.h"
32#import "WKData.h"
33#import "WKRetainPtr.h"
34#import "WKString.h"
35#import "WKStringCF.h"
36#import <wtf/RetainPtr.h>
37
38using namespace WebKit;
39
40@interface WKConnectionData : NSObject {
41@public
42    // Underlying connection object.
43    WKRetainPtr<WKConnectionRef> _connectionRef;
44
45    // Delegate for callbacks.
46    id<WKConnectionDelegate> _delegate;
47}
48@end
49
50@implementation WKConnectionData
51@end
52
53@implementation WKConnection
54
55- (void)dealloc
56{
57    WKConnectionSetConnectionClient(_data->_connectionRef.get(), 0);
58
59    [_data release];
60    [super dealloc];
61}
62
63- (void)sendMessageWithName:(NSString *)messageName body:(id)messageBody
64{
65    WKRetainPtr<WKStringRef> wkMessageName = adoptWK(WKStringCreateWithCFString((CFStringRef)messageName));
66    RefPtr<ObjCObjectGraph> wkMessageBody = ObjCObjectGraph::create(messageBody);
67
68    WKConnectionPostMessage(_data->_connectionRef.get(), wkMessageName.get(), (WKTypeRef)wkMessageBody.get());
69}
70
71#pragma mark Delegates
72
73- (id<WKConnectionDelegate>)delegate
74{
75    return _data->_delegate;
76}
77
78- (void)setDelegate:(id<WKConnectionDelegate>)delegate
79{
80    _data->_delegate = delegate;
81}
82
83@end
84
85@implementation WKConnection (Internal)
86
87static void didReceiveMessage(WKConnectionRef, WKStringRef messageName, WKTypeRef messageBody, const void* clientInfo)
88{
89    WKConnection *connection = (WKConnection *)clientInfo;
90    if ([connection.delegate respondsToSelector:@selector(connection:didReceiveMessageWithName:body:)]) {
91        RetainPtr<CFStringRef> nsMessageName = adoptCF(WKStringCopyCFString(kCFAllocatorDefault, messageName));
92        RetainPtr<id> nsMessageBody = ((ObjCObjectGraph*)messageBody)->rootObject();
93
94        [connection.delegate connection:connection didReceiveMessageWithName:(NSString *)nsMessageName.get() body:nsMessageBody.get()];
95    }
96}
97
98static void didClose(WKConnectionRef, const void* clientInfo)
99{
100    WKConnection *connection = (WKConnection *)clientInfo;
101    if ([connection.delegate respondsToSelector:@selector(connectionDidClose:)]) {
102        [connection.delegate connectionDidClose:connection];
103    }
104}
105
106static void setUpClient(WKConnection *connection, WKConnectionRef connectionRef)
107{
108    WKConnectionClient client;
109    memset(&client, 0, sizeof(client));
110
111    client.version = WKConnectionClientCurrentVersion;
112    client.clientInfo = connection;
113    client.didReceiveMessage = didReceiveMessage;
114    client.didClose = didClose;
115
116    WKConnectionSetConnectionClient(connectionRef, &client);
117}
118
119- (id)_initWithConnectionRef:(WKConnectionRef)connectionRef
120{
121    self = [super init];
122    if (!self)
123        return nil;
124
125    _data = [[WKConnectionData alloc] init];
126    _data->_connectionRef = connectionRef;
127
128    setUpClient(self, _data->_connectionRef.get());
129
130    return self;
131}
132
133@end
134