//
//  WSUploadloadSession.m
//  zhuxun
//
//  Created by winsoft on 17/6/26.
//
//

#import "WSUploadSession.h"
#import "AsyncSocket.h"
#import "DataInputStream.h"
#import "DataOutputStream.h"
#import "NSData+crc32.h"
#import "NSData+MD5Digest.h"

#import "NSDictionary+JSON.h"
#import "NSString+Extension.h"

#import "FileUtils.h"

#define ChunkSize 8*1024
@interface WSUploadSession()

@property (nonatomic , copy) NSString *fileName;
@property (nonatomic, copy)NSString *filePath;
@property (nonatomic, copy)NSString *uuid;

//@property (nonatomic, assign)AttachType attachMentType;

/*文件发送相关*/
@property (nonatomic, strong)AsyncSocket *asyncSocket;
@property (nonatomic, strong)NSSet *runLoopModes;
@property (nonatomic, copy)NSMutableData *sendData;
@property (nonatomic, copy)NSString *md5;
@property (nonatomic, assign)unsigned long long fileSize;
//初始偏移量
@property (nonatomic, assign)unsigned long long uploadOffset;

@property (nonatomic , copy) NSString *host;
@property (nonatomic , copy) NSString *port;

@end
@implementation WSUploadSession
+ (WSUploadSession *)uploadFileWithServerHost:(NSString *)host port:(NSString *)port fileMD5:(NSString *)fileMD5  uuid:(NSString *)uuid fileSize:(NSInteger)fileSize startSize:(NSInteger)startSize localFileFullPath:(NSString *)localFileFullPath processBlock:(UploadProgressBlock)processBlock successBlock:(UploadSuccessBlock)successBlock failBlock:(UploadFailedBlock)failBlock
{
    WSUploadSession *uploadSession = [[WSUploadSession alloc]initUploadFileWithServerHost:host port:port fileMD5:fileMD5 uuid:uuid fileSize:fileSize startSize:startSize localFileFullPath:localFileFullPath processBlock:processBlock successBlock:successBlock failBlock:failBlock];
    return uploadSession;
}

- (id)initUploadFileWithServerHost:(NSString *)host port:(NSString *)port fileMD5:(NSString *)fileMD5   uuid:(NSString *)uuid fileSize:(NSInteger)fileSize startSize:(NSInteger)startSize localFileFullPath:(NSString *)localFileFullPath processBlock:(UploadProgressBlock)processBlock successBlock:(UploadSuccessBlock)successBlock failBlock:(UploadFailedBlock)failBlock
{
    if (self = [super init]) {
        self.uploadProgressBlock = processBlock;
        self.uploadFailedBlock = failBlock;
        self.uploadSuccessBlock = successBlock;
        
        if ([_asyncSocket isConnected]) {
            [_asyncSocket disconnect];
            _asyncSocket.delegate = nil;
            _asyncSocket = nil;
        }
        
        _asyncSocket = [[AsyncSocket alloc] initWithDelegate:self];
        _runLoopModes = [NSSet setWithObject:NSRunLoopCommonModes];
        
        _uploadOffset = startSize;
        
        if ([FileUtils fileSizeAtPath:localFileFullPath] < fileSize) {
            
            fileSize = [FileUtils fileSizeAtPath:localFileFullPath];
        };
        
        _fileSize = fileSize;
        
        _filePath = localFileFullPath;
        
        _fileName = localFileFullPath.lastPathComponent;
        
        _host = host;
        
        _port = port;
        
        _md5 = fileMD5;
        
        _uuid = uuid;
        
        [self operationDidStart];
    }
    

    return self;
}

