<commit_before>//
//  PhoneIdFramework.swift
//  PhoneIdTestApp
//
//  Created by <NAME> on 30/08/14.
//  Copyright (c) 2014 <NAME>. All rights reserved.
//

import UIKit
import libPhoneNumber_iOS


typealias RequestCompletion = (error:NSError?) -> Void
typealias UserInfoRequestCompletion = (userInfo:UserInfo?,error:NSError?) -> Void
public typealias TokenRequestCompletion = (token:TokenInfo?,error:NSError?) -> Void

public typealias PhoneIdAuthenticationSucceed = (token:TokenInfo) -> Void
public typealias PhoneIdWorkflowErrorHappened = (error:NSError) -> Void
public typealias PhoneIdAuthenticationCancelled = () -> Void

public class PhoneIdService: NSObject {
    
    public class var sharedInstance: PhoneIdService {
        struct Static { static let instance: PhoneIdService = PhoneIdService() }
        return Static.instance
    }
    
    public var componentFactory:ComponentFactory = DefaultComponentFactory()
    public var phoneIdAuthenticationSucceed: PhoneIdAuthenticationSucceed?
    public var phoneIdAuthenticationCancelled: PhoneIdAuthenticationCancelled?
    public var phoneIdAuthenticationRefreshed: PhoneIdAuthenticationSucceed?
    public var phoneIdWorkflowErrorHappened: PhoneIdWorkflowErrorHappened?
    public var phoneIdDidLogout:(() -> Void)?
    
    public var isLoggedIn: Bool {
        get {
            return token != nil ? self.token!.isValid() : false
        }
    }
    
    public var token: TokenInfo? {
        get {
            return TokenInfo.loadFromKeyChain()
        }
    }
        
    public internal(set) var appName: String?
    public internal(set) var clientId: String?
    public internal(set) var autorefreshToken: Bool = true
    
    internal var urlSession: NSURLSession!;
    internal var refreshMonitor: PhoneIdRefreshMonitor!;
    
    private var apiBaseURL:NSURL!
    private var phoneUtil: NBPhoneNumberUtil {return NBPhoneNumberUtil.sharedInstance()}
    
    override init(){
        super.init()
        urlSession = NSURLSession.sharedSession()
        apiBaseURL = Constants.baseURL
        
    }
    
    convenience init(baseURL:NSURL) {
        self.init()
        apiBaseURL = baseURL
    }
    
    public func configureClient(id: String, autorefresh:Bool = true) {
        self.autorefreshToken = autorefresh
        
        self.clientId = id;
        
        if(autorefresh){
            refreshMonitor = PhoneIdRefreshMonitor(phoneIdService:self)
            if(self.isLoggedIn){
                refreshMonitor.start()
            }
        }
        
        self.loadClients(id) { (error) -> Void in}
    }
    
    
    public func logout() {
        
        self.refreshMonitor?.stop()
        self.token?.removeFromKeychain();
        
        NSNotificationCenter
            .defaultCenter()
            .postNotificationName(Notifications.DidLogout, object: nil, userInfo:nil)
        phoneIdDidLogout?()
    }
    
    // MARK: - API
    func requestAuthenticationCode(info: NumberInfo, completion:RequestCompletion) {
        
        let validation = info.isValid()
        guard validation.result else{
            completion(error:validation.error);
            self.notifyClientCodeAboutError(validation.error)
            return
        }
        
        let number = info.e164Format()!
        
        self.get(Endpoints.RequestCode.endpoint(), params:["number":number,"client_id":clientId!], completion: { response in
            
            var error:NSError?=nil
            if let responseError = response.error {
                NSLog("Failed to request PhoneId authentication code due to \(responseError))")
                error = PhoneIdServiceError.requestFailedError("error.failed.request.auth.code", reasonKey:responseError.localizedDescription)
                
            }else if let info = response.responseJSON as? NSDictionary{
                let responseCode = info["result"] as? Int
                if(responseCode==0){
                    NSLog("Request authentication code success:\(responseCode), info: \(info)")
                }else{
                    let message = "No request success marker in response \(response.responseJSON)"
                    NSLog(message)
                    error = PhoneIdServiceError.requestFailedError("error.unexpected.response", reasonKey: "error.reason.auth.unexpected.response")
                }
            }
            
            completion(error:error)
            self.notifyClientCodeAboutError(error)
        })
        
    }
    
