//
//  NewTestScheduler.m
//  SKCore
//
//  Created by jungeol.park on 2014. 10. 8..
//  Copyright (c) 2014 ACCVUER. All rights reserved.
//

#import "NewTestScheduler.h"

#define DEFUALT_TRANSFER_PORT @"8000"
#define DEFUALT_LATENCY_PORT @"8001"

#define DOWNLOAD_WARMUP_MAX_TIME @"5000000"
#define DOWNLOAD_WARMUP_MAX_BYTES @"2621440"
#define DOWNLOAD_BUFFER_SIZE @"1048576"

#define UPLOAD_WARMUP_MAX_TIME @"5000000"
#define UPLOAD_WARMUP_MAX_BYTES @"2621440"
#define UPLOAD_SEND_DATA_CHUNK @"512"
#define UPLOAD_POSTDATA_LENGTH @"1048576"

#define LATENCY_PERCENTILE @"100"

@implementation NewTestScheduler

-(id)init
{
    self = [super init];
    
    if(self)
    {
    }
    
    return self;
}

-(BOOL)startLoadConfigFromJsonFiles
{
    m_serverList = [SKGlobalMethods getServerListFromJson];
    m_downloadedScenarioDic = [SKGlobalMethods getScenarioFromJson];
    m_localSavedScenarioDic = [SKGlobalMethods getLocalSavedScenarioFromJson];
    
    return [self poplateClosestTargetInfo];
}

-(BOOL)poplateClosestTargetInfo
{
    if(m_serverList == nil || m_serverList.count == 0)
        return NO;
    
    hosts = [[NSMutableArray alloc] initWithCapacity:m_serverList.count];
    for (NSDictionary *temp in m_serverList)
    {
        NSString *ip = [temp objectForKey:@"Address"];
        NSString *name = [temp objectForKey:@"Name"];
        NSDictionary *host = [[NSDictionary alloc] initWithObjectsAndKeys:
                              name, @"display_name",
                              ip, @"dns_name",
                              nil];
        [hosts addObject:host];
    }
    
    // create Closest Target
    self.m_closestTargetTestInfo = [[NSMutableDictionary alloc] init];
    [self.m_closestTargetTestInfo setObject:@"closestTarget" forKey:@"type"];
    [self.m_closestTargetTestInfo setObject:@"Closest Target" forKey:@"displayName"];
    
    NSMutableArray *params = [[NSMutableArray alloc] init];
    for (NSDictionary *temp in m_serverList)
    {
        NSString *ip = [temp objectForKey:@"Address"];
        NSDictionary *paramDic = [[NSDictionary alloc] initWithObjectsAndKeys:
                                  ip, @"target",
                                  nil];
        [params addObject:paramDic];
    }
    [self.m_closestTargetTestInfo setObject:params forKey:@"params"];
    
    return YES;
}

