//
//  ServerAPI.m
//  LifeLog
//
//  Created by Nguyen Van Phong on 7/30/17.
//  Copyright © 2017 PhongNV. All rights reserved.
//

#import "ServerAPI.h"
#import "Utilities.h"

NSString *const kServerAddress = @"http://clover.timesfun.jp:9001/";
NSString *const kUser = @"KEY_USER";
NSString *const kToken = @"KEY_TOKEN";
NSString *const kNotificationToken = @"TOKEN_INVALID";

@implementation NSString (NSString_Extended)
- (NSString *)urlencode {
    NSMutableString *output = [NSMutableString string];
    const unsigned char *source = (const unsigned char *)[self UTF8String];
    int sourceLen = (int)strlen((const char *)source);
    for (int i = 0; i < sourceLen; ++i) {
        const unsigned char thisChar = source[i];
        if (thisChar == ' '){
            [output appendString:@"+"];
        } else if (thisChar == '.' || thisChar == '-' || thisChar == '_' || thisChar == '~' ||
                   (thisChar >= 'a' && thisChar <= 'z') ||
                   (thisChar >= 'A' && thisChar <= 'Z') ||
                   (thisChar >= '0' && thisChar <= '9')) {
            [output appendFormat:@"%c", thisChar];
        } else {
            [output appendFormat:@"%%%02X", thisChar];
        }
    }
    return output;
}
@end

@implementation ServerAPI
static ServerAPI *_server = nil;

NSURLSessionDataTask * searchTask;

@synthesize timeOutInterval = _timeOutInterval;

+ (instancetype)server
{
    @synchronized(self) {
        if (_server == nil) {
            _server = [[ServerAPI alloc] init];
        }
    }
    return _server;
}

- (instancetype)init
{
    self = [super init];
    if (self != nil) {
        self.timeOutInterval = 60;
    }
    return self;
}

#pragma mark - Login and Register
// Login
- (void)loginWithEmail:(NSString *)email Password:(NSString *)password CompletionHandler: (void (^)(User *, NSString *, NSError *)) completion
{
    [self _request:[kServerAddress stringByAppendingFormat: @"login"] method:@"POST" token:@"" paras:@{@"email":email, @"password": password} completion:^(NSData *data, NSError *error) {
        
        if (completion == NULL) {
            return ;
        }
        
        if (error == nil)
        {
            NSDictionary *dataResult =  [NSJSONSerialization JSONObjectWithData:data options: NSJSONReadingAllowFragments error: &error];
          
            int status = [dataResult[@"status"] intValue];
            if (status == 1) { // status = 1 success
                NSString *token = dataResult[@"result"][@"token"];
                NSDictionary *dictUser = dataResult[@"result"][@"user"];
                User *user = [[User alloc] init];
                user.user_id = [NSString stringWithFormat:@"%@",dictUser[@"id"]];
                user.username = [NSString stringWithFormat:@"%@",dictUser[@"username"]];
                user.full_name = [NSString stringWithFormat:@"%@",dictUser[@"full_name"]];
                user.nickname = [NSString stringWithFormat:@"%@",dictUser[@"nickname"]];
                user.email = [NSString stringWithFormat:@"%@",dictUser[@"email"]];
                user.password = [NSString stringWithFormat:@"%@",dictUser[@"password"]];
                user.birthday = [NSString stringWithFormat:@"%@",dictUser[@"birthday"]];
                user.address = [NSString stringWithFormat:@"%@",dictUser[@"address"]];
                user.gender = [[NSString stringWithFormat:@"%@",dictUser[@"gender"]] intValue];
                user.height = [[NSString stringWithFormat:@"%@",dictUser[@"height"]] floatValue];
                user.weight = [[NSString stringWithFormat:@"%@",dictUser[@"weight"]] floatValue];
                user.user_description = [NSString stringWithFormat:@"%@",dictUser[@"description"]];
                user.created_at = [NSString stringWithFormat:@"%@",dictUser[@"created_at"]];
                user.physical_activity = [NSString stringWithFormat:@"%@",dictUser[@"physical_activity"]];
                user.profile_image = [NSString stringWithFormat:@"%@",dictUser[@"profile_image"]];
                user.updated_at = [NSString stringWithFormat:@"%@",dictUser[@"updated_at"]];
                user.delete_flag = [[NSString stringWithFormat:@"%@",dictUser[@"delete_flag"]] intValue];
                user.fat_rate = [[NSString stringWithFormat:@"%@",dictUser[@"fat_rate"]] intValue];
                user.profiles_share = [[NSString stringWithFormat:@"%@",dictUser[@"profiles_share"]] intValue];
                user.remember_me = [[NSString stringWithFormat:@"%@",dictUser[@"remember_me"]] intValue];
                user.sound_notifications_share = [[NSString stringWithFormat:@"%@",dictUser[@"sound_notifications_share"]] intValue];
                user.spend_calo_in_day = [[NSString stringWithFormat:@"%@",dictUser[@"spend_calo_in_day"]] intValue];
                user.target = [[NSString stringWithFormat:@"%@",dictUser[@"target"]] intValue];
                completion(user, token, nil);
            }
            else { // status = 0 error
                NSString *message = dataResult[@"message"];
                if (message == nil) {
                    message = @"Unknown error";
                }
                NSError *loginFaild = [NSError errorWithDomain:@"LifeLog_Domain" code:-1 userInfo:@{@"message":message}];
                completion(nil, nil, loginFaild);
            }
        }
        else
        {
            completion(nil, nil, error);
        }
    }];
}

