/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#import "WXWebSocketModule.h"
#import "WXUtility.h"
#import "WXWebSocketHandler.h"
#import "WXHandlerFactory.h"
#import "WXWebSocketLoader.h"
#import "WXConvert.h"

@interface WXWebSocketModule()

@property(nonatomic,copy)WXModuleKeepAliveCallback errorCallBack;
@property(nonatomic,copy)WXModuleKeepAliveCallback messageCallBack;
@property(nonatomic,copy)WXModuleKeepAliveCallback openCallBack;
@property(nonatomic,copy)WXModuleKeepAliveCallback closeCallBack;

@end

@implementation WXWebSocketModule
{
    WXWebSocketLoader *loader;
}
WX_EXPORT_METHOD(@selector(WebSocket:protocol:))
WX_EXPORT_METHOD(@selector(send:))
WX_EXPORT_METHOD(@selector(close:reason:))
WX_EXPORT_METHOD(@selector(onerror:))
WX_EXPORT_METHOD(@selector(onmessage:))
WX_EXPORT_METHOD(@selector(onopen:))
WX_EXPORT_METHOD(@selector(onclose:))

@synthesize weexInstance;

- (void)WebSocket:(NSString *)url protocol:(NSString *)protocol
{
    // check url
    NSURL* theURL = [NSURL URLWithString:url];
    if (theURL == nil) {
        return;
    }
    NSString *scheme = theURL.scheme.lowercaseString;
    if (!([scheme isEqualToString:@"ws"] || [scheme isEqualToString:@"http"] ||
          [scheme isEqualToString:@"wss"] || [scheme isEqualToString:@"https"])) {
        return;
    }
    
    if(loader)
    {
        [loader clear];
    }
    loader = [[WXWebSocketLoader alloc] initWithUrl:url protocol:protocol];
    __weak typeof(self) weakSelf = self;
    loader.onReceiveMessage = ^(id message) {
        if (weakSelf) {
            NSMutableDictionary *dic = [NSMutableDictionary new];
            if([message isKindOfClass:[NSString class]]) {
                [dic setObject:message forKey:@"data"];
            }else if([message isKindOfClass:[NSData class]]){
                [dic setObject:[WXUtility dataToBase64Dict:message] forKey:@"data"];
            }
            if (weakSelf.messageCallBack) {
                weakSelf.messageCallBack(dic,true);;
            }
        }
    };
    loader.onOpen = ^() {
        if (weakSelf) {
            if (weakSelf.openCallBack) {
                NSMutableDictionary *dict = [NSMutableDictionary new];
                weakSelf.openCallBack(dict,true);;
            }
        }
    };
    loader.onFail = ^(NSError *error) {
        if (weakSelf) {
            WXLogError(@":( Websocket Failed With Error %@", error);
            NSMutableDictionary *dict = [NSMutableDictionary new];
            [dict setObject:error.userInfo?[WXUtility JSONString:error.userInfo]:@"" forKey:@"data"];
            if (weakSelf.errorCallBack) {
                weakSelf.errorCallBack(dict, true);
            }
        }
    };
    loader.onClose = ^(NSInteger code,NSString *reason,BOOL wasClean) {
        if (weakSelf) {
            if (weakSelf.closeCallBack) {
                WXLogInfo(@"Websocket colse ");
                NSMutableDictionary * callbackRsp = [[NSMutableDictionary alloc] init];
                [callbackRsp setObject:[NSNumber numberWithInteger:code] forKey:@"code"];
                [callbackRsp setObject:reason?reason:@"" forKey:@"reason"];
                [callbackRsp setObject:wasClean?@true:@false forKey:@"wasClean"];
                if (weakSelf.closeCallBack) {
                    weakSelf.closeCallBack(callbackRsp,false);
                }
            }
        }
    };
    
    [loader open];
}

- (void)send:(id)data
{
    if([data isKindOfClass:[NSString class]]){
        [loader send:data];
    }else if([data isKindOfClass:[NSDictionary class]]){
        NSData *sendData = [WXUtility base64DictToData:data];
        if(sendData){
            [loader send:sendData];
        }
    }
}

- (void)close
{
    [loader close];
}

- (void)close:(NSString *)code reason:(NSString *)reason
{
    if([WXUtility isBlankString:code])
    {
        [loader close];
        return;
    }
    [loader close:[code integerValue] reason:reason];
}

- (void)onerror:(WXModuleKeepAliveCallback)callback
{
    self.errorCallBack = callback;
}

- (void)onmessage:(WXModuleKeepAliveCallback)callback
{
    self.messageCallBack = callback;
}

- (void)onopen:(WXModuleKeepAliveCallback)callback
{
    self.openCallBack = callback;
}

- (void)onclose:(WXModuleKeepAliveCallback)callback
{
    self.closeCallBack = callback;
}

-(void)dealloc
{
    [loader clear];
}

@end