-(void)poplateAllTestsInfoWithBestServer:(NSString *)bestServerName
{
    NSMutableDictionary *scenarioDic = [self getScenarioDic];
    
    if(bestServerName == nil || bestServerName.length == 0)
        return;
    if(m_serverList == nil || m_serverList.count == 0)
        return;
    if(scenarioDic == nil || scenarioDic.count == 0)
        return;
    
#ifdef DEBUG
    NSLog(@"poplateAllTestsInfoWithBestServer");
#endif
    
    NSString *transferPort = DEFUALT_TRANSFER_PORT;
    NSString *latencyPort = DEFUALT_LATENCY_PORT;
    for (NSDictionary *temp in m_serverList)
    {
        NSString *serverName = [temp objectForKey:@"Name"];
        if([bestServerName isEqualToString:serverName])
        {
            transferPort = [temp objectForKey:@"Speedtestport"];
            latencyPort = [temp objectForKey:@"latencyport"];
            break;
        }
    }
    
    
    /////////// create test schedule
    self.tests = [[NSMutableArray alloc] init];
    
    // create download schedule
    NSDictionary *downloadConfig = [scenarioDic objectForKey:@"Download"];
    
    if(downloadConfig == nil || downloadConfig.count == 0)
        return;
    
    NSString *downloadSessionCount = [downloadConfig objectForKey:@"Session"];
    NSString *downloadMaxTime = [downloadConfig objectForKey:@"Time"];
    int downloadRepeatCount = [[downloadConfig objectForKey:@"Count"] intValue];
    int downloadFileSizeMB = [[downloadConfig objectForKey:@"Filesize"] intValue];
    NSString *downloadMaxBytes = [NSString stringWithFormat:@"%ld", [self convertMBtoByte:downloadFileSizeMB]];
    
    for (int i=0; i<downloadRepeatCount; i++) 
    {
        NSMutableDictionary *downloadTestDic = [[NSMutableDictionary alloc] init];
        
        [downloadTestDic setObject:@"downstreamthroughput" forKey:@"type"];
        [downloadTestDic setObject:@"Download" forKey:@"displayName"];
        
        NSMutableArray *paramsDL = [[NSMutableArray alloc] initWithObjects:
                                    [[NSDictionary alloc] initWithObjectsAndKeys:@"$closest", @"target", nil],
                                    [[NSDictionary alloc] initWithObjectsAndKeys:transferPort, @"port", nil],
                                    [[NSDictionary alloc] initWithObjectsAndKeys:@"100000000MB.bin", @"file", nil],
                                    [[NSDictionary alloc] initWithObjectsAndKeys:DOWNLOAD_WARMUP_MAX_TIME, @"warmupmaxtime", nil],
                                    [[NSDictionary alloc] initWithObjectsAndKeys:DOWNLOAD_WARMUP_MAX_BYTES, @"warmupmaxbytes", nil],
                                    [[NSDictionary alloc] initWithObjectsAndKeys:downloadMaxTime, @"transfermaxtime", nil],
                                    [[NSDictionary alloc] initWithObjectsAndKeys:downloadMaxBytes, @"transfermaxbytes", nil],
                                    [[NSDictionary alloc] initWithObjectsAndKeys:DOWNLOAD_BUFFER_SIZE, @"buffersize", nil],
                                    [[NSDictionary alloc] initWithObjectsAndKeys:downloadSessionCount, @"numberofthreads", nil],
                                    nil];
        [downloadTestDic setObject:paramsDL forKey:@"params"];
        
        [self.tests addObject:downloadTestDic];
    }
    
    // create upload schedule
    NSDictionary *uploadConfig = [scenarioDic objectForKey:@"Upload"];
    
    if(uploadConfig == nil || uploadConfig.count == 0)
        return;
    
    NSString *uploadSessionCount = [uploadConfig objectForKey:@"Session"];
    NSString *uploadMaxTime = [uploadConfig objectForKey:@"Time"];
    int uploadRepeatCount = [[uploadConfig objectForKey:@"Count"] intValue];
    int uploadFileSizeMB = [[uploadConfig objectForKey:@"Filesize"] intValue];
    NSString *uploadMaxBytes = [NSString stringWithFormat:@"%ld", [self convertMBtoByte:uploadFileSizeMB]];
    
    for (int i=0; i<uploadRepeatCount; i++) 
    {
        NSMutableDictionary *uploadTestDic = [[NSMutableDictionary alloc] init];
        
        [uploadTestDic setObject:@"upstreamthroughput" forKey:@"type"];
        [uploadTestDic setObject:@"Upload" forKey:@"displayName"];
        
        NSMutableArray *paramsUL = [[NSMutableArray alloc] initWithObjects:
                                    [[NSDictionary alloc] initWithObjectsAndKeys:@"$closest", @"target", nil],
                                    [[NSDictionary alloc] initWithObjectsAndKeys:transferPort, @"port", nil],
                                    [[NSDictionary alloc] initWithObjectsAndKeys:@"100MB.bin", @"file", nil],
                                    [[NSDictionary alloc] initWithObjectsAndKeys:UPLOAD_WARMUP_MAX_TIME, @"warmupmaxtime", nil],
                                    [[NSDictionary alloc] initWithObjectsAndKeys:UPLOAD_WARMUP_MAX_BYTES, @"warmupmaxbytes", nil],
                                    [[NSDictionary alloc] initWithObjectsAndKeys:uploadMaxTime, @"transfermaxtime", nil],
                                    [[NSDictionary alloc] initWithObjectsAndKeys:uploadMaxBytes, @"transfermaxbytes", nil],
                                    [[NSDictionary alloc] initWithObjectsAndKeys:UPLOAD_SEND_DATA_CHUNK, @"sendDataChunk", nil],
                                    [[NSDictionary alloc] initWithObjectsAndKeys:UPLOAD_POSTDATA_LENGTH, @"postdatalength", nil],
                                    [[NSDictionary alloc] initWithObjectsAndKeys:uploadSessionCount, @"numberofthreads", nil],
                                    nil];
        [uploadTestDic setObject:paramsUL forKey:@"params"];
        
        [self.tests addObject:uploadTestDic];
    }
    
    // create latency schedule
    NSDictionary *latencyConfig = [scenarioDic objectForKey:@"Latency"];
    
    if(latencyConfig == nil || latencyConfig.count == 0)
        return;
    
    NSString *packteInterval = [latencyConfig objectForKey:@"Interval"];
    NSString *delayTimeout = [latencyConfig objectForKey:@"Timeout"];
    NSString *numberOfPacket = [latencyConfig objectForKey:@"numberOfPacket"];
    NSString *latencyMaxTime = [latencyConfig objectForKey:@"Time"];
    
    NSMutableDictionary *latencyTestDic = [[NSMutableDictionary alloc] init];
    
    [latencyTestDic setObject:@"latency" forKey:@"type"];
    [latencyTestDic setObject:@"Latency / Loss" forKey:@"displayName"];
    
    NSMutableArray *paramsLatency = [[NSMutableArray alloc] initWithObjects:
                                     [[NSDictionary alloc] initWithObjectsAndKeys:@"$closest", @"target", nil],
                                     [[NSDictionary alloc] initWithObjectsAndKeys:latencyPort, @"port", nil],
                                     [[NSDictionary alloc] initWithObjectsAndKeys:packteInterval, @"interPacketTime", nil],
                                     [[NSDictionary alloc] initWithObjectsAndKeys:delayTimeout, @"delayTimeout", nil],
                                     [[NSDictionary alloc] initWithObjectsAndKeys:numberOfPacket, @"numberOfPackets", nil],
                                     [[NSDictionary alloc] initWithObjectsAndKeys:LATENCY_PERCENTILE, @"percentile", nil],
                                     [[NSDictionary alloc] initWithObjectsAndKeys:latencyMaxTime, @"maxTime", nil],
                                     nil];
    [latencyTestDic setObject:paramsLatency forKey:@"params"];
    
    [self.tests addObject:latencyTestDic];
}