// Register
- (void)registerUserWithParams:(NSDictionary *)params CompletionHandler: (void (^)(User *, NSString *, NSError *)) completion {
    [self _request:[kServerAddress stringByAppendingFormat: @"register"] method:@"POST" token:@"" paras:params completion:^(NSData *data, NSError *error) {
        
        if (completion == NULL) {
            return ;
        }
        
        if (error == nil)
        {
            NSDictionary *dataResult =  [NSJSONSerialization JSONObjectWithData:data options: NSJSONReadingAllowFragments error: &error];
            
            int status = [dataResult[@"status"] intValue];
            if (status == 1) { // status = 1 success
                NSString *token = dataResult[@"result"][@"token"];
                NSDictionary *dictUser = dataResult[@"result"][@"user"];
                User *user = [[User alloc] init];
                user.user_id = [NSString stringWithFormat:@"%@",dictUser[@"id"]];
                user.username = [NSString stringWithFormat:@"%@",dictUser[@"username"]];
                user.full_name = [NSString stringWithFormat:@"%@",dictUser[@"full_name"]];
                user.nickname = [NSString stringWithFormat:@"%@",dictUser[@"nickname"]];
                user.email = [NSString stringWithFormat:@"%@",dictUser[@"email"]];
                user.password = [NSString stringWithFormat:@"%@",dictUser[@"password"]];
                user.birthday = [NSString stringWithFormat:@"%@",dictUser[@"birthday"]];
                user.address = [NSString stringWithFormat:@"%@",dictUser[@"address"]];
                user.gender = [[NSString stringWithFormat:@"%@",dictUser[@"gender"]] intValue];
                user.height = [[NSString stringWithFormat:@"%@",dictUser[@"height"]] floatValue];
                user.weight = [[NSString stringWithFormat:@"%@",dictUser[@"weight"]] floatValue];
                user.user_description = [NSString stringWithFormat:@"%@",dictUser[@"description"]];
                user.created_at = [NSString stringWithFormat:@"%@",dictUser[@"created_at"]];
                user.physical_activity = [NSString stringWithFormat:@"%@",dictUser[@"physical_activity"]];
                user.profile_image = [NSString stringWithFormat:@"%@",dictUser[@"profile_image"]];
                user.updated_at = [NSString stringWithFormat:@"%@",dictUser[@"updated_at"]];
                user.delete_flag = [[NSString stringWithFormat:@"%@",dictUser[@"delete_flag"]] intValue];
                user.fat_rate = [[NSString stringWithFormat:@"%@",dictUser[@"fat_rate"]] intValue];
                user.profiles_share = [[NSString stringWithFormat:@"%@",dictUser[@"profiles_share"]] intValue];
                user.remember_me = [[NSString stringWithFormat:@"%@",dictUser[@"remember_me"]] intValue];
                user.sound_notifications_share = [[NSString stringWithFormat:@"%@",dictUser[@"sound_notifications_share"]] intValue];
                user.spend_calo_in_day = [[NSString stringWithFormat:@"%@",dictUser[@"spend_calo_in_day"]] intValue];
                user.target = [[NSString stringWithFormat:@"%@",dictUser[@"target"]] intValue];
                completion(user, token, nil);
            }
            else { // status = 0 error
                NSString *message = dataResult[@"message"];
                if (message == nil) {
                    message = @"Unknown error";
                }
                NSError *loginFaild = [NSError errorWithDomain:@"LifeLog_Domain" code:-1 userInfo:@{@"message":message}];
                completion(nil, nil, loginFaild);
            }
        }
        else
        {
            completion(nil, nil, error);
        }
    }];
}

- (void)forgetPass:(NSString *)email CompletionHandler:(void (^)(NSError *)) completion {
    [self _request:[kServerAddress stringByAppendingFormat: @"forgetPass"] method:@"POST" token:@"" paras:@{@"email":email} completion:^(NSData *data, NSError *error) {
    
        if (completion == NULL) {
            return ;
        }
    
        if (error == nil)
        {
            NSDictionary *dataResult =  [NSJSONSerialization JSONObjectWithData:data options: NSJSONReadingAllowFragments error: &error];
      
            int status = [dataResult[@"status"] intValue];
            if (status == 1) { // status = 1 success
                completion(nil);
            }
            else { // status = 0 error
                NSString *message = dataResult[@"message"];
                if (message == nil) {
                    message = @"Unknown error";
                }
                NSError *forgetPass = [NSError errorWithDomain:@"LifeLog_Domain" code:-1 userInfo:@{@"message":message}];
                completion(forgetPass);
            }
        }
        else
        {
            completion(error);
        }
    }];
}
- (void)confirmForgetPass:(NSString *)email withConfirm:(NSString *)confirm CompletionHandler:(void (^)(NSError *)) completion {
    [self _request:[kServerAddress stringByAppendingFormat: @"forgetPass/confirm"] method:@"POST" token:@"" paras:@{@"email":email, @"code_confirm": confirm} completion:^(NSData *data, NSError *error) {
    
        if (completion == NULL) {
            return ;
        }
    
        if (error == nil)
        {
            NSDictionary *dataResult =  [NSJSONSerialization JSONObjectWithData:data options: NSJSONReadingAllowFragments error: &error];
      
            int status = [dataResult[@"status"] intValue];
            if (status == 1) { // status = 1 success
                completion(nil);
            }
            else { // status = 0 error
                NSString *message = dataResult[@"message"];
                NSError *confirmForgetPass = [NSError errorWithDomain:@"LifeLog_Domain" code:-1 userInfo:@{@"message":message}];
                completion(confirmForgetPass);
            }
        }
        else
        {
            completion(error);
        }
  }];
}

- (void)uploadImage:(NSString *)token andImageData:(NSData *)data CompletionHandler:(void (^)(NSString *, NSError *)) completion {
    NSDictionary *dict = nil;
    NSString *base64Encoded = [data base64EncodedStringWithOptions:0];
    if (token != nil) {
        dict = @{@"token":token, @"img": base64Encoded};
    }
    else {
        dict = @{@"img": base64Encoded};
    }
    [self _request:[kServerAddress stringByAppendingFormat: @"upload-image"] method:@"POST" token:token paras:dict completion:^(NSData *data, NSError *error) {
      
        if (completion == NULL) {
            return ;
        }
    
        if (error == nil)
        {
            NSDictionary *dataResult =  [NSJSONSerialization JSONObjectWithData:data options: NSJSONReadingAllowFragments error: &error];
            NSString *image_profile = [NSString stringWithFormat:@"%@", dataResult[@"message"]];
            completion(image_profile, nil);
        }
        else
        {
            completion(nil, error);
        }
    }];
}

-(NSString *) convertIntToString : (int) type {
    switch (type) {
        case 1:
            return @"week";
            break;
        case 2:
            return @"oneMonth";
            break;
        case 3:
            return @"threeMonth";
            break;
        case 4:
            return @"sixMonth";
            break;
        default:
            return @"today";
            break;
    }
}