    func verifyAuthentication(verifyCode: String, info: NumberInfo, completion:TokenRequestCompletion) {
        
        let validation = info.isValid()
        guard validation.result else{
            completion(token: nil, error:validation.error);
            self.notifyClientCodeAboutError(validation.error)
            return
        }
        
        if let number: String = info.e164Format(){
            
            var params: Dictionary<String, AnyObject> = [:]
            params["grant_type"]="authorization_code"
            params["client_id"]=clientId!
            params["code"]=verifyCode + "/" + number
            
            print("request params: \(params)")
            
            self.post(Endpoints.RequestToken.endpoint(), params:params) { response in
                
                var error:NSError?
                var token:TokenInfo?
                
                if let responseError = response.error {
                    NSLog("Failed to verify code %@", responseError)
                    error = PhoneIdServiceError.requestFailedError("error.failed.request.code.verification",reasonKey: responseError.localizedDescription)
                    self.sendNotificationVerificationFail(error!)
                    
                    
                }else if let receivedToken = TokenInfo.parse(response){
                    self.doOnAuthenticationSucceed(receivedToken)
                    token = receivedToken
                }else{
                    error = PhoneIdServiceError.requestFailedError("error.unexpected.response", reasonKey: "error.reason.response.does.not.contrain.valid.token.info")
                    self.sendNotificationVerificationFail(error!)
                }
                
                completion(token:token, error:error)
                self.notifyClientCodeAboutError(error)
            }
        }
    }
    
    func doOnAuthenticationSucceed(token:TokenInfo){
        token.saveToKeychain()
        
        if(self.autorefreshToken){
            self.refreshMonitor.start()
        }
        
        self.sendNotificationVerificationSuccess()
    }
    