//+ (void)networkRequestThreadEntryPoint:(id)__unused object {
//    @autoreleasepool {
//        [[NSThread currentThread] setName:@"TCPSocketUpLod"];
//        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
//        [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
//        [runLoop run];
//    }
//}
//
//+ (NSThread *)networkRequestThread {
//    static NSThread *_networkRequestThread = nil;
//    static dispatch_once_t oncePredicate;
//    dispatch_once(&oncePredicate, ^{
//        _networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil];
//        [_networkRequestThread start];
//    });
//    return _networkRequestThread;
//}
//
//
//
//-(void)start
//{
//    if ([self isCancelled]) {
//        [self performSelector:@selector(operationDidStart) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[_runLoopModes allObjects]];
//    } else if ([self isReady]) {
//        [self performSelector:@selector(operationDidStart) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[_runLoopModes allObjects]];
//    }
//}

//FILE_UP_SERVER_HOST FILE_UP_SERVER_PORT
- (void)operationDidStart {
    NSError *error;
    if (![_asyncSocket connectToHost:_host onPort:[_port integerValue]  error:&error])
    {
        NSLog(@"Error connecting: %@", error);
    }
}

#pragma mark --
#pragma mark -- sockectOperate
-(void)writeToSocket:(NSMutableData *)data {
    [_asyncSocket writeData:data withTimeout:-1 tag:0];
    [_asyncSocket readDataToData:[AsyncSocket JsonData] withTimeout:-1 tag:1];
}

#pragma mark socket delegate

- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port
{
    NSLog(@"didConnectToHost");//通过数据包的偏移位置来控制断点上传的二进制数据 00112000231
    NSData *bitData = [self makeChunk:_uploadOffset];
    
    if (bitData) {
        [self writeToSocket:[[NSMutableData alloc]initWithData:[self makeChunk:_uploadOffset]]];
    }
    
}

