<commit_before>//
//  PageInfoRequest.swift
//  Hoverlytics
//
//  Created by <NAME> on 2/05/2015.
//  Copyright (c) 2015 <NAME>. All rights reserved.
//

import Foundation
import Alamofire
import Ono


public class PageInfoRequest {
	typealias CompletionHandler = (info: PageInfo, infoRequest: PageInfoRequest) -> Void
	
	public let URL: NSURL
	public let includingContent: Bool
	public let method: Alamofire.Method
	public let expectedBaseContentType: BaseContentType
	let completionHandler: CompletionHandler
	var request: Alamofire.Request?
	
	init(URL: NSURL, expectedBaseContentType: BaseContentType, includingContent: Bool = false, completionHandler: CompletionHandler) {
		self.URL = URL
		self.expectedBaseContentType = expectedBaseContentType
		self.includingContent = includingContent
		self.method = includingContent ? .GET : .HEAD
		self.completionHandler = completionHandler
	}
	
	func copyNotIncludingContent() -> PageInfoRequest {
		return PageInfoRequest(URL: URL, expectedBaseContentType: expectedBaseContentType, includingContent: false, completionHandler: completionHandler)
	}
}

private class PageInfoReference {
	let info: PageInfo
	
	init(info: PageInfo) {
		self.info = info
	}
}

class PageInfoRequestQueue {
	let requestManager: Alamofire.Manager
	let maximumActiveRequests = 5
	var activeRequests = [PageInfoRequest]()
	var pendingRequests = [PageInfoRequest]()
	var willPerformHTTPRedirection: ((redirectionInfo: RequestRedirectionInfo) -> Void)?
	var didFinishWithRequest: ((infoRequest: PageInfoRequest) -> Void)?
	
	init() {
		let manager = Alamofire.Manager()
		self.requestManager = manager
		
		let managerDelegate = manager.delegate
		managerDelegate.taskWillPerformHTTPRedirection = { [weak self] session, task, response, request in
			#if DEBUG
				print("taskWillPerformHTTPRedirection")
			#endif
			
			if let
				willPerformHTTPRedirection = self?.willPerformHTTPRedirection,
				originalRequest = task.originalRequest
			{
				let info = RequestRedirectionInfo(sourceRequest: originalRequest, nextRequest: request, statusCode: response.statusCode, MIMEType: MIMETypeString(response.MIMEType))
				willPerformHTTPRedirection(redirectionInfo: info)
			}
			
			return request
		}
	}
	
	func addRequestForURL(URL: NSURL, expectedBaseContentType: BaseContentType, includingContent: Bool, highPriority: Bool = false, completionHandler: PageInfoRequest.CompletionHandler) -> PageInfoRequest? {
		let URL = URL.absoluteURL
		if URL.host != nil {
			let infoRequest = PageInfoRequest(URL: URL, expectedBaseContentType: expectedBaseContentType, includingContent: includingContent, completionHandler: completionHandler)
			
			if highPriority || activeRequests.count < maximumActiveRequests {
				performRequest(infoRequest)
			}
			else {
				pendingRequests.append(infoRequest)
			}
			
			return infoRequest
		}
		
		return nil
	}
	
	func downgradePendingRequestsToNotIncludeContent(decider: ((PageInfoRequest) -> Bool)) {
		pendingRequests = pendingRequests.map { request in
			if request.includingContent && decider(request) {
				return request.copyNotIncludingContent()
			}
			else {
				return request
			}
		}
	}
	
	func cancelRequestForURL(URL: NSURL) {
		let URLAbsoluteString = URL.absoluteString
		
		func requestContainsURL(infoRequest: PageInfoRequest) -> Bool {
			return infoRequest.URL.absoluteString == URLAbsoluteString
		}
		
		for (index, request) in pendingRequests.enumerate() {
			if requestContainsURL(request) {
				pendingRequests.removeAtIndex(index)
				break
			}
		}
	}
	
	private func performNextPendingRequest() {
		// Perform the request next at the top of the list.
		if let infoRequest = pendingRequests.first {
			pendingRequests.removeAtIndex(0)
			performRequest(infoRequest)
		}
	}
	
	private func activeRequestDidComplete(infoRequest: PageInfoRequest, withInfo info: PageInfo) {
		infoRequest.completionHandler(info: info, infoRequest: infoRequest)
		
		// Remove from active requests
		for (index, someRequest) in activeRequests.enumerate() {
			if someRequest === infoRequest {
				activeRequests.removeAtIndex(index)
				break
			}
		}
		
		// Start the next request in queue going
		performNextPendingRequest()
	}
	