#pragma mark - getter


-(NSMutableDictionary *)getScenarioDic
{
    m_downloadedScenarioDic = [SKGlobalMethods getScenarioFromJson];
    m_localSavedScenarioDic = [SKGlobalMethods getLocalSavedScenarioFromJson];
    
    if(m_downloadedScenarioDic == nil && m_localSavedScenarioDic == nil)
        return nil;
    
    if (m_localSavedScenarioDic == nil || m_localSavedScenarioDic.count == 0)
    {
        return [[NSMutableDictionary alloc] initWithDictionary:m_downloadedScenarioDic];
    }
    
    return [[NSMutableDictionary alloc] initWithDictionary:m_localSavedScenarioDic];
}

- (NSString*)getClosestTargetName:(NSString*)dns
{
    if (nil == hosts) return nil;
    if ([hosts count] == 0) return nil;
    
    bool bFound = false;
    NSString *result = nil;
    for (int m=0; m<[hosts count]; m++)
    {
        if (bFound) break;
        NSDictionary *dict = [hosts objectAtIndex:m];
        
        if (nil != dict)
        {
            if ([dict objectForKey:@"dns_name"] && [dict objectForKey:@"display_name"])
            {
                NSString *dns_name = [dict objectForKey:@"dns_name"];
                NSString *display_name = [dict objectForKey:@"display_name"];
                
                if ([dns isEqualToString:dns_name])
                {
                    bFound = true;
                    result = display_name;
                }
            }
        }
    }
    
    if (bFound)
    {
        return result;
    }
    
    // To reach here, we couldn't find a suitable display name!
    // Return the original name (typically: an IP address)
    //SK_ASSERT(false);
    
    return dns;
}

-(NSString *)getTransferTestPort
{
    if (nil == self.tests) return nil;
    if ([self.tests count] == 0) return nil;
    
    for (int j=0; j<[self.tests count]; j++)
    {
        NSDictionary *dict = [self.tests objectAtIndex:j];
        
        if (nil != dict)
        {
            if ([dict objectForKey:@"type"])
            {
                NSString *type = [dict objectForKey:@"type"];
                
                if ([type isEqualToString:@"downstreamthroughput"]
                    || [type isEqualToString:@"upstreamthroughput"])
                {
                    NSArray *params = [dict objectForKey:@"params"];
                    for (NSDictionary *temp in params)
                    {
                        if ([temp objectForKey:@"port"])
                            return [temp valueForKey:@"port"];
                        
                    }
                }
            }
        }
    }
    
    return nil;
}

-(long)convertMBtoByte:(int)xMb
{
    return xMb * 1048576;
}

@end