#pragma mark - Home Screen Function
- (void)requestTopWithMode:(int)mode andDate:(NSString *)date CompletionHandler:(void (^)(TopObject *, NSError *)) completion
{
    NSString * token = [[NSUserDefaults standardUserDefaults] stringForKey:kToken];
    NSString *url = [kServerAddress stringByAppendingFormat:@"api/top/%d/%@", mode, date];
    [self _request:url method:@"GET" token:token paras:nil completion:^(NSData *data, NSError *error) {
        
        if (completion == NULL) {
            return ;
        }
        
        if (error == nil)
        {
            NSDictionary *dataResult =  [NSJSONSerialization JSONObjectWithData:data options: NSJSONReadingAllowFragments error: &error];
            int status = [dataResult[@"status"] intValue];
            if (status == 1) { // status = 1 success
                if(dataResult[@"result"] != nil) {
                    NSDictionary * dictResult = dataResult[@"result"];
                    TopObject *topObject = [[TopObject alloc] init];
                    TargetInfor *targetInfor = [[TargetInfor alloc] initWithData:dictResult[@"targetInf"]];
                    topObject.targetInfor = targetInfor;
                    topObject.kcal = [[NSString stringWithFormat:@"%@", dictResult[@"kcal"]] intValue];
                    topObject.distance = [[NSString stringWithFormat:@"%@", dictResult[@"distance"]] floatValue];
                    topObject.time = [NSString stringWithFormat:@"%@", dictResult[@"time"]];
                    NSMutableArray *arrayStep = [[NSMutableArray alloc] init];
                    NSArray *array = dictResult[@"dataChart"];
                    for(NSDictionary *dict in array) {
                        StepObject *object = [[StepObject alloc] init];
                        if([dict objectForKey:@"numStep"] != nil) {
                            object.step = [dict[@"numStep"] intValue];
                        }
                        if([dict objectForKey:@"hour"] != nil) {
                            object.hour = [dict[@"hour"] intValue];
                        }
                        switch (mode) {
                            case 1:
                                object.typeStep = @"walking";
                                break;
                            case 2:
                                object.typeStep = @"running";
                                break;
                            case 3:
                                object.typeStep = @"bike";
                                break;
                            default:
                                break;
                        }
                        [arrayStep addObject:object];
                    }
                    topObject.dataChart = [[NSMutableArray alloc] initWithArray:arrayStep];
                    completion(topObject, nil);
                }
                else {
                    NSError *errorObject = [NSError errorWithDomain:@"LifeLog_Domain" code:-1 userInfo:@{@"message":@"Unknown Error"}];
                    completion(nil, errorObject);
                }
            }
            else {
                NSString *message = dataResult[@"message"];
                if (message == nil) {
                    message = @"Unknown error";
                }
                
                if ([message isEqualToString:@"Token is invalid"]) {
                    [self checkTokenCompletionHandler:^(NSString *token, NSError *error) {
                        if (error == nil) {
                            [self requestTopWithMode:mode andDate:date CompletionHandler:completion];
                        }
                        else {
                            completion(nil, error);
                        }
                    }];
                }
                else {
                    NSError *errorObject = [NSError errorWithDomain:@"LifeLog_Domain" code:-1 userInfo:@{@"message":message}];
                    completion(nil, errorObject);
                }
            }
        }
        else
        {
            completion(nil, error);
        }
    }];
}

- (void)requestHomeWithMode:(int)mode andDate:(NSString *)date CompletionHandler:(void (^)(HomeObject *, NSError *)) completion
{
    NSString * token = [[NSUserDefaults standardUserDefaults] stringForKey:kToken];
    NSString *url = [kServerAddress stringByAppendingFormat:@"api/home/%d/%@", mode, date];
    [self _request:url method:@"GET" token:token paras:nil completion:^(NSData *data, NSError *error) {
        
        if (completion == NULL) {
            return ;
        }
        
        if (error == nil)
        {
            NSDictionary *dataResult =  [NSJSONSerialization JSONObjectWithData:data options: NSJSONReadingAllowFragments error: &error];
            int status = [dataResult[@"status"] intValue];
            if (status == 1) { // status = 1 success
                if(dataResult[@"result"] != nil) {
                    NSDictionary * dictResult = dataResult[@"result"];
                    HomeObject *homeObject = [[HomeObject alloc] init];
                    TargetInfor *targetInfor = [[TargetInfor alloc] initWithData:dictResult[@"targetInf"]];
                    homeObject.targetInfor = targetInfor;
                    NSMutableArray *arrayNotice = [[NSMutableArray alloc] init];
                    NSArray *array = dictResult[@"listNotice"];
                    for(NSDictionary *dict in array) {
                        NoticeInfor *object = [[NoticeInfor alloc] initWithData:dict];
                        [arrayNotice addObject:object];
                    }
                    homeObject.listNotice = [[NSMutableArray alloc] initWithArray:arrayNotice];
                    completion(homeObject, nil);
                }
                else {
                    NSError *errorObject = [NSError errorWithDomain:@"LifeLog_Domain" code:-1 userInfo:@{@"message":@"Unknown Error"}];
                    completion(nil, errorObject);
                }
            }
            else {
                NSString *message = dataResult[@"message"];
                if (message == nil) {
                    message = @"Unknown error";
                }
                
                if ([message isEqualToString:@"Token is invalid"]) {
                    [self checkTokenCompletionHandler:^(NSString *token, NSError *error) {
                        if (error == nil) {
                            [self requestHomeWithMode:mode andDate:date CompletionHandler:completion];
                        }
                        else {
                            completion(nil, error);
                        }
                    }];
                }
                else {
                    NSError *errorObject = [NSError errorWithDomain:@"LifeLog_Domain" code:-1 userInfo:@{@"message":message}];
                    completion(nil, errorObject);
                }
            }
        }
        else
        {
            completion(nil, error);
        }
    }];
}