	private func performRequest(infoRequest: PageInfoRequest) {
		activeRequests.append(infoRequest)
		
		// An Alamofire serializer to perform the parsing etc on the request’s background queue.
		let serializer = GenericResponseSerializer<PageInfo> { URLRequest, response, data in
			if let response = response {
				let requestedURL = infoRequest.URL
				let MIMEType = MIMETypeString(response.MIMEType)
				let baseContentType: BaseContentType = MIMEType?.baseContentType ?? .Unknown
				
				let byteCount: Int?
				let contentInfo: PageContentInfo?
				if let data = data where infoRequest.includingContent {
					byteCount = data.length
					contentInfo = PageContentInfo(data: data, localURL: requestedURL)
				}
				else {
					byteCount = nil
					contentInfo = nil
				}
				
				let info = PageInfo(requestedURL: requestedURL, finalURL: response.URL, statusCode: response.statusCode, baseContentType: baseContentType, MIMEType: MIMEType, byteCount: byteCount, contentInfo: contentInfo)
				
				return .Success(info)
			}
			else {
				let failureReason = "Data could not be serialized. Input data was nil."
				let error = Alamofire.Error.errorWithCode(Alamofire.Error.Code.DataSerializationFailed, failureReason: failureReason)
				return .Failure(data, error)
			}
		}
		
		// Perform the request
		let requestedURL = infoRequest.URL
		infoRequest.request = requestManager
			.request(infoRequest.method, requestedURL)
			.response(responseSerializer: serializer, completionHandler: { (URLRequest, response, result) in
				if case let .Success(info) = result {
					self.activeRequestDidComplete(infoRequest, withInfo: info)
				}
		})
	}
	
