iOS_Subhra
4/26/2018 - 6:27 AM

ThumbnailGenerator

TO Download thumbnail data for files

//
//  SPThumbnailGenerator.swift
//  SROperations
//
//  Created by Subhr Roy on 21/08/17.
//  Copyright © 2017 Subhr Roy. All rights reserved.
//

import Foundation
import CoreData


class SPThumbnailGenerator: SROperation,URLSessionTaskDelegate {
    
    var  storeFilePath : String?
    var  saveFilePath : String?
    var  url : URL?
    var  fileName : String?
    
    fileprivate (set) var  downloadTask : URLSessionDownloadTask?
	fileprivate (set) var  dataTask : URLSessionDataTask?
    var  category : OperationCategory?
    fileprivate (set) var  progressContentLength : Int64 = 0
    fileprivate (set) var  expectedContentLength : Int64 = 0
    fileprivate (set) var  thumbnailDownloadURL : URL?
	fileprivate (set) var  fileThumbnailResponseData : Data?
    
    //MARK:--------Init Thumbnail Downloader---------//
    
    func  initiate(_ urlString : String? = nil , _hasIdentifier : String? = nil, _groupIdentifier : String? = nil, _storefilePath : String? = nil, _saveFilePath : String? = nil, operationQueue : OperationQueue? = OperationQueue.main ,inProgress : Bool = false , isPreSign : Bool = false , opDelegate: OperationTaskDelegate? = nil , operationCategory : OperationCategory = OperationCategory.thumbnailDownload ,priority : OperationPriority? = OperationPriority.high , isCopy : Bool = false) throws -> Bool{
        
       
        self.storeFilePath = _storefilePath
        self.saveFilePath = _saveFilePath
        self.isVisualEffectEnable = false
        self.category = operationCategory
        
         super.initiate(_hasIdentifier, groupIdentifier: _groupIdentifier , progress: inProgress , delegate:opDelegate ,priority:priority,isCopy: isCopy)
        
        
        if let fileURL = urlString {
            
            self.url = URL(string: fileURL)
            
        }else{
            
            throw  Result.Failure(ErrorType.notFound)
            
        }
        
        if isNotNull(_hasIdentifier){
            
            //Fetch
            return  true
            
        }else{
            
            throw Result.Failure(ErrorType.nullValue)
            
        }
        
    }
    
    //MARK:-------Downloder Default Session--------//
    lazy var  thumbDefaultSession : URLSession = {
        
        //appSessionDefaultConfige.sessionSendsLaunchEvents = true;    //-------Edited By Subhra-------------//
        //appSessionDefaultConfige.isDiscretionary = true;
        let  session = URLSession(configuration: appSessionDefaultConfige, delegate: self , delegateQueue: nil) //OperationQueue.main
        session.sessionDescription = self.hashIdentifier
        return  session
        
    }()
    
    //MARK:------Execute operation-------//
    override  func  execute(){

        super.execute()
        self.inProgress = true
        self.fileThumbnailResponseData = Data()
        let arcCommon = ARCCommon()
        
        if let filePath = self.storeFilePath ,!arcCommon.isPDFValidAtPath(filePath) || !arcCommon.isFileExistAt(filePath) {
            
            self.inProgress = true
            self.expectedContentLength = -1
            self.progressContentLength = 0
            
            guard  let serviceURL = self.url else { return }
            
            let  _token = ARCPreference.shared().authToken() ?? ""
            let requestHeader : [String : String] = [head_token     : _token,
                                                     head_moduleId  : "PWP",
                                                     content_type   : "application/json"]
            
            let request : NSMutableURLRequest = NSMutableURLRequest(url: serviceURL, cachePolicy: URLRequest.CachePolicy.reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: SROperationConstant.timeIntervalForRequest);
            
            request.httpMethod = "POST"
            request.allHTTPHeaderFields = requestHeader
            request.setValue("application/json", forHTTPHeaderField: "Content-Type")
            request.setValue("gzip", forHTTPHeaderField: "Accept-Encoding")
            
            let urlRequest : URLRequest = request as URLRequest
            
            let  session = self.thumbDefaultSession
			if let taskIdentifier = self.hashIdentifier, taskIdentifier.isEqual(session.sessionDescription){
				
				self.dataTask = session.dataTask(with: urlRequest)
				self.dataTask?.resume()
			}else{
				
				self.cleanupThumbConnection()
			}
			
        }else{
            
            
        }
        
    }
    