- (void)requestCreateLog:(int)mode withStep:(int)numStep startDate:(NSString *)startDate endDate:(NSString *)endDate CompletionHandler:(void (^)(NSError *))completion {
    NSString * token = [[NSUserDefaults standardUserDefaults] stringForKey:kToken];
    NSString *url = [kServerAddress stringByAppendingFormat:@"api/createLog"];
    NSDictionary *dict = @{@"mode": [NSNumber numberWithInt:mode], @"numStep": [NSNumber numberWithInt:numStep], @"startTime": startDate, @"endTime": endDate};
    [self _request:url method:@"POST" token:token paras:dict completion:^(NSData *data, NSError *error) {
        
        if (completion == NULL) {
            return ;
        }
        
        if (error == nil)
        {
            NSDictionary *dataResult =  [NSJSONSerialization JSONObjectWithData:data options: NSJSONReadingAllowFragments error: &error];
            int status = [dataResult[@"status"] intValue];
            if (status == 1) { // status = 1 success
                completion(nil);
            }
            else {
                NSString *message = dataResult[@"message"];
                if (message == nil) {
                    message = @"Unknown error";
                }
                
                if ([message isEqualToString:@"Token is invalid"]) {
                    [self checkTokenCompletionHandler:^(NSString *token, NSError *error) {
                        if (error == nil) {
                            [self requestCreateLog:mode withStep:numStep startDate:startDate endDate:endDate CompletionHandler:completion];
                        }
                        else {
                            completion(error);
                        }
                    }];
                }
                else {
                    NSError *errorObject = [NSError errorWithDomain:@"LifeLog_Domain" code:-1 userInfo:@{@"message":message}];
                    completion(errorObject);
                }
            }
        }
        else
        {
            completion(error);
        }
    }];
}

#pragma mark - History Screen Function
- (void) requestHistory:(NSString *)token startDate:(NSDate *)startDate endDate:(NSDate *)endDate CompletionHandler:(void (^)(NSArray *, NSError *)) completion {
    NSString *url = [kServerAddress stringByAppendingFormat:@"api/history/%@/%@", [Utilities stringFromDate:startDate withFormat:@"YYYYMMdd" locale:@""], [Utilities stringFromDate:endDate withFormat:@"YYYYMMdd" locale:@""]];
    NSLog(@"requestHistory link %@", url);
    [self _request:url method:@"GET" token:token paras:nil completion:^(NSData *data, NSError *error) {
        
        if (completion == NULL) {
            return ;
        }
        
        if (error == nil)
        {
            NSDictionary *dataResult =  [NSJSONSerialization JSONObjectWithData:data options: NSJSONReadingAllowFragments error: &error];
            NSLog(@"%@", dataResult);
            int status = [dataResult[@"status"] intValue];
            if (status == 1) { // status = 1 success
                NSMutableArray * arrayHistory = [[NSMutableArray alloc] init];
                NSDictionary * arrResult = dataResult[@"result"];
                if(arrResult != nil) {
                    /* mode_1: Data for mode walking
                    mode_2: Data for mode running
                    mode_3: Data for mode bike */
                    NSArray *arrayKey = [NSArray arrayWithObjects:@"mode_3", @"mode_1", @"mode_2", nil];
                    for(NSString * key in arrayKey) {
                        NSDictionary *mode = [arrResult objectForKey:key];
                        if(![[arrResult objectForKey:key] isKindOfClass:[NSNull class]]) {
                            HistoryObject * objectMode = [[HistoryObject alloc] initWithData:mode];
                            [arrayHistory addObject:objectMode];
                        }
                        else {
                            [arrayHistory addObject:[[HistoryObject alloc] init]];
                        }
                    }
                }
                completion(arrayHistory, nil);
            }
            else {
                NSString *message = dataResult[@"message"];
                if (message == nil) {
                    message = @"Unknown error";
                }
                
                if ([message isEqualToString:@"Token is invalid"]) {
                    [self checkTokenCompletionHandler:^(NSString *token, NSError *error) {
                        if (error == nil) {
                            NSString *tokenNew = [[NSUserDefaults standardUserDefaults] objectForKey:kToken];
                            [self requestHistory:tokenNew startDate:startDate endDate:endDate CompletionHandler:completion];
                        }
                        else {
                            completion(nil, error);
                        }
                    }];
                }
                else {
                    NSError *errorObject = [NSError errorWithDomain:@"LifeLog_Domain" code:-1 userInfo:@{@"message":message}];
                    completion(nil, errorObject);
                }
            }
        }
        else
        {
            completion(nil, error);
        }
    }];
}

- (void) requestHistoryList:(NSString *)token startDate:(NSDate *)startDate endDate:(NSDate *)endDate CompletionHandler:(void (^)(NSArray *, NSError *)) completion {
    NSString *url = [kServerAddress stringByAppendingFormat:@"api/history/detail/%@/%@", [Utilities stringFromDate:startDate withFormat:@"YYYYMMdd" locale:@""], [Utilities stringFromDate:endDate withFormat:@"YYYYMMdd" locale:@""]];
    NSLog(@"requestHistoryList link %@", url);
    [self _request:url method:@"GET" token:token paras:nil completion:^(NSData *data, NSError *error) {
        
        if (completion == NULL) {
            return ;
        }
        
        if (error == nil)
        {
            NSDictionary *dataResult =  [NSJSONSerialization JSONObjectWithData:data options: NSJSONReadingAllowFragments error: &error];
            NSLog(@"%@", dataResult);
            int status = [dataResult[@"status"] intValue];
            if (status == 1) { // status = 1 success
                if(dataResult[@"result"] != nil) {
                    NSMutableArray * arrayHistory = [[NSMutableArray alloc] init];
                    NSDictionary * arrResult = dataResult[@"result"];
                    if(arrResult != nil) {
                        /* mode_1: Data for mode walking
                         mode_2: Data for mode running
                         mode_3: Data for mode bike */
                        NSArray *arrayKey = [NSArray arrayWithObjects:@"mode_3", @"mode_1", @"mode_2", nil];
                        for(NSString * key in arrayKey) {
                            NSDictionary *mode = [arrResult objectForKey:key];
                            if(![[arrResult objectForKey:key] isKindOfClass:[NSNull class]]) {
                                NSMutableArray *array = [[NSMutableArray alloc] init];
                                for(NSString *key in mode.allKeys) {
                                    HistoryObject * objectMode = [[HistoryObject alloc] initWithData:mode[key]];
                                    objectMode.date = [Utilities dateFromString:key withFormat:@"yyyy-MM-dd"];
                                    [array addObject:objectMode];
                                }
                                [arrayHistory addObject:array];
                            }
                            else {
                                [arrayHistory addObject:[[NSArray alloc] init]];
                            }
                        }
                    }
                    completion(arrayHistory, nil);
                }
                else {
                    NSError *errorObject = [NSError errorWithDomain:@"LifeLog_Domain" code:-1 userInfo:@{@"message":@"Unknown Error"}];
                    completion(nil, errorObject);
                }
            }
            else {
                NSString *message = dataResult[@"message"];
                if (message == nil) {
                    message = @"Unknown error";
                }
                
                if ([message isEqualToString:@"Token is invalid"]) {
                    [self checkTokenCompletionHandler:^(NSString *token, NSError *error) {
                        if (error == nil) {
                            NSString *tokenNew = [[NSUserDefaults standardUserDefaults] objectForKey:kToken];
                            [self requestHistoryList:tokenNew startDate:startDate endDate:endDate CompletionHandler:completion];
                        }
                        else {
                            completion(nil, error);
                        }
                    }];
                }
                else {
                    NSError *errorObject = [NSError errorWithDomain:@"LifeLog_Domain" code:-1 userInfo:@{@"message":message}];
                    completion(nil, errorObject);
                }
            }
        }
        else
        {
            completion(nil, error);
        }
    }];
}