	func cancelAll(clearAll: Bool = true) {
		// Cancel any requests being performed
		for infoRequest in activeRequests {
			infoRequest.request?.cancel()<commit_msg>Fix for Alamofire 3<commit_after>//
//  PageInfoRequest.swift
//  Hoverlytics
//
//  Created by <NAME> on 2/05/2015.
//  Copyright (c) 2015 <NAME>. All rights reserved.
//

import Foundation
import Alamofire
import Ono


public class PageInfoRequest {
	typealias CompletionHandler = (info: PageInfo, infoRequest: PageInfoRequest) -> Void
	
	public let URL: NSURL
	public let includingContent: Bool
	public let method: Alamofire.Method
	public let expectedBaseContentType: BaseContentType
	let completionHandler: CompletionHandler
	var request: Alamofire.Request?
	
	init(URL: NSURL, expectedBaseContentType: BaseContentType, includingContent: Bool = false, completionHandler: CompletionHandler) {
		self.URL = URL
		self.expectedBaseContentType = expectedBaseContentType
		self.includingContent = includingContent
		self.method = includingContent ? .GET : .HEAD
		self.completionHandler = completionHandler
	}
	
	func copyNotIncludingContent() -> PageInfoRequest {
		return PageInfoRequest(URL: URL, expectedBaseContentType: expectedBaseContentType, includingContent: false, completionHandler: completionHandler)
	}
}

private class PageInfoReference {
	let info: PageInfo
	
	init(info: PageInfo) {
		self.info = info
	}
}

class PageInfoRequestQueue {
	let requestManager: Alamofire.Manager
	let maximumActiveRequests = 5
	var activeRequests = [PageInfoRequest]()
	var pendingRequests = [PageInfoRequest]()
	var willPerformHTTPRedirection: ((redirectionInfo: RequestRedirectionInfo) -> Void)?
	var didFinishWithRequest: ((infoRequest: PageInfoRequest) -> Void)?
	
	init() {
		let manager = Alamofire.Manager()
		self.requestManager = manager
		
		let managerDelegate = manager.delegate
		managerDelegate.taskWillPerformHTTPRedirection = { [weak self] session, task, response, request in
			#if DEBUG
				print("taskWillPerformHTTPRedirection")
			#endif
			
			if let
				willPerformHTTPRedirection = self?.willPerformHTTPRedirection,
				originalRequest = task.originalRequest
			{
				let info = RequestRedirectionInfo(sourceRequest: originalRequest, nextRequest: request, statusCode: response.statusCode, MIMEType: MIMETypeString(response.MIMEType))
				willPerformHTTPRedirection(redirectionInfo: info)
			}
			
			return request
		}
	}
	
	func addRequestForURL(URL: NSURL, expectedBaseContentType: BaseContentType, includingContent: Bool, highPriority: Bool = false, completionHandler: PageInfoRequest.CompletionHandler) -> PageInfoRequest? {
		let URL = URL.absoluteURL
		if URL.host != nil {
			let infoRequest = PageInfoRequest(URL: URL, expectedBaseContentType: expectedBaseContentType, includingContent: includingContent, completionHandler: completionHandler)
			
			if highPriority || activeRequests.count < maximumActiveRequests {
				performRequest(infoRequest)
			}
			else {
				pendingRequests.append(infoRequest)
			}
			
			return infoRequest
		}
		
		return nil
	}
	
	func downgradePendingRequestsToNotIncludeContent(decider: ((PageInfoRequest) -> Bool)) {
		pendingRequests = pendingRequests.map { request in
			if request.includingContent && decider(request) {
				return request.copyNotIncludingContent()
			}
			else {
				return request
			}
		}
	}
	
	func cancelRequestForURL(URL: NSURL) {
		let URLAbsoluteString = URL.absoluteString
		
		func requestContainsURL(infoRequest: PageInfoRequest) -> Bool {
			return infoRequest.URL.absoluteString == URLAbsoluteString
		}
		
		for (index, request) in pendingRequests.enumerate() {
			if requestContainsURL(request) {
				pendingRequests.removeAtIndex(index)
				break
			}
		}
	}
	
	private func performNextPendingRequest() {
		// Perform the request next at the top of the list.
		if let infoRequest = pendingRequests.first {
			pendingRequests.removeAtIndex(0)
			performRequest(infoRequest)
		}
	}
	
	private func activeRequestDidComplete(infoRequest: PageInfoRequest, withInfo info: PageInfo) {
		infoRequest.completionHandler(info: info, infoRequest: infoRequest)
		
		// Remove from active requests
		for (index, someRequest) in activeRequests.enumerate() {
			if someRequest === infoRequest {
				activeRequests.removeAtIndex(index)
				break
			}
		}
		
		// Start the next request in queue going
		performNextPendingRequest()
	}
	
	private func performRequest(infoRequest: PageInfoRequest) {
		activeRequests.append(infoRequest)
		
		// An Alamofire serializer to perform the parsing etc on the request’s background queue.
		let serializer = ResponseSerializer<PageInfo, NSError> { URLRequest, response, data, error in
			guard error == nil else { return .Failure(error!) }
			
			if let response = response {
				let requestedURL = infoRequest.URL
				let MIMEType = MIMETypeString(response.MIMEType)
				let baseContentType: BaseContentType = MIMEType?.baseContentType ?? .Unknown
				
				let byteCount: Int?
				let contentInfo: PageContentInfo?
				if let data = data where infoRequest.includingContent {
					byteCount = data.length
					contentInfo = PageContentInfo(data: data, localURL: requestedURL)
				}
				else {
					byteCount = nil
					contentInfo = nil
				}
				
				let info = PageInfo(requestedURL: requestedURL, finalURL: response.URL, statusCode: response.statusCode, baseContentType: baseContentType, MIMEType: MIMEType, byteCount: byteCount, contentInfo: contentInfo)
				
				return .Success(info)
			}
			else {
				let failureReason = "Data could not be serialized. Input data was nil."
				let error = Alamofire.Error.errorWithCode(Alamofire.Error.Code.DataSerializationFailed, failureReason: failureReason)
				return .Failure(error)
			}
		}
		
		// Perform the request
		let requestedURL = infoRequest.URL
		infoRequest.request = requestManager
			.request(infoRequest.method, requestedURL)
			.response(responseSerializer: serializer, completionHandler: { response in
				if case let .Success(info) = response.result {
					self.activeRequestDidComplete(infoRequest, withInfo: info)
				}
		})
	}
	
	func cancelAll(clearAll: Bool = true) {
		// Cancel any requests being performed
		for infoRequest in activeRequests {
			infoRequest.request?.cancel()
{'fraction_non_alphanumeric': 0.08096696746419406, 'fraction_numerical': 0.002235284377845848, 'mean_word_length': 4.380846325167038, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5880149', 'n_tokens_mistral': 3964, 'n_tokens_neox': 3402, 'n_words': 871}