    func loadUserInfo(completion:UserInfoRequestCompletion) {
        
        let endpoint: String = Endpoints.RequestMe.endpoint()
        self.get(endpoint, params: nil) { response in<commit_msg>Minor fix<commit_after>//
//  PhoneIdFramework.swift
//  PhoneIdTestApp
//
//  Created by <NAME> on 30/08/14.
//  Copyright (c) 2014 <NAME>. All rights reserved.
//

import UIKit
import libPhoneNumber_iOS


typealias RequestCompletion = (error:NSError?) -> Void
typealias UserInfoRequestCompletion = (userInfo:UserInfo?,error:NSError?) -> Void
public typealias TokenRequestCompletion = (token:TokenInfo?,error:NSError?) -> Void

public typealias PhoneIdAuthenticationSucceed = (token:TokenInfo) -> Void
public typealias PhoneIdWorkflowErrorHappened = (error:NSError) -> Void
public typealias PhoneIdAuthenticationCancelled = () -> Void

public class PhoneIdService: NSObject {
    
    public class var sharedInstance: PhoneIdService {
        struct Static { static let instance: PhoneIdService = PhoneIdService() }
        return Static.instance
    }
    
    public var componentFactory:ComponentFactory = DefaultComponentFactory()
    public var phoneIdAuthenticationSucceed: PhoneIdAuthenticationSucceed?
    public var phoneIdAuthenticationCancelled: PhoneIdAuthenticationCancelled?
    public var phoneIdAuthenticationRefreshed: PhoneIdAuthenticationSucceed?
    public var phoneIdWorkflowErrorHappened: PhoneIdWorkflowErrorHappened?
    public var phoneIdDidLogout:(() -> Void)?
    
    public var isLoggedIn: Bool {
        get {
            return token != nil ? self.token!.isValid() : false
        }
    }
    
    public var token: TokenInfo? {
        get {
            return TokenInfo.loadFromKeyChain()
        }
    }
        
    public internal(set) var appName: String?
    public internal(set) var clientId: String?
    public internal(set) var autorefreshToken: Bool = true
    
    internal var urlSession: NSURLSession!;
    internal var refreshMonitor: PhoneIdRefreshMonitor!;
    
    private var apiBaseURL:NSURL!
    private var phoneUtil: NBPhoneNumberUtil {return NBPhoneNumberUtil.sharedInstance()}
    
    override init(){
        super.init()
        urlSession = NSURLSession.sharedSession()
        apiBaseURL = Constants.baseURL
        
    }
    
    convenience init(baseURL:NSURL) {
        self.init()
        apiBaseURL = baseURL
    }
    
    public func configureClient(id: String, autorefresh:Bool = true) {
        self.autorefreshToken = autorefresh
        
        self.clientId = id;
        
        if(autorefresh){
            refreshMonitor = PhoneIdRefreshMonitor(phoneIdService:self)
            if(self.isLoggedIn){
                refreshMonitor.start()
            }
        }
        
        self.loadClients(id) { (error) -> Void in}
    }
    
    
    public func logout() {
        
        self.refreshMonitor?.stop()
        self.token?.removeFromKeychain();
        
        NSNotificationCenter
            .defaultCenter()
            .postNotificationName(Notifications.DidLogout, object: nil, userInfo:nil)
        phoneIdDidLogout?()
    }
    
    // MARK: - API
    func requestAuthenticationCode(info: NumberInfo, completion:RequestCompletion) {
        
        let validation = info.isValid()
        guard validation.result else{
            completion(error:validation.error);
            self.notifyClientCodeAboutError(validation.error)
            return
        }
        
        let number = info.e164Format()!
        
        self.get(Endpoints.RequestCode.endpoint(), params:["number":number,"client_id":clientId!], completion: { response in
            
            var error:NSError?=nil
            if let responseError = response.error {
                NSLog("Failed to request PhoneId authentication code due to \(responseError))")
                error = PhoneIdServiceError.requestFailedError("error.failed.request.auth.code", reasonKey:responseError.localizedDescription)
                
            }else if let info = response.responseJSON as? NSDictionary{
                let responseCode = info["result"] as? Int
                if(responseCode==0){
                    NSLog("Request authentication code success:\(responseCode), info: \(info)")
                }else{
                    let message = "No request success marker in response \(response.responseJSON)"
                    NSLog(message)
                    error = PhoneIdServiceError.requestFailedError("error.unexpected.response", reasonKey: "error.reason.auth.unexpected.response")
                }
            }
            
            completion(error:error)
            self.notifyClientCodeAboutError(error)
        })
        
    }
    
    func verifyAuthentication(verifyCode: String, info: NumberInfo, completion:TokenRequestCompletion) {
        
        let validation = info.isValid()
        guard validation.result else{
            completion(token: nil, error:validation.error);
            self.notifyClientCodeAboutError(validation.error)
            return
        }
        
        if let number: String = info.e164Format(){
            
            var params: Dictionary<String, AnyObject> = [:]
            params["grant_type"]="authorization_code"
            params["client_id"]=clientId!
            params["code"]=verifyCode + "/" + number
            
            print("request params: \(params)")
            
            self.post(Endpoints.RequestToken.endpoint(), params:params) { response in
                
                var error:NSError?
                var token:TokenInfo?
                
                if let responseError = response.error {
                    NSLog("Failed to verify code %@", responseError)
                    error = PhoneIdServiceError.requestFailedError("error.failed.request.code.verification",reasonKey: responseError.localizedDescription)
                    self.sendNotificationVerificationFail(error!)
                    
                    
                }else if let receivedToken = TokenInfo.parse(response){
                    self.doOnAuthenticationSucceed(receivedToken)
                    token = receivedToken
                }else{
                    error = PhoneIdServiceError.requestFailedError("error.unexpected.response", reasonKey: "error.reason.response.does.not.contrain.valid.token.info")
                    self.sendNotificationVerificationFail(error!)
                }
                
                completion(token:token, error:error)
                self.notifyClientCodeAboutError(error)
            }
        }
    }
    
    func doOnAuthenticationSucceed(token:TokenInfo){
        token.saveToKeychain()
        
        if(self.autorefreshToken){
            self.refreshMonitor?.start()
        }
        
        self.sendNotificationVerificationSuccess()
    }
    
    func loadUserInfo(completion:UserInfoRequestCompletion) {
        
        let endpoint: String = Endpoints.RequestMe.endpoint()
        self.get(endpoint, params: nil) { response in
{'fraction_non_alphanumeric': 0.08543080178011235, 'fraction_numerical': 0.0024804844240169256, 'mean_word_length': 2.123974475843209, 'pattern_counts': {'":': 4, '<': 9, '<?xml version=': 0, '>': 25, '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': '2121581', 'n_tokens_mistral': 3535, 'n_tokens_neox': 3394, 'n_words': 692}