#pragma mark - SNS Screen Function
- (void) requestTweetsList:(NSString *)token groupID: (int) groupID withPage:(int)page CompletionHandler:(void (^)(NSArray *, NSError *)) completion {
    NSString *url = [kServerAddress stringByAppendingFormat:@"api/tweet/list?page=%d&record=10", page];
    if(groupID > -1) {
        url = [kServerAddress stringByAppendingFormat:@"api/tweet/list?group_id=%d&page=%d&record=10", groupID, page];
    }
    NSLog(@"requestTweetsList link %@", url);
    [self _request:url method:@"GET" token:token paras:nil completion:^(NSData *data, NSError *error) {
        
        if (completion == NULL) {
            return ;
        }
        
        if (error == nil)
        {
            NSDictionary *dataResult =  [NSJSONSerialization JSONObjectWithData:data options: NSJSONReadingAllowFragments error: &error];
            NSLog(@"%@", dataResult);
            int status = [dataResult[@"status"] intValue];
            if (status == 1) { // status = 1 success
                if(dataResult[@"result"] != nil) {
                    NSArray * array = dataResult[@"result"];
                    NSMutableArray * arrayTweets = [[NSMutableArray alloc] init];
                    for(NSDictionary * dict in array) {
                        TweetObject * object = [[TweetObject alloc] initWithData:dict];
                        [arrayTweets addObject:object];
                    }
                    completion(arrayTweets, nil);
                }
                else {
                    NSError *errorObject = [NSError errorWithDomain:@"LifeLog_Domain" code:-1 userInfo:@{@"message":@"Unknown Error"}];
                    completion(nil, errorObject);
                }
            }
            else {
                NSString *message = dataResult[@"message"];
                if (message == nil) {
                    message = @"Unknown error";
                }
                
                if ([message isEqualToString:@"Token is invalid"]) {
                    [self checkTokenCompletionHandler:^(NSString *token, NSError *error) {
                        if (error == nil) {
                            NSString *tokenNew = [[NSUserDefaults standardUserDefaults] objectForKey:kToken];
                            [self requestTweetsList:tokenNew groupID:groupID withPage:page CompletionHandler:completion];
                        }
                        else {
                            completion(nil, error);
                        }
                    }];
                }
                else {
                    NSError *errorObject = [NSError errorWithDomain:@"LifeLog_Domain" code:-1 userInfo:@{@"message":message}];
                    completion(nil, errorObject);
                }
            }
        }
        else
        {
            completion(nil, error);
        }
    }];
}

- (void) searchGroup:(NSString *)token withKey:(NSString *)key andPage:(int)page CompletionHandler:(void (^)(NSArray *, NSError *)) completion {
    NSString *url = [kServerAddress stringByAppendingFormat:@"api/sns/group/search"];
    NSLog(@"searchGroup link %@ page %d", url, page);
    if(searchTask != nil) {
        [searchTask cancel];
    }
    
    searchTask = [self _request:url method:@"POST" token:token paras:@{@"keyword":key, @"page": [NSNumber numberWithInt:page]}  completion:^(NSData *data, NSError *error) {
        searchTask = nil;
        if (completion == NULL) {
            return ;
        }
        
        if (error == nil)
        {
            NSDictionary *dataResult =  [NSJSONSerialization JSONObjectWithData:data options: NSJSONReadingAllowFragments error: &error];
            NSLog(@"%@", dataResult);
            int status = [dataResult[@"status"] intValue];
            if (status == 1) { // status = 1 success
                if(dataResult[@"result"] != nil) {
                    NSArray * array = dataResult[@"result"];
                    NSMutableArray * arrayTweets = [[NSMutableArray alloc] init];
                    for(NSDictionary * dict in array) {
                        GroupObject * object = [[GroupObject alloc] initWithData:dict];
                        [arrayTweets addObject:object];
                    }
                    completion(arrayTweets, nil);
                }
                else {
                    NSError *errorObject = [NSError errorWithDomain:@"LifeLog_Domain" code:-1 userInfo:@{@"message":@"Unknown Error"}];
                    completion(nil, errorObject);
                }
            }
            else {
                NSString *message = dataResult[@"message"];
                NSError *errorObject = [NSError errorWithDomain:@"LifeLog_Domain" code:-1 userInfo:@{@"message":message}];
                completion(nil, errorObject);
            }
        }
        else
        {
            completion(nil, error);
        }
    }];
}

