<commit_before>//
//  LocationOperations.swift
//  Operations
//
//  Created by <NAME> on 27/07/2015.
//  Copyright (c) 2015 <NAME>. All rights reserved.
//

import Foundation
import CoreLocation


// MARK: Consumer Interfaces -

// MARK: UserLocationOperation

/**
Access the device's current location. It will ask for
permission if required.

- parameter accuracy: the location accuracy which defaults to 3km.
- parameter completion: a closure CLLocation -> Void.
*/
public typealias UserLocationOperation = _UserLocationOperation<CLLocationManager>

// MARK: ReverseGeocodeOperation

/**
Reverse geocode a given CLLocation.

- parameter location: the location to reverse lookup.
- parameter completion: a completion block of CompletionBlockType
*/
public typealias ReverseGeocodeOperation = _ReverseGeocodeOperation<CLGeocoder>

// MARK: ReverseGeocodeUserLocationOperation

/**
Reverse geocode the device's current location.

- parameter accuracy: the location accuracy.
- parameter completion: a completion block of CompletionBlockType
*/
public typealias ReverseGeocodeUserLocationOperation = _ReverseGeocodeUserLocationOperation<CLGeocoder, CLLocationManager>

@available(*, unavailable, renamed="UserLocationOperation")
public typealias LocationOperation = UserLocationOperation

// MARK: - Implementation Details -

public protocol LocationManagerType: LocationCapabilityRegistrarType {
    func opr_setDesiredAccuracy(desiredAccuracy: CLLocationAccuracy)
    func opr_startUpdatingLocation()
    func opr_stopLocationUpdates()
}

extension CLLocationManager: LocationManagerType {

    public func opr_setDesiredAccuracy(accuracy: CLLocationAccuracy) {
        desiredAccuracy = accuracy
    }

    public func opr_startUpdatingLocation() {
        startUpdatingLocation()
    }

    public func opr_stopLocationUpdates() {
        stopUpdatingLocation()
    }
}

public enum LocationOperationError: ErrorType, Equatable {
    case LocationManagerDidFail(NSError)
    case GeocoderError(NSError)
}

public class _UserLocationOperation<Manager: LocationManagerType>: Operation, CLLocationManagerDelegate {
    public typealias CompletionBlockType = CLLocation -> Void

    private let manager: Manager
    private let accuracy: CLLocationAccuracy
    private let completion: CompletionBlockType

    /// Access the user's location once it has updated.
    public private(set) var location: CLLocation? = .None

    /**
    Initialize an operation which will use a custom location manager to
    determine the user's current location to the desired accuracy. It will ask for
    permission if required.

    Framework consumers should use: UserLocationOperation

    - parameter accuracy: the location accuracy which defaults to 3km.
    - parameter completion: a closure CLLocation -> Void.
    */
    public convenience init(accuracy: CLLocationAccuracy = kCLLocationAccuracyThreeKilometers, completion: CompletionBlockType = { _ in }) {
        self.init(manager: Manager(), accuracy: accuracy, completion: completion)
    }

    /**
    Initialize an operation which will use a custom location manager to
    determine the user's current location to the desired accuracy. It will ask for
    permission if required.

     - parameter manager: instance of a type which implements LocationManagerType.
     - parameter accuracy: the location accuracy which defaults to 3km.
     - parameter completion: a closure CLLocation -> Void.
    */
    public init(manager: Manager, accuracy: CLLocationAccuracy, completion: CompletionBlockType) {
        self.manager = manager
        self.accuracy = accuracy
        self.completion = completion
        super.init()
        name = "User Location"
        addCondition(AuthorizedFor(_LocationCapability(.WhenInUse, registrar: manager)))
        addCondition(MutuallyExclusive<CLLocationManager>())
    }

    /// Starts updating the location
    public override func execute() {
        manager.opr_setDesiredAccuracy(accuracy)
        manager.opr_setDelegate(self)
        manager.opr_startUpdatingLocation()
    }

    /// Stops updating the location before cancelling the operation
    public override func cancel() {
        dispatch_async(Queue.Main.queue) {
            self.stopLocationUpdates()
            super.cancel()
        }
    }

    internal func stopLocationUpdates() {
        manager.opr_stopLocationUpdates()
    }

    @objc public func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        if let location = locations.last where location.horizontalAccuracy <= accuracy {
            dispatch_async(Queue.Main.queue) {
                self.stopLocationUpdates()
                self.location = location
                self.completion(location)
                self.finish()
            }
        }
    }

    @objc public func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
        dispatch_async(Queue.Main.queue) {
            self.stopLocationUpdates()
            self.finish(LocationOperationError.LocationManagerDidFail(error))
        }
    }
}

public protocol ReverseGeocoderType {
    init()
    func opr_cancel()
    func opr_reverseGeocodeLocation(location: CLLocation, completion: ([CLPlacemark], NSError?) -> Void)
}

