#import "YQDataManager.h"

#import <YYModel/YYModel.h>

#pragma mark - 数据model基类

@implementation YQListBaseModel

+ (NSDictionary *)modelCustomPropertyMapper

{

    return @{};

}

@end

 

@implementation YQDataBaseModel

 

+ (NSDictionary *)modelCustomPropertyMapper

{

    return @{};

}

 

@end

 

@implementation YQBaseModel

+ (NSDictionary *)modelCustomPropertyMapper

{

    return @{};

}

 

@end

 

 

#pragma mark - 网络请求基类

///请求类型类型

typedef NS_ENUM(NSUInteger, YQNetWorkType) {

    

    YQNetWorkTypeGet,//get请求

    

    YQNetWorkTypeHttpPost,//入参Http格式Post请求

    

    YQNetWorkTypeJsonPost,//入参json格式Post请求

};

 

/**

 *  请求重试计数器

 */

@interface RetryCounter : NSObject

 

//重试次数,默认30次

@property (nonatomic, assign) NSInteger retryCount;

//已重试的次数

@property (nonatomic, assign) NSInteger retryTime;

//重试时间间隔,默认100毫秒

@property (nonatomic, assign) NSTimeInterval retryInterval;

//计算器id

@property (nonatomic, assign) NSInteger counterId;

 

- (instancetype)initWithHash:(NSUInteger)hash;

- (BOOL)canRetry;

 

@end

 

@implementation RetryCounter

 

- (instancetype)initWithHash:(NSUInteger)hash

{

    self = [super init];

    //set default value

    self.retryCount = 1;

    self.retryInterval = 0.1;

    self.counterId = hash;

    

    return self;

}

 

/**

 *  是否可以重试,如果是,则返回true,并且重试次数自增1.

 *

 *  @return 是否可以重试

 */

- (BOOL)canRetry {

    BOOL result = (_retryTime < _retryCount);

    

    if (result) {

        _retryTime++;

    }

    

    return result;

}

@end

 

@interface YQDataManager ()

 

@property (nonnull, nonatomic, strong) NSMutableArray *retryCounterList;

 

@end

@implementation YQDataManager

 

/**

 *  创建单例

 *

 *  @return return value description

 */

+ (YQDataManager *)manager {

    static YQDataManager *sharedManager = nil;

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

        NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];

        configuration.timeoutIntervalForRequest = 8.0;

        configuration.timeoutIntervalForResource = 8.0;

        /* 创建网络请求对象 */

        sharedManager = [[YQDataManager alloc] initWithBaseURL:[NSURL URLWithString:BaseUrl] sessionConfiguration:configuration];

        /* 设置请求和接收的数据编码格式 */

 

        sharedManager.responseSerializer = [AFJSONResponseSerializer serializer]; // 设置接收数据为 JSON 数据

 

        sharedManager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];

        sharedManager.securityPolicy.allowInvalidCertificates = YES;

        // 修改 解析数据格式 能够接受的内容类型 - 官方推荐的做法,民间做法:直接修改 AFN 的源代码

        sharedManager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json",@"text/json",@"text/javascript", @"text/html",nil];

      

      

        sharedManager.retryCounterList = [NSMutableArray array];

    });

    return sharedManager;

}

 

#pragma mark - helper

 

- (RetryCounter*)retryCounterForHash:(NSUInteger)hash

{

    RetryCounter *target = nil;

    for (RetryCounter *counter in _retryCounterList) {

        if (counter.counterId == hash) {

            target = counter;

            break;

        }

    }

    

    return target;

}

 

- (RetryCounter*)insertCounterWithHash:(NSUInteger)hash

{

    RetryCounter *counter = [[RetryCounter alloc] initWithHash:hash];

    [[YQDataManager manager].retryCounterList addObject:counter];

    

    return counter;

}

 

- (void)removeCounterForHash:(NSUInteger)hash

{

    RetryCounter *counter = [self retryCounterForHash:hash];

    

    if (counter != nil) {

        [_retryCounterList removeObject:counter];

    }

}

 

 

#pragma mark - http process

 

 

/**

 *  重试的方法

 */