#pragma mark - Group Function
-(void) requestCreateGroup:(NSString *)token withGroup:(GroupObject *)group CompletionHandler:(void (^)(GroupObject *, NSError *)) completion {
    NSString *url = [kServerAddress stringByAppendingFormat:@"api/groups/newGroup"];
    NSLog(@"requestCreateGroup link %@", url);
    NSDictionary * dict = @{@"group_name":group.name,
                            @"goal":group.goal,
                            @"walk_mode_active":[NSNumber numberWithBool:group.walkMode],
                            @"run_mode_active":[NSNumber numberWithBool:group.runMode],
                            @"bike_mode_active":[NSNumber numberWithBool:group.bikeMode],
                            @"step_mode_active":[NSNumber numberWithBool:group.stepMode],
                            @"gym_mode_active":[NSNumber numberWithBool:group.gymMode],
                            @"beginer_mode_active":[NSNumber numberWithBool:group.beginMode],
                            @"walk_mode_goal":[NSNumber numberWithBool:group.walkGoal],
                            @"run_mode_goal":[NSNumber numberWithBool:group.runGoal],
                            @"bike_mode_goal":[NSNumber numberWithBool:group.bikeGoal]};
    
    [self _request:url method:@"POST" token:token paras:dict completion:^(NSData *data, NSError *error) {
        
        if (completion == NULL) {
            return ;
        }
        
        if (error == nil)
        {
            NSDictionary *dataResult =  [NSJSONSerialization JSONObjectWithData:data options: NSJSONReadingAllowFragments error: &error];
            NSLog(@"%@", dataResult);
            int status = [dataResult[@"status"] intValue];
            if (status == 1) { // status = 1 success
                if(dataResult[@"result"] != nil) {
                    NSDictionary * dict = dataResult[@"result"];
                    group.groupID = [dict[@"group_id"] intValue];
                    completion(group, nil);
                }
                else {
                    NSError *errorObject = [NSError errorWithDomain:@"LifeLog_Domain" code:-1 userInfo:@{@"message":@"Unknown Error"}];
                    completion(nil, errorObject);
                }
            }
            else {
                NSString *message = dataResult[@"message"];
                if (message == nil) {
                    message = @"Unknown error";
                }
                
                if ([message isEqualToString:@"Token is invalid"]) {
                    [self checkTokenCompletionHandler:^(NSString *token, NSError *error) {
                        if (error == nil) {
                            NSString *tokenNew = [[NSUserDefaults standardUserDefaults] objectForKey:kToken];
                            [self requestCreateGroup:tokenNew withGroup:group CompletionHandler:completion];
                        }
                        else {
                            completion(nil, error);
                        }
                    }];
                }
                else {
                    NSError *errorObject = [NSError errorWithDomain:@"LifeLog_Domain" code:-1 userInfo:@{@"message":message}];
                    completion(nil, errorObject);
                }
            }
        }
        else
        {
            completion(nil, error);
        }
    }];
}

- (void) getGroupDetail:(NSString *)token withGroupID:(int)groupID CompletionHandler:(void (^)(GroupObject *, NSError *)) completion {
    NSString *url = [kServerAddress stringByAppendingFormat:@"api/sns/group/detail/%d", groupID];
    NSLog(@"getGroupDetail link %@", url);
    [self _request:url method:@"GET" token:token paras:nil completion:^(NSData *data, NSError *error) {
        
        if (completion == NULL) {
            return ;
        }
        
        if (error == nil)
        {
            NSDictionary *dataResult =  [NSJSONSerialization JSONObjectWithData:data options: NSJSONReadingAllowFragments error: &error];
            NSLog(@"%@", dataResult);
            int status = [dataResult[@"status"] intValue];
            if (status == 1) { // status = 1 success
                if(dataResult[@"result"] != nil) {
                    NSArray * array = dataResult[@"result"];
                    GroupObject * object = [[GroupObject alloc] initWithData:array[0] andGroupID:groupID];
                    completion(object, nil);
                }
                else {
                    NSError *errorObject = [NSError errorWithDomain:@"LifeLog_Domain" code:-1 userInfo:@{@"message":@"Unknown Error"}];
                    completion(nil, errorObject);
                }
            }
            else {
                NSString *message = dataResult[@"message"];
                if (message == nil) {
                    message = @"Unknown error";
                }
                
                if ([message isEqualToString:@"Token is invalid"]) {
                    [self checkTokenCompletionHandler:^(NSString *token, NSError *error) {
                        if (error == nil) {
                            NSString *tokenNew = [[NSUserDefaults standardUserDefaults] objectForKey:kToken];
                            [self getGroupDetail:tokenNew withGroupID:groupID CompletionHandler:completion];
                        }
                        else {
                            completion(nil, error);
                        }
                    }];
                }
                else {
                    NSError *errorObject = [NSError errorWithDomain:@"LifeLog_Domain" code:-1 userInfo:@{@"message":message}];
                    completion(nil, errorObject);
                }
            }
        }
        else
        {
            completion(nil, error);
        }
    }];
}

- (void) requestMemberList:(NSString *)token groupID: (int) groupID withPage:(int)page CompletionHandler:(void (^)(NSArray *, NSError *)) completion {
    NSString *url = [kServerAddress stringByAppendingFormat:@"api/sns/group/member/%d/%d", groupID, page];
    NSLog(@"requestMemberList link %@ page %d", url, page);
    
    [self _request:url method:@"GET" token:token paras:nil  completion:^(NSData *data, NSError *error) {
        if (completion == NULL) {
            return ;
        }
        
        if (error == nil)
        {
            NSDictionary *dataResult =  [NSJSONSerialization JSONObjectWithData:data options: NSJSONReadingAllowFragments error: &error];
            NSLog(@"%@", dataResult);
            int status = [dataResult[@"status"] intValue];
            if (status == 1) { // status = 1 success
                if(dataResult[@"result"] != nil) {
                    NSArray * array = dataResult[@"result"];
                    NSMutableArray * arrayTweets = [[NSMutableArray alloc] init];
                    for(NSDictionary * dict in array) {
                        MemberObject * object = [[MemberObject alloc] initWithData:dict];
                        [arrayTweets addObject:object];
                    }
                    completion(arrayTweets, nil);
                }
                else {
                    NSError *errorObject = [NSError errorWithDomain:@"LifeLog_Domain" code:-1 userInfo:@{@"message":@"Unknown Error"}];
                    completion(nil, errorObject);
                }
            }
            else {
                NSString *message = dataResult[@"message"];
                if (message == nil) {
                    message = @"Unknown error";
                }
                
                if ([message isEqualToString:@"Token is invalid"]) {
                    [self checkTokenCompletionHandler:^(NSString *token, NSError *error) {
                        if (error == nil) {
                            NSString *tokenNew = [[NSUserDefaults standardUserDefaults] objectForKey:kToken];
                            [self requestMemberList:tokenNew groupID:groupID withPage:page CompletionHandler:completion];
                        }
                        else {
                            completion(nil, error);
                        }
                    }];
                }
                else {
                    NSError *errorObject = [NSError errorWithDomain:@"LifeLog_Domain" code:-1 userInfo:@{@"message":message}];
                    completion(nil, errorObject);
                }
            }
        }
        else
        {
            completion(nil, error);
        }
    }];
}