extension CLGeocoder: ReverseGeocoderType {<commit_msg>[OPR-108]: Adds log info for when the device locations are updated.<commit_after>//
//  LocationOperations.swift
//  Operations
//
//  Created by <NAME> on 27/07/2015.
//  Copyright (c) 2015 <NAME>. All rights reserved.
//

import Foundation
import CoreLocation


// MARK: Consumer Interfaces -

// MARK: UserLocationOperation

/**
Access the device's current location. It will ask for
permission if required.

- parameter accuracy: the location accuracy which defaults to 3km.
- parameter completion: a closure CLLocation -> Void.
*/
public typealias UserLocationOperation = _UserLocationOperation<CLLocationManager>

// MARK: ReverseGeocodeOperation

/**
Reverse geocode a given CLLocation.

- parameter location: the location to reverse lookup.
- parameter completion: a completion block of CompletionBlockType
*/
public typealias ReverseGeocodeOperation = _ReverseGeocodeOperation<CLGeocoder>

// MARK: ReverseGeocodeUserLocationOperation

/**
Reverse geocode the device's current location.

- parameter accuracy: the location accuracy.
- parameter completion: a completion block of CompletionBlockType
*/
public typealias ReverseGeocodeUserLocationOperation = _ReverseGeocodeUserLocationOperation<CLGeocoder, CLLocationManager>

@available(*, unavailable, renamed="UserLocationOperation")
public typealias LocationOperation = UserLocationOperation

// MARK: - Implementation Details -

public protocol LocationManagerType: LocationCapabilityRegistrarType {
    func opr_setDesiredAccuracy(desiredAccuracy: CLLocationAccuracy)
    func opr_startUpdatingLocation()
    func opr_stopLocationUpdates()
}

extension CLLocationManager: LocationManagerType {

    public func opr_setDesiredAccuracy(accuracy: CLLocationAccuracy) {
        desiredAccuracy = accuracy
    }

    public func opr_startUpdatingLocation() {
        startUpdatingLocation()
    }

    public func opr_stopLocationUpdates() {
        stopUpdatingLocation()
    }
}

public enum LocationOperationError: ErrorType, Equatable {
    case LocationManagerDidFail(NSError)
    case GeocoderError(NSError)
}

public class _UserLocationOperation<Manager: LocationManagerType>: Operation, CLLocationManagerDelegate {
    public typealias CompletionBlockType = CLLocation -> Void

    private let manager: Manager
    private let accuracy: CLLocationAccuracy
    private let completion: CompletionBlockType

    /// Access the user's location once it has updated.
    public private(set) var location: CLLocation? = .None

    /**
    Initialize an operation which will use a custom location manager to
    determine the user's current location to the desired accuracy. It will ask for
    permission if required.

    Framework consumers should use: UserLocationOperation

    - parameter accuracy: the location accuracy which defaults to 3km.
    - parameter completion: a closure CLLocation -> Void.
    */
    public convenience init(accuracy: CLLocationAccuracy = kCLLocationAccuracyThreeKilometers, completion: CompletionBlockType = { _ in }) {
        self.init(manager: Manager(), accuracy: accuracy, completion: completion)
    }

    /**
    Initialize an operation which will use a custom location manager to
    determine the user's current location to the desired accuracy. It will ask for
    permission if required.

     - parameter manager: instance of a type which implements LocationManagerType.
     - parameter accuracy: the location accuracy which defaults to 3km.
     - parameter completion: a closure CLLocation -> Void.
    */
    public init(manager: Manager, accuracy: CLLocationAccuracy, completion: CompletionBlockType) {
        self.manager = manager
        self.accuracy = accuracy
        self.completion = completion
        super.init()
        name = "User Location"
        addCondition(AuthorizedFor(_LocationCapability(.WhenInUse, registrar: manager)))
        addCondition(MutuallyExclusive<CLLocationManager>())
    }

    /// Starts updating the location
    public override func execute() {
        manager.opr_setDesiredAccuracy(accuracy)
        manager.opr_setDelegate(self)
        manager.opr_startUpdatingLocation()
    }

    /// Stops updating the location before cancelling the operation
    public override func cancel() {
        dispatch_async(Queue.Main.queue) {
            self.stopLocationUpdates()
            super.cancel()
        }
    }

    internal func stopLocationUpdates() {
        manager.opr_stopLocationUpdates()
    }

    @objc public func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        if let location = locations.last {
            log.info("\(operationName) updated last location: \(location)")
            if location.horizontalAccuracy <= accuracy {
                dispatch_async(Queue.Main.queue) {
                    self.stopLocationUpdates()
                    self.location = location
                    self.completion(location)
                    self.finish()
                }
            }
        }
    }

    @objc public func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
        dispatch_async(Queue.Main.queue) {
            self.stopLocationUpdates()
            self.finish(LocationOperationError.LocationManagerDidFail(error))
        }
    }
}

public protocol ReverseGeocoderType {
    init()
    func opr_cancel()
    func opr_reverseGeocodeLocation(location: CLLocation, completion: ([CLPlacemark], NSError?) -> Void)
}

extension CLGeocoder: ReverseGeocoderType {
{'fraction_non_alphanumeric': 0.07209280913359728, 'fraction_numerical': 0.003038394254672682, 'mean_word_length': 3.490285241835469, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 27, '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': '1880652', 'n_tokens_mistral': 2861, 'n_tokens_neox': 2745, 'n_words': 815}