/*
 * 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 "WXResourceLoader.h"
#import "WXResourceRequestHandler.h"
#import "WXSDKInstance.h"
#import "WXLog.h"
#import "WXHandlerFactory.h"
#import "WXSDKError.h"
#import "WXConfigCenterProtocol.h"
#import "WXSDKEngine.h"

//deprecated
#import "WXNetworkProtocol.h"

@interface WXResourceLoader () <WXResourceRequestDelegate>

@end

@implementation WXResourceLoader
{
    NSMutableData *_data;
    WXResourceResponse *_response;
}

- (instancetype)initWithRequest:(WXResourceRequest *)request
{
    if (self = [super init]) {
        self.request = request;
    }
    
    return self;
}

- (void)setRequest:(WXResourceRequest *)request
{
    if (_request) {
        [self cancel:nil];
    }
    
    _request = request;
}

- (void)start
{
    if ([_request.URL isFileURL]) {
        [self _handleFileURL:_request.URL];
        return;
    }
    
    id<WXResourceRequestHandler> requestHandler = [WXHandlerFactory handlerForProtocol:@protocol(WXResourceRequestHandler)];
    if (requestHandler) {
        [requestHandler sendRequest:_request withDelegate:self];
    } else if ([WXHandlerFactory handlerForProtocol:NSProtocolFromString(@"WXNetworkProtocol")]){
        // deprecated logic
        [self _handleDEPRECATEDNetworkHandler];
    } else {
        WXLogError(@"No resource request handler found!");
    }
}

- (void)cancel:(NSError *__autoreleasing *)error
{
    id<WXResourceRequestHandler> requestHandler = [WXHandlerFactory handlerForProtocol:@protocol(WXResourceRequestHandler)];
    if ([requestHandler respondsToSelector:@selector(cancelRequest:)]) {
        [requestHandler cancelRequest:_request];
    } else if (error) {
        *error = [NSError errorWithDomain:WX_ERROR_DOMAIN code:WX_ERR_CANCEL userInfo:@{NSLocalizedDescriptionKey: @"handle:%@ not respond to cancelRequest"}];
    }
}

- (void)_handleFileURL:(NSURL *)url
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSData *fileData = [[NSFileManager defaultManager] contentsAtPath:[url path]];
        if (self.onFinished) {
            self.onFinished([[WXResourceResponse alloc]initWithURL:url statusCode:200 HTTPVersion:@"1.1" headerFields:nil], fileData);
        }
    });
}

- (void)_handleDEPRECATEDNetworkHandler
{
    WXLogWarning(@"WXNetworkProtocol is deprecated, use WXResourceRequestHandler instead!");
    id networkHandler = [WXHandlerFactory handlerForProtocol:NSProtocolFromString(@"WXNetworkProtocol")];
    __weak typeof(self) weakSelf = self;
    [networkHandler sendRequest:_request withSendingData:^(int64_t bytesSent, int64_t totalBytes) {
        if (weakSelf.onDataSent) {
            weakSelf.onDataSent(bytesSent, totalBytes);
        }
    } withResponse:^(NSURLResponse *response) {
        _response = (WXResourceResponse *)response;
        if (weakSelf.onResponseReceived) {
            weakSelf.onResponseReceived((WXResourceResponse *)response);
        }
    } withReceiveData:^(NSData *data) {
        if (weakSelf.onDataReceived) {
            weakSelf.onDataReceived(data);
        }
    } withCompeletion:^(NSData *totalData, NSError *error) {
        if (error) {
            if (weakSelf.onFailed) {
                weakSelf.onFailed(error);
            }
        } else {
            weakSelf.onFinished(_response, totalData);
            _response = nil;
        }
    }];
}

#pragma mark - WXResourceRequestDelegate

- (void)request:(WXResourceRequest *)request didSendData:(unsigned long long)bytesSent totalBytesToBeSent:(unsigned long long)totalBytesToBeSent
{
    WXLogDebug(@"request:%@ didSendData:%llu totalBytesToBeSent:%llu", request, bytesSent, totalBytesToBeSent);
    
    if (self.onDataSent) {
        self.onDataSent(bytesSent, totalBytesToBeSent);
    }
}

- (void)request:(WXResourceRequest *)request didReceiveResponse:(WXResourceResponse *)response
{
    WXLogDebug(@"request:%@ didReceiveResponse:%@ ", request, response);
    
    _response = response;
    _data = nil;
    
    if (self.onResponseReceived) {
        self.onResponseReceived(response);
    }
}

- (void)request:(WXResourceRequest *)request didReceiveData:(NSData *)data
{
    WXLogDebug(@"request:%@ didReceiveDataLength:%ld", request, (unsigned long)data.length);
    
    if (!_data) {
        _data = [NSMutableData new];
    }
    [_data appendData:data];
    
    if (self.onDataReceived) {
        self.onDataReceived(data);
    }
}

- (void)requestDidFinishLoading:(WXResourceRequest *)request
{
    WXLogDebug(@"request:%@ requestDidFinishLoading", request);
    
    if (self.onFinished) {
        self.onFinished(_response, _data);
    }
    
    _data = nil;
    _response = nil;
}

- (void)request:(WXResourceRequest *)request didFailWithError:(NSError *)error
{
    WXLogDebug(@"request:%@ didFailWithError:%@", request, error.localizedDescription);
    
    if (self.onFailed) {
        self.onFailed(error);
    }
    
    _data = nil;
    _response = nil;
}

#ifdef __IPHONE_10_0
- (void)request:(WXResourceRequest *)request didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics
{
    WXLogDebug(@"request:%@ didFinishCollectingMetrics", request);
}
#endif


@end