- (void) requestJoinGroup:(NSString *)token groupID: (int) groupID CompletionHandler:(void (^)(NSError *)) completion {
    NSString *url = [kServerAddress stringByAppendingFormat:@"api/sns/group/join"];
    NSLog(@"requestJoinGroup link %@", url);
    
    [self _request:url method:@"POST" token:token paras:@{@"group_id": [NSNumber numberWithInt:groupID]}  completion:^(NSData *data, NSError *error) {
        if (completion == NULL) {
            return ;
        }
        
        if (error == nil)
        {
            NSDictionary *dataResult =  [NSJSONSerialization JSONObjectWithData:data options: NSJSONReadingAllowFragments error: &error];
            NSLog(@"%@", dataResult);
            int status = [dataResult[@"status"] intValue];
            if (status == 1) { // status = 1 success
                if(dataResult[@"result"] != nil) {
                    completion(nil);
                }
                else {
                    NSError *errorObject = [NSError errorWithDomain:@"LifeLog_Domain" code:-1 userInfo:@{@"message":@"Unknown Error"}];
                    completion(errorObject);
                }
            }
            else {
                NSString *message = dataResult[@"message"];
                if ([message isEqualToString:@"Token is invalid"]) {
                    [self checkTokenCompletionHandler:^(NSString *token, NSError *error) {
                        if (error == nil) {
                            NSString *tokenNew = [[NSUserDefaults standardUserDefaults] objectForKey:kToken];
                            [self requestJoinGroup:tokenNew groupID:groupID CompletionHandler:completion];
                        }
                        else {
                            completion(error);
                        }
                    }];
                }
                else {
                    NSError *errorObject = [NSError errorWithDomain:@"LifeLog_Domain" code:-1 userInfo:@{@"message":message}];
                    completion(errorObject);
                }
            }
        }
        else
        {
            completion(error);
        }
    }];
}

- (void) requestGroupList:(NSString *)token CompletionHandler:(void (^)(NSArray *, NSError *)) completion {
    NSString *url = [kServerAddress stringByAppendingFormat:@"api/groups/list"];
    NSLog(@"requestGroupList link %@", url);
    
    [self _request:url method:@"GET" token:token paras:nil completion:^(NSData *data, NSError *error) {
        if (completion == NULL) {
            return ;
        }
        
        if (error == nil)
        {
            NSDictionary *dataResult =  [NSJSONSerialization JSONObjectWithData:data options: NSJSONReadingAllowFragments error: &error];
            NSLog(@"%@", dataResult);
            int status = [dataResult[@"status"] intValue];
            if (status == 1) { // status = 1 success
                if(dataResult[@"result"] != nil) {
                    NSArray * array = dataResult[@"result"];
                    NSMutableArray * arrayGroup = [[NSMutableArray alloc] init];
                    for(NSDictionary * dict in array) {
                        GroupObject * object = [[GroupObject alloc] initWithShortData:dict];
                        [arrayGroup addObject:object];
                    }
                    completion(arrayGroup, nil);
                }
                else {
                    NSError *errorObject = [NSError errorWithDomain:@"LifeLog_Domain" code:-1 userInfo:@{@"message":@"Unknown Error"}];
                    completion(nil, errorObject);
                }
            }
            else {
                NSString *message = dataResult[@"message"];
                if (message == nil) {
                    message = @"Unknown error";
                }
                
                if ([message isEqualToString:@"Token is invalid"]) {
                    [self checkTokenCompletionHandler:^(NSString *token, NSError *error) {
                        if (error == nil) {
                            NSString *tokenNew = [[NSUserDefaults standardUserDefaults] objectForKey:kToken];
                            [self requestGroupList:tokenNew CompletionHandler:completion];
                        }
                        else {
                            completion(nil, error);
                        }
                    }];
                }
                else {
                    NSError *errorObject = [NSError errorWithDomain:@"LifeLog_Domain" code:-1 userInfo:@{@"message":message}];
                    completion(nil, errorObject);
                }
            }
        }
        else
        {
            completion(nil, error);
        }
    }];
}

#pragma mark - Ranking API
- (void) requestRankingList:(NSString *)token startDate:(NSDate *)startDate endDate:(NSDate *)endDate mode:(int) mode page:(int) page CompletionHandler:(void (^)(NSArray *, NSError *)) completion {
    NSString *url = [kServerAddress stringByAppendingFormat:@"api/ranking/%d/%@/%@/%d", mode, [Utilities stringFromDate:startDate withFormat:@"YYYYMMdd" locale:@""], [Utilities stringFromDate:endDate withFormat:@"YYYYMMdd" locale:@""], page];
    NSLog(@"requestRaningList link %@", url);
    [self _request:url method:@"GET" token:token paras:nil completion:^(NSData *data, NSError *error) {
        
        if (completion == NULL) {
            return ;
        }
        
        if (error == nil)
        {
            NSDictionary *dataResult =  [NSJSONSerialization JSONObjectWithData:data options: NSJSONReadingAllowFragments error: &error];
            NSLog(@"%@", dataResult);
            int status = [dataResult[@"status"] intValue];
            if (status == 1) { // status = 1 success
                NSArray * array = dataResult[@"result"];
                NSMutableArray * arrayRanking = [[NSMutableArray alloc] init];
                for(NSDictionary * dict in array) {
                    RankingObject * object = [[RankingObject alloc] initWithData:dict];
                    [arrayRanking addObject:object];
                }
                completion(arrayRanking, nil);
            }
            else {
                NSString *message = dataResult[@"message"];
                if (message == nil) {
                    message = @"Unknown error";
                }
                
                if ([message isEqualToString:@"Token is invalid"]) {
                    [self checkTokenCompletionHandler:^(NSString *token, NSError *error) {
                        if (error == nil) {
                            NSString *tokenNew = [[NSUserDefaults standardUserDefaults] objectForKey:kToken];
                            [self requestRankingList:tokenNew startDate:startDate endDate:endDate mode:mode page:page CompletionHandler:completion];
                        }
                        else {
                            completion(nil, error);
                        }
                    }];
                }
                else {
                    NSError *errorObject = [NSError errorWithDomain:@"LifeLog_Domain" code:-1 userInfo:@{@"message":message}];
                    completion(nil, errorObject);
                }
            }
        }
        else
        {
            completion(nil, error);
        }
    }];
}