+ (void)networkMananger:(YQDataManager *)manager

                 method:(YQNetWorkType)httpMethod

           retryWithUrl:(NSString*)url

                 params:(NSDictionary*)param

                success:(void(^)(id responseData))successBlock

                failure:(void(^)(NSError *error))failureBlock {

    

    RetryCounter *currentCounter = [[YQDataManager manager] retryCounterForHash:param.hash];

    

    if (currentCounter == nil) {

        //add to retry counter list

        currentCounter = [[YQDataManager manager] insertCounterWithHash:param.hash];

    }

    

    BOOL retryFlag = [currentCounter canRetry];

    //wait for 10ms

    NSDate *endDate = [NSDate dateWithTimeIntervalSinceNow:currentCounter.retryInterval];

    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:endDate];

    

    if (httpMethod == YQNetWorkTypeGet) {

        [manager GET:url parameters:param progress:nil success:^(NSURLSessionDataTask *task, id responseData) {

            successBlock(responseData);

            //remove counter

            [[YQDataManager manager] removeCounterForHash:param.hash];

        } failure:^(NSURLSessionDataTask *task, NSError *error) {

            if (retryFlag) {

                //retry

                [YQDataManager networkMananger:manager method:httpMethod retryWithUrl:url params:param success:successBlock failure:failureBlock];

            } else {

                failureBlock(error);

                //remove counter

                [[YQDataManager manager] removeCounterForHash:param.hash];

            }

            

        }];

    }else if (httpMethod == YQNetWorkTypeJsonPost){

        manager.requestSerializer = [AFJSONRequestSerializer serializer]; // 设置请求数据为 JSON 数据

        [manager POST:url parameters:param progress:nil success:^(NSURLSessionDataTask *task, id responseData) {

            successBlock(responseData);

            //remove counter

            [[YQDataManager manager] removeCounterForHash:param.hash];

        } failure:^(NSURLSessionDataTask *task, NSError *error) {

            if (retryFlag) {

                //retry

                [YQDataManager networkMananger:manager method:httpMethod retryWithUrl:url params:param success:successBlock failure:failureBlock];

            } else {

                failureBlock(error);

                //remove counter

                [[YQDataManager manager] removeCounterForHash:param.hash];

            }

        }];

    }else{

        manager.requestSerializer = [AFHTTPRequestSerializer serializer];

        [manager POST:url parameters:param progress:nil success:^(NSURLSessionDataTask *task, id responseData) {

            successBlock(responseData);

            //remove counter

            [[YQDataManager manager] removeCounterForHash:param.hash];

        } failure:^(NSURLSessionDataTask *task, NSError *error) {

            if (retryFlag) {

                //retry

                [YQDataManager networkMananger:manager method:httpMethod retryWithUrl:url params:param success:successBlock failure:failureBlock];

            } else {

                failureBlock(error);

                //remove counter

                [[YQDataManager manager] removeCounterForHash:param.hash];

            }

        }];

    }

}

 

/**

 *  网络请求的底层方法

 */

+ (void)networkProcessWithUrl:(NSString *)url

                       params:(NSDictionary *)aParams

                       method:(YQNetWorkType )httpMethod

                   modelClass:(Class)modelClass

                responseBlock:(YQNetworkResult)respBlock

{

    YQDataManager *manager = [YQDataManager manager];

    

 

    NSString *fullPath = [NSString stringWithFormat:@"%@%@",manager.baseURL,url];

    if (aParams) {

        NSError *error;

        NSData *jsonData = [NSJSONSerialization dataWithJSONObject:aParams options:0 error:&error];

        

        NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];

        NSLog(@"url : %@, param ==== %@", fullPath, jsonString);

    }else{

        NSLog(@"url : %@, param ==== %@", fullPath, aParams);

    }

    

    

    if (httpMethod == YQNetWorkTypeGet) {

 

        if ([UserManager isLogin]) {

            UserInfo *info=  [UserManager getUserObject];

            

            NSDictionary *headerFieldValueDictionary = @{@"token":info.token, @"usercode":info.userCode};

            

            if (headerFieldValueDictionary != nil) {

                for (NSString *httpHeaderField in headerFieldValueDictionary.allKeys) {

                    NSString *value = headerFieldValueDictionary[httpHeaderField];

                    [manager.requestSerializer setValue:value forHTTPHeaderField:httpHeaderField];

                }

            }

            

            

        }

        [manager GET:fullPath parameters:aParams progress:nil success:^(NSURLSessionDataTask *task, id responseData) {

            

            [YQDataManager successProcessWithModelClass:modelClass result:responseData block:respBlock];

            

        } failure:^(NSURLSessionDataTask *task, NSError *error) {

            [YQDataManager networkMananger:manager method:httpMethod  retryWithUrl:url params:aParams success:^(id respData) {

                [YQDataManager successProcessWithModelClass:modelClass result:respData block:respBlock];

            } failure:^(NSError *error) {

                [YQDataManager failureProcess:error block:respBlock];

            }];

        }];

        

    } else if (httpMethod == YQNetWorkTypeJsonPost) {

        if ([UserManager isLogin]) {

            UserInfo *info=  [UserManager getUserObject];

            

            NSDictionary *headerFieldValueDictionary = @{@"token":info.token, @"userMobile":info.userMobile};

            if (headerFieldValueDictionary != nil) {

                for (NSString *httpHeaderField in headerFieldValueDictionary.allKeys) {

                    NSString *value = headerFieldValueDictionary[httpHeaderField];

                    [manager.requestSerializer setValue:value forHTTPHeaderField:httpHeaderField];

                }

            }

            

            

        }

        

        

        manager.requestSerializer = [AFJSONRequestSerializer serializer]; // 设置请求数据为 JSON 数据

     

        [manager POST:fullPath parameters:aParams progress:nil success:^(NSURLSessionDataTask *task, id responseData) {

            

            [YQDataManager successProcessWithModelClass:modelClass result:responseData block:respBlock];

            

        } failure:^(NSURLSessionDataTask *task, NSError *error) {

            

            [YQDataManager networkMananger:manager method:httpMethod  retryWithUrl:url params:aParams success:^(id respData) {

                [YQDataManager successProcessWithModelClass:modelClass result:respData block:respBlock];

            } failure:^(NSError *error) {

                [YQDataManager failureProcess:error block:respBlock];

            }];

        }];

    }else{

        

        manager.requestSerializer = [AFHTTPRequestSerializer serializer];

        [manager POST:fullPath parameters:aParams progress:nil success:^(NSURLSessionDataTask *task, id responseData) {

            

            [YQDataManager successProcessWithModelClass:modelClass result:responseData block:respBlock];

            

        } failure:^(NSURLSessionDataTask *task, NSError *error) {

            

            [YQDataManager networkMananger:manager method:httpMethod  retryWithUrl:url params:aParams success:^(id respData) {

                [YQDataManager successProcessWithModelClass:modelClass result:respData block:respBlock];

            } failure:^(NSError *error) {

                [YQDataManager failureProcess:error block:respBlock];

            }];

            

        }];

    }

}

 