    //MARK:------Download Thumbnails------//
    func downloadThumbnails() -> Void{
        
        guard  let thumburl = self.thumbnailDownloadURL else{
            
            print("\n\n Fail presigned requst: \(String(describing: self.fileName)) \n Download Url: \(String(describing: self.thumbnailDownloadURL)) \n hashIdentifier: \(String(describing: self.hashIdentifier))")
			
			let identifier : String = self.hashIdentifier ?? ""
            self.queueManagerDelegate?.operationDidFail(self , closure: { [weak self] (_ , _) in
                
				DispatchQueue.main.async {
					
					NotificationCenter.default.post(name: NSNotification.Name(DOWNLOAD_END), object: identifier)
				}
				self?.cleanupThumbConnection()

            })
            
            return
        }
		
		if let _dataTask = self.dataTask{
			
			_dataTask.cancel()
		}
        
        let thumbRequest = URLRequest(url: thumburl, cachePolicy: URLRequest.CachePolicy.reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: SROperationConstant.timeIntervalForRequest)
        
        let  session = self.thumbDefaultSession
		if let taskIdentifier = self.hashIdentifier, taskIdentifier.isEqual(session.sessionDescription){
			
			self.downloadTask = session.downloadTask(with: thumbRequest)
			
			guard let thumbnailDownloadtask = self.downloadTask  else{
				
				return
				
			}
			thumbnailDownloadtask.resume()
			
		}else{
			
			self.cleanupThumbConnection()
		}
		
    }
    
    //MARK:--------Finished Operation---------//
    override func finished(_ errors: [NSError]?) {
        
        super.finished(errors)

    }
    
    //MARK:--------Cancel Operation---------//
    override func cancel() {
		
		super.cancel()
		
        let identifier : String = self.hashIdentifier ?? ""
        self.queueManagerDelegate?.operationDidFail(self ,closure: { [weak self] (_ , _) in
			
            DispatchQueue.main.async {
                
                NotificationCenter.default.post(name: NSNotification.Name(DOWNLOAD_END), object: identifier)
            }
			self?.cleanupThumbConnection()

        })
        
    }
    
    //MARK:-----Clean Up Task-------//
    func cleanupThumbConnection() -> Void{
        
	    if let thumbnailDownloadtask = self.downloadTask {
            
            thumbnailDownloadtask.cancel()
            
        }
		
		if let _dataTask = self.dataTask{
			
			_dataTask.cancel()
		}
		

		self.inProgress = false
		self.finished([])
		//self.thumbDefaultSession.invalidateAndCancel()
		self.queueManagerDelegate?.removeOperationFromArrayWith(self)

    }
    
    deinit {
        
        print("ThumbnailGenerator Dealloc")
    }
    
}

extension  SPThumbnailGenerator:URLSessionDataDelegate,URLSessionDownloadDelegate{
	