#warning 文件上传/下载只有两种状态，取消，下载
-(void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{
    //如果用户退出，如何判断消息是上次还是下载，则msg新增字段，这里为上传。
    
    DataInputStream *inputData = [DataInputStream dataInputStreamWithData:data];
    NSString *str = [inputData readUTF];
    if (!str) {
        
         [self cancerUpload];
        
        if (self.uploadFailedBlock) {
            self.uploadFailedBlock(@"error",self.uuid);
        }
        
//        if (self.uploadFailedDBBlock) {
//            self.uploadFailedDBBlock(@"error",self.uuid);
//        }
        
       
        return;
    }
    
    NSDictionary* dic = str.jsonValue;
    BOOL success = [[dic objectForKey:@"success"] boolValue];
    NSInteger code = [[dic valueForKey:@"code"] integerValue];
    if (!success) {
        NSString *errMessage = [dic objectForKey:@"message"];
        NSLog(@"message:---%@", errMessage);

         [self cancerUpload];
        if (self.uploadFailedBlock) {
            self.uploadFailedBlock(errMessage,self.uuid);
        }
        

       
        
        return;
    }
    //区分状态码的返回结果
    if (code == 304) {
        
        //
        if (self.uploadSuccessBlock) {
            self.uploadSuccessBlock(nil,_fileSize,self.md5);
            
        }
        
//        if (self.uploadSuccessDBBlock) {
//            self.uploadSuccessDBBlock(nil,_fileSize,self.md5);
//        }

//        if (self.completionBlock) {
//            self.completionBlock();
//        }
        

        //关闭连接
        [sock disconnect];
        

        return;
    }else if(code == 200){
        unsigned long long start = [[dic valueForKey:@"accept"] integerValue];
        double progress = ((double)start/_fileSize);
        if (self.uploadProgressBlock) {
            self.uploadProgressBlock(progress,start,self.uuid);
            NSLog(@"当前人物uuid--%@",self.uuid);
        }
        
//        if (self.uploadProgressDBBlock) {
//            self.uploadProgressDBBlock(progress,start,self.uuid);
//        }
        _uploadOffset = start;
        NSLog(@"已经上传%llu， 当前进度%f%%", start, progress*100);
    
        [self writeToSocket:[[NSMutableData alloc]initWithData:[self makeChunk:start]]];
    }
}


-(void)onSocketDidDisconnect:(AsyncSocket *)sock
{
    NSLog(@"socketDidDisconnect");
    
}

-(void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err
{
    NSLog(@"socketDidDisconnect with error");
  

    [self cancerUpload];
    
    if (self.uploadFailedBlock) {
        self.uploadFailedBlock(@"onSocketDidDisconnect",self.uuid);
    }

    
}



#pragma mark --
#pragma mark --
/*客户端向服务端发送文件:
 
 本次传输的包总长度(0-4)
 +协议说明JSON长度(4-8)
 {
 "md5":"E96261B90BE7B1895E9193D9CB9AAC5A",
 "crc":"F9C19B6F",
 "cmd":"1",
 "fileName":"0483737.xls",
 "offset":0,
 "user":
 {
 "sender":"serverid-gyj","receiver":"serverid-joe"
 },
 "fileLength":83456,
 "client":
 {
 "name":"realicq",
 "version":"6.5"
 },
 "complete":1
 }
 +文件流长度(4位)+文件流
 */

-(NSData *)makeChunk:(unsigned long long) start{
    
    NSUInteger toSendChunkSize = 0;
    if (start + ChunkSize > _fileSize) {
        toSendChunkSize = (unsigned int)(_fileSize - start);
    }else{
        toSendChunkSize = ChunkSize;
    }
    NSData *chunk = [[NSMutableData alloc] init];
    
    if (_sendData && !_filePath) {

         [self cancerUpload];
        
        if (self.uploadFailedBlock) {
            self.uploadFailedBlock(@"upload fail",self.uuid);
        }
        
       
        

        return nil;
        
        
    }else{

        NSFileHandle *readHandle = [NSFileHandle fileHandleForReadingAtPath:_filePath];
        [readHandle seekToFileOffset:start];
        if(!readHandle)
        {

            [self cancerUpload];
            
            if (self.uploadFailedBlock) {
                self.uploadFailedBlock(@"error",self.uuid);
            }
            
            
            
            return nil;
        }
        
        NSInputStream *inputStream = [NSInputStream inputStreamWithData:[readHandle readDataOfLength:toSendChunkSize]];
        [inputStream open];
        
        chunk = [[NSMutableData alloc]initWithLength:toSendChunkSize];
        NSUInteger readLength = (NSUInteger)[inputStream read:(uint8_t*)[chunk bytes] maxLength:chunk.length];
        if (readLength != [chunk length]) {
            
             [self cancerUpload];
            
            if (self.uploadFailedBlock) {
                self.uploadFailedBlock(@"error",self.uuid);
            }
            

           
            
            return nil;
        }
        [inputStream close];
    }
    

    NSString *crc32 = [NSString stringWithFormat:@"%@",[[NSString alloc] initWithFormat:@"%08x",chunk.crc32]];
    
    NSDictionary *chunkDes = nil;
    
    
    //    if (self.messageType == MESSAGE_TYPE_GROUP) {
    
    chunkDes = @{
                 @"md5":_md5,
                 @"crc":crc32,
                 @"cmd":@"1",
                 @"fileName":_fileName,
                 @"offset":@(start),
                 @"fileLength":@(_fileSize),
                 @"client":@{@"name":@"iOS",@"version":@"1.0"},
                 @"complete":@(1)
                 };
    
    
    NSLog(@"chunkDes:  %@",chunkDes);
    
    NSString *desString=[chunkDes jsonString];
    
    DataOutputStream *outData = [DataOutputStream new];
    
    [outData writeInt:0];
    [outData writeUTF:desString];
    [outData writeBytes:chunk];
    [outData writeDataCount];
    
    NSData *sendData = [outData toByteArray];
    if(!sendData)
    {
  
        [self cancerUpload];
        if (self.uploadFailedBlock) {
            
            self.uploadFailedBlock(@"error",self.uuid);
        }
        

        
        
    }
    return sendData;
}

- (void)cancerUpload
{
//    [super cancel];
    
    if (_asyncSocket.isConnected) {
        [_asyncSocket disconnect];
        _asyncSocket.delegate = nil;
        _asyncSocket = nil;
    }
    
    
    
}

- (void)resumeUpload
{
    
    
}

@end