#pragma mark - Common API
- (void)refreshToken: (NSString *)userID CompletionHandler:(void (^)(NSString *, NSError *))completion {
    [self _request:[kServerAddress stringByAppendingFormat: @"refreshToken"] method:@"POST" token:@"" paras:@{@"userId":userID} completion:^(NSData *data, NSError *error) {
        
        if (completion == NULL) {
            return ;
        }
        
        if (error == nil)
        {
            NSDictionary *dataResult =  [NSJSONSerialization JSONObjectWithData:data options: NSJSONReadingAllowFragments error: &error];
            
            int status = [dataResult[@"status"] intValue];
            if (status == 1) { // status = 1 success
                NSArray *arrayResult = dataResult[@"result"];
                if (arrayResult.count > 0) {
                    NSString *token = arrayResult[0];
                    completion(token, nil);
                }
                else {
                    NSError *errorObject = [NSError errorWithDomain:@"LifeLog_Domain" code:-1 userInfo:@{@"message":@"refreshToken Error"}];
                    completion(nil, errorObject);
                }
                
            }
            else { // status = 0 error
                NSString *message = dataResult[@"message"];
                if (message == nil) {
                    message = @"refreshToken Error";
                }
                NSError *loginFaild = [NSError errorWithDomain:@"LifeLog_Domain" code:-1 userInfo:@{@"message":message}];
                completion(nil, loginFaild);
            }
        }
        else
        {
            completion(nil, error);
        }
    }];
}

- (void)getNoticeByDate: (NSString *)date CompletionHandler:(void (^)(NSArray *, NSError *)) completion
{
    [self _request:[kServerAddress stringByAppendingFormat: @"api/getnoticesbydate/%@", date] method:@"GET" token:@"" paras:nil completion:^(NSData *data, NSError *error) {
        
        if (completion == NULL) {
            return ;
        }
        
        if (error == nil)
        {
            NSDictionary *dataResult =  [NSJSONSerialization JSONObjectWithData:data options: NSJSONReadingAllowFragments error: &error];
            
            int status = [dataResult[@"status"] intValue];
            if (status == 1) { // status = 1 success
                NSArray *arrayResult = dataResult[@"result"][@"listNotice"];
                if (arrayResult.count > 0) {
                    NSMutableArray *notices = [[NSMutableArray alloc] init];
                    for(NSDictionary *dict in arrayResult) {
                        NSString *object = [dict objectForKey:@"notice_content"];
                        [notices addObject:object];
                    }
                    completion(notices, nil);
                }
                else {
                    NSError *errorObject = [NSError errorWithDomain:@"LifeLog_Domain" code:-1 userInfo:@{@"message":@"Today is not notice"}];
                    completion(nil, errorObject);
                }
                
            }
            else { // status = 0 error
                NSString *message = dataResult[@"message"];
                if (message == nil) {
                    message = @"Unknown error";
                }
                NSError *loginFaild = [NSError errorWithDomain:@"LifeLog_Domain" code:-1 userInfo:@{@"message":message}];
                completion(nil, loginFaild);
            }
        }
        else
        {
            completion(nil, error);
        }
    }];
}

#pragma mark - Private Function
- (void) checkTokenCompletionHandler:(void (^)(NSString *, NSError *)) completion
{
    NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:kUser];
    User *user = (User *)[NSKeyedUnarchiver unarchiveObjectWithData:data];
    if (user != nil) {
        [self refreshToken:user.user_id CompletionHandler:^(NSString *token, NSError *error) {
            if (error == nil) {
                [[NSUserDefaults standardUserDefaults] setObject:token forKey:kToken];
                [[NSUserDefaults standardUserDefaults] synchronize];
                completion(token, nil);
            }
            else {
                completion(nil, error);
            }
        }];
    }
    else {
        NSError *error = [NSError errorWithDomain:@"LifeLog_Domain" code:-1 userInfo:@{@"message":@"User not found"}];
        completion(nil, error);
    }
}

- (NSData *) _encodeDictionary: (NSDictionary *) dictionary
{
    NSMutableArray *parts = [[NSMutableArray alloc] init];
    for (id key in dictionary)
    {
        NSString *encodedValue = [[dictionary[key] description] urlencode];
        NSString *encodedKey = [[key description] stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];//[[key description] urlencode];
        NSString *part = [NSString stringWithFormat: @"%@=%@", encodedKey, encodedValue];
        [parts addObject:part];
    }
    NSString *encodedDictionary = [parts componentsJoinedByString:@"&"];
    return [encodedDictionary dataUsingEncoding: NSUTF8StringEncoding];
}

- (NSURLSessionDataTask *) _request:(NSString *)address method:(NSString *)method token:(NSString *) token paras:(NSDictionary *)paras completion:(void (^)(NSData *data, NSError *error))completion
{
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL: [NSURL URLWithString:address]];
    request.HTTPMethod = method;
    [request setValue: @"application/json" forHTTPHeaderField: @"Accept"];
    [request setValue: @"application/json" forHTTPHeaderField: @"Content-Type"];
    if(token != nil && ![token  isEqual: @""]) {
        [request setValue: token forHTTPHeaderField: @"token"];
    }
    [request setTimeoutInterval:self.timeOutInterval];
    
    if (paras != nil)
    {
        NSData *encodedData = [self _encodeDictionary: paras];
        [request setValue: @"application/x-www-form-urlencoded charset=utf-8" forHTTPHeaderField: @"Content-Type"];
        [request setHTTPBody: encodedData];
    }
    
    //NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionConfiguration *defaultConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
    [defaultConfiguration setHTTPMaximumConnectionsPerHost:20];
    NSOperationQueue *operationQueue = [NSOperationQueue mainQueue];
    operationQueue.maxConcurrentOperationCount = 20;
    NSURLSession *session = [NSURLSession sessionWithConfiguration:defaultConfiguration delegate:nil delegateQueue:operationQueue];
    NSURLSessionDataTask *task = [session dataTaskWithRequest:request
                                            completionHandler:
                                  ^(NSData *data, NSURLResponse *response, NSError *error) {
                                      if (completion == NULL) {
                                          return ;
                                      }
                                      if (error == nil)
                                      {
                                          completion(data, nil);
                                      }
                                      else
                                      {
                                          completion(nil, error);
                                      }
                                  }];
    [task resume];
    return task;
}

-(void)waitUntilDone:(void(^)(void))waitBlock {
    //use your statement or call method here
    if(waitBlock){
        waitBlock();
    }
}

@end