	/*func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
		
		let authMethod = challenge.protectionSpace.authenticationMethod
		
		switch authMethod {
		case NSURLAuthenticationMethodServerTrust:
			
			if let serverTrust = challenge.protectionSpace.serverTrust{
				
				var secResult = SecTrustResultType.invalid
				let status : OSStatus = SecTrustEvaluate(serverTrust, &secResult)
				
				switch status {
					
					case errSecSuccess:
						
						print("\(SecTrustGetCertificateCount(serverTrust))")
						if let serverTrustCertificate : SecCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0){
							
							
							// Public key pinning
							if #available(iOS 10.3, *) {
								if let serverHashPublicKey : SecKey = SecCertificateCopyPublicKey(serverTrustCertificate){
									
									let serverPublicKeyData : Data = SecKeyCopyExternalRepresentation(serverHashPublicKey, nil)! as Data
									let keyHash = ARCCommon().sha256(data: serverPublicKeyData as Data)
									
									print("\(keyHash)")
									
									if (keyHash == KpinnedPublicKeyHash) {
										// Success! This is our server
										completionHandler(.useCredential, URLCredential(trust:serverTrust))
										return
									}
								}
							} else {
								// Fallback on earlier versions
								
								if let serverHashPublicKey : String = SecCertificateCopySubjectSummary(serverTrustCertificate) as String?{
									
									var serverPublicKeyData : Data?
									if #available(iOS 10.0, *) {
										serverPublicKeyData = SecKeyCopyExternalRepresentation(serverHashPublicKey as! SecKey, nil)! as Data
									} else {
										// Fallback on earlier versions
										//serverPublicKeyData =
									}
									
									let keyHash = ARCCommon().sha256(data: serverPublicKeyData!)
									if (keyHash == KpinnedPublicKeyHash) {
										// Success! This is our server
										completionHandler(.useCredential, URLCredential(trust:serverTrust))
										return
									}
									
								}
								
							}
							
						}
					
					default:
						print("")
						
				}
				
			}
			
		default:
			print("")
		}
			
		// Pinning failed
		completionHandler(.cancelAuthenticationChallenge, nil)
		
	}*/
    