/**

 *  接口请求成功返回

 */

+ (void)successProcessWithModelClass:(Class)modelClass

                              result:(id)responseData

                               block:(YQNetworkResult)block

{

    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:responseData options:NSJSONWritingPrettyPrinted error:nil];

    NSString *jsonStr = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];

    NSLog(@"====%@",jsonStr);

    if (!block) {

        

        

        return;

    }

    //model

    if (modelClass == nil) {

        if (block) {

            block(YES, nil, responseData);

        }

    } else {

        YQBaseModel *item = [YQBaseModel yy_modelWithJSON:responseData];

        if ([item.status isEqualToString:@"SUCCESS"]) {//返回成功状态

            if ([item.data isKindOfClass:[NSDictionary class]]) {

                id model = [modelClass yy_modelWithJSON:item.data];

                if (block) {

                    block(YES, item, model);

                }

            }else{

                if (item.data) {

                    NSDictionary *josnDic = @{@"data":item.data };

                    id model = [modelClass yy_modelWithJSON:josnDic];

                    if (block) {

                        block(YES, item, model);

                    }

                }else{

                    if (block) {

                        block(YES, item, nil);

                    }

                }

            }

        }else{//返回失败状态

            if (block) {

                NSError *error = [YQDataManager errorWithDescription:item.message cede:item.code];

                block(NO, item, error);

            }

        }

    }

}

/**

 *  接口请求失败无返回

 */

+ (void)failureProcess:(NSError *)error block:(YQNetworkResult)block

{

    NSLog(@"error: %@,userInfo = %@",error, [error userInfo]);

    

    if (block) {

        block(NO, nil, error);

    }

}

 

/**

 *  get方式请求调用方法

 */

+ (void)getDataWithUrl:(NSString *)url

                Params:(NSDictionary *)params

            modelClass:(Class)modelClass

         responseBlock:(YQNetworkResult)respBlock

{

    [YQDataManager networkProcessWithUrl:url params:params method:YQNetWorkTypeGet modelClass:modelClass responseBlock:respBlock];

}

 

/**

 *  post 请求调用方式 入参Json请求数据

 */

+ (void)postDataJsonRequestWithUrl:(NSString *)url

                            Params:(NSDictionary *)params

                        modelClass:(Class)modelClass

                     responseBlock:(YQNetworkResult)respBlock

{

    [YQDataManager networkProcessWithUrl:url params:params method:YQNetWorkTypeJsonPost modelClass:modelClass responseBlock:respBlock];

}

 

/**

 *  post 请求调用方法 入参Http请求数据 

 */

+ (void)postDataHttpRequestWithUrl:(NSString *)url

                            Params:(NSDictionary *)params

                        modelClass:(Class)modelClass

                     responseBlock:(YQNetworkResult)respBlock

{

    [YQDataManager networkProcessWithUrl:url params:params method:YQNetWorkTypeHttpPost modelClass:modelClass responseBlock:respBlock];

}

 

 

#pragma mark - Utils

 

/**

 *  请求成功返回失败状态时创建错误返回

 */

+ (NSError*)errorWithDescription:(NSString *)errorMsg cede:(NSInteger)code

{

    NSString *msg = errorMsg;

    if (msg == nil) {

        msg = @"未知错误";

        code = 22222;

    }

    

    NSDictionary *userInfo = @{NSLocalizedDescriptionKey: msg};

    

    NSError *error = [NSError errorWithDomain:@"dongze" code:code userInfo:userInfo];

    

    return error;

}

 

 

@end