    public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Swift.Void){
        
        if(dataTask.state == URLSessionTask.State.canceling) {
			
			let identifier : String = self.hashIdentifier ?? ""
			self.queueManagerDelegate?.operationDidFail(self ,closure: { [weak self] (_ , _) in
				
				DispatchQueue.main.async {
					
					NotificationCenter.default.post(name: NSNotification.Name(DOWNLOAD_END), object: identifier)
				}
				self?.cleanupThumbConnection()

			})
			
            completionHandler(.cancel)
            return
            
        }else{
            
            if response is HTTPURLResponse {
                
                if let urlResponse : HTTPURLResponse = response as? HTTPURLResponse{
                    
                    let httpsResponse : HTTPURLResponse = urlResponse
                    let statusCode = httpsResponse.statusCode
                    let responseHeader = httpsResponse.allHeaderFields
                    
                    print("\(responseHeader)")
                    
                    if statusCode == 200 {
                        
                        guard  let _ = self.saveFilePath else{
                            
							let identifier : String = self.hashIdentifier ?? ""
							self.queueManagerDelegate?.operationDidFail(self ,closure: { [weak self] (_ , _) in
								
								DispatchQueue.main.async {
									
									NotificationCenter.default.post(name: NSNotification.Name(DOWNLOAD_END), object: identifier)
								}
								self?.cleanupThumbConnection()

							})
                            
                            completionHandler(.cancel)
                            
                            return
                            
                        }
                        
                        if self.expectedContentLength == -1 {
                            
                            self.expectedContentLength = response.expectedContentLength
                            
                        } else {
                            
                        }
                        
                        self.queueManagerDelegate?.operationDidStart(self , closure: { [weak self] _ , _ in
                            
                            print("Start : \(String(describing: self?.hashIdentifier))")
                            
                        })
						
						completionHandler(.allow)
                        
                    }else if statusCode >= 400{
                        
						let identifier : String = self.hashIdentifier ?? ""
						self.queueManagerDelegate?.operationDidFail(self ,closure: { [weak self] (_ , _) in
							
							DispatchQueue.main.async {
								
								NotificationCenter.default.post(name: NSNotification.Name(DOWNLOAD_END), object: identifier)
							}
							self?.cleanupThumbConnection()

						})
						
						completionHandler(.cancel)
                    }
                    
                }
                
            }else{
                
                self.expectedContentLength = -1
                
				let identifier : String = self.hashIdentifier ?? ""
				self.queueManagerDelegate?.operationDidFail(self ,closure: { [weak self] (_ , _) in
					
					DispatchQueue.main.async {
						
						NotificationCenter.default.post(name: NSNotification.Name(DOWNLOAD_END), object: identifier)
					}
					self?.cleanupThumbConnection()

				})
				
				completionHandler(.cancel)
                
            }
            
        }
		
    }
    
    
    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data){
        
        if(dataTask.state == URLSessionTask.State.canceling) {
            
            return
            
        }else{
            
			guard let _ = self.thumbnailDownloadURL else{
				
				self.fileThumbnailResponseData?.append(data)
				return
			}
        }
        
    }
   
    
  func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64){
        
        print("Document Thumb Progress...")
            
    }
    
     func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, willCacheResponse proposedResponse: CachedURLResponse, completionHandler: @escaping (CachedURLResponse?) -> Swift.Void){

        if proposedResponse.response.url?.scheme == "https" {
            let updatedResponse = CachedURLResponse(response: proposedResponse.response,
                                                    data: proposedResponse.data,
                                                    userInfo: proposedResponse.userInfo,
                                                    storagePolicy: .allowed)
            completionHandler(updatedResponse)
        } else {
            completionHandler(proposedResponse)
        }

    }
    
   func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL){
    
        // Check if the operation has been cancelled
        if(downloadTask.state == URLSessionTask.State.canceling) {
			
			let identifier : String = self.hashIdentifier ?? ""
			self.queueManagerDelegate?.operationDidFail(self ,closure: { [weak self] (_ , _) in
				
				DispatchQueue.main.async {
					
					NotificationCenter.default.post(name: NSNotification.Name(DOWNLOAD_END), object: identifier)
				}
				self?.cleanupThumbConnection()

			})
            return
        }
            // Check if the operation has been Suspended
        else  if(downloadTask.state == URLSessionTask.State.suspended) {
            //downloadTask.suspend()
			//self.cleanupThumbConnection()
			
			let identifier : String = self.hashIdentifier ?? ""
			self.queueManagerDelegate?.operationDidFail(self ,closure: { [weak self] (_ , _) in
				
				DispatchQueue.main.async {
					
					NotificationCenter.default.post(name: NSNotification.Name(DOWNLOAD_END), object: identifier)
				}
				self?.cleanupThumbConnection()

			})
			
            return
        }
    
        let  data =  try! Data(contentsOf: location)
    
        //self.multiThreadFileWriter?.write(data, toFileOffset: self.progressContentLength)
        //self.multiThreadFileWriter?.write(data, toFileOffset: self.progressContentLength, completion: { [unowned self] _ in
    
            guard  let filePath = self.saveFilePath else {
                
				let identifier : String = self.hashIdentifier ?? ""
				self.queueManagerDelegate?.operationDidFail(self ,closure: { [weak self] (_ , _) in
					
					DispatchQueue.main.async {
						
						NotificationCenter.default.post(name: NSNotification.Name(DOWNLOAD_END), object: identifier)
					}
					self?.cleanupThumbConnection()

				})
				
                return
            }
            self.progressContentLength = self.progressContentLength + Int64(data.count)
    
            let fileManager : FileManager = FileManager.default
            if fileManager.fileExists(atPath: filePath){
                
                
            }else{
                let savePathURL = URL(fileURLWithPath: filePath)
                do{
                    
                    try fileManager.moveItem(at: location, to: savePathURL)
                    
                }catch let error{
                    
                    print("\(error.localizedDescription)")
                    print("Can't move download file")
                }
            }
    
            //-------------//
            
            if self.progressContentLength.hashValue > 0 {
                
               // print("\n\n Finish \n Download Url: \(String(describing: self.thumbnailDownloadURL)) \n hashIdentifier: \(String(describing: self.hashIdentifier))")
                
                self.queueManagerDelegate?.operationDidFinish(self, errors: [] , closure: { [weak self] (_,_) in
					
					let thumbnailId : String = self?.hashIdentifier ?? ""
                     print("Finish : \(String(describing: thumbnailId))")
                    DispatchQueue.main.async {
                        
                        NotificationCenter.default.post(name: NSNotification.Name(DOWNLOAD_END), object: thumbnailId)
                    }
					self?.cleanupThumbConnection()

                    
                })
                
            }else{
                
                print("\n\n Fail presigned requst: \(String(describing: self.fileName)) \n Download Url: \(String(describing: self.thumbnailDownloadURL)) \n hashIdentifier: \(String(describing: self.hashIdentifier))")
                
                self.queueManagerDelegate?.operationDidFail(self , closure: { [weak self] (_ , _) in
					
					let thumbnailId : String = self?.hashIdentifier ?? ""
                    DispatchQueue.main.async {
                        
                        NotificationCenter.default.post(name: NSNotification.Name(DOWNLOAD_END), object: thumbnailId)
                    }
					self?.cleanupThumbConnection()

                })
                
            }
        
    }
    
    public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didResumeAtOffset fileOffset: Int64, expectedTotalBytes: Int64){
        
        
    }
    
    public func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?){
        
        // Check if the operation has been cancelled
        if(task.state == URLSessionTask.State.canceling){
            let thumbnailId : String = self.hashIdentifier ?? ""
            self.queueManagerDelegate?.operationDidFail(self, closure: { [weak  self] _, _  in
				
                DispatchQueue.main.async {
                    
                    NotificationCenter.default.post(name: NSNotification.Name(DOWNLOAD_END), object: thumbnailId)
                }
				self?.cleanupThumbConnection()

                
            })
            
            return
        }
            // Check if the operation has been Suspended
        else if(task.state == URLSessionTask.State.suspended) {
           // task.suspend()
            let thumbnailId : String = self.hashIdentifier ?? ""
            self.queueManagerDelegate?.operationDidFail(self, closure: { [weak self]  _, _  in
				
                DispatchQueue.main.async {
                    
                    NotificationCenter.default.post(name: NSNotification.Name(DOWNLOAD_END), object: thumbnailId)
                }
				self?.cleanupThumbConnection()

                
            })
            
            return
        }
        
		if let errorInfo = error{
			
			print("Thumb Download completed with error: \(String(describing: errorInfo.localizedDescription))")
			print("\(String(describing: self.thumbnailDownloadURL))")
			self.queueManagerDelegate?.operationDidFail(self, closure: {  [weak self] _, _  in
				
				let thumbnailId : String = self?.hashIdentifier ?? ""
				
				DispatchQueue.main.async {
					
					NotificationCenter.default.post(name: NSNotification.Name(DOWNLOAD_END), object: thumbnailId)
					
				}
				self?.cleanupThumbConnection()
				
				
			})
			
		}else{
			
				guard let _ = self.thumbnailDownloadURL else{
					
					if let data = self.fileThumbnailResponseData{
						
						let  response : String? = String(data: data, encoding: .utf8)
						
						let  thumbnailURL = response?.replacingOccurrences(of: "\"", with: "")
						
						if let flatMapThumbURL = thumbnailURL{
							
							self.thumbnailDownloadURL = URL(string: flatMapThumbURL)
							self.downloadThumbnails()
							
						}else{
							
							print("\n\n Fail presigned requst: \(String(describing: self.fileName)) \n Download Url: \(String(describing: self.thumbnailDownloadURL)) \n hashIdentifier: \(String(describing: self.hashIdentifier))")
							
							let identifier : String = self.hashIdentifier ?? ""
							self.queueManagerDelegate?.operationDidFail(self ,closure: { [weak self] (_ , _) in
								
								DispatchQueue.main.async {
									
									NotificationCenter.default.post(name: NSNotification.Name(DOWNLOAD_END), object: identifier)
								}
								self?.cleanupThumbConnection()
								
							})
							
						}
						
					}
					
					return
					
				}
			
		}
		
    }
	
	func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?){
		
		print("Session to invalidate : \(session)")
		print("Session Operation Count : \(session.delegateQueue.operations.count)")
		
	}
	func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession){
		
		print("Session to invalidate : \(session)")
	}
	
    
}