<commit_before>//
//  SyncEngine.swift
//  GISTFramework
//
//  Created by <NAME> on 14/06/2016.
//  Copyright © 2016 Social Cubix. All rights reserved.
//

import UIKit

/**
 SyncEngine is framework to Sync Data from Server.
 It syncs application's Colors, Constants, Font Sizes/Styles and Texts/ Strings.
 */
open class SyncEngine: NSObject {
    
    //MARK: - Properties
    
    private static var _sharedInstance: SyncEngine = SyncEngine(customData: true);
    
    /// A singleton sharedInstance for SyncEngine
    class var sharedInstance: SyncEngine {
        get {
            return self._sharedInstance;
        }
    }
    
    private var _urlToSync:URL!
    private var _headers:[String:String] = [:];
    
    private var _languageCode:String = "";
    
    private var _isCustomData = false;
    
    private lazy var syncedFile: String = {
        return "\(type(of: self))";
    }()
    
    private lazy var applicationDocumentsDirectory: URL = {
        let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
        return urls[urls.count-1]
    }();
    
    private var syncedFileUrl: URL {
        get {
            return self.applicationDocumentsDirectory.appendingPathComponent("\(self.syncedFile + self._languageCode).plist");
        }
    }
    
    //Flag if dict date is updated
    private var _hasUpdate:Bool = false;
    
    private var _dictData:NSMutableDictionary?
    internal var dictData:NSDictionary? {
        get {
            return _dictData;
        }
    } //P.E.
    
    /// Holds Last Synced Server Data
    open static var lastSyncedServerDate:String? {
        get {
            return SyncEngine.sharedInstance.lastSyncedServerDate;
        }
    } //P.E.
    
    private var lastSyncedServerDate:String? {
        get {
            return UserDefaults.standard.object(forKey: "LAST_SYNCED_SERVER_DATE" + _languageCode) as? String;
        }
        
        set {
            UserDefaults.standard.set(newValue, forKey: "LAST_SYNCED_SERVER_DATE" + _languageCode);
            UserDefaults.standard.synchronize();
        }
    } //P.E.
    
    private var lastSyncedResponseDate:Date? {
        get {
            return UserDefaults.standard.object(forKey: "LAST_SYNCED_RESPONSE_DATE" + _languageCode) as? Date;
        }
        
        set {
            UserDefaults.standard.set(newValue, forKey: "LAST_SYNCED_RESPONSE_DATE" + _languageCode);
            UserDefaults.standard.synchronize();
        }
    } //P.E.
    
    //MARK: - Constructors
    
    override init() {
        super.init();
         
        self.setupSyncedFile();
    } //P.E.
    
    //MARK: - Methods
    
    /// Static Initializer for Sync Engine.
    ///
    /// - Parameters:
    ///   - urlToSync: Http request url for Sync data
    ///   - authentication: Authentication Header if any
    public static func initialize(_ urlToSync:String, authorizationHandler: @autoclosure @escaping ()->(name:String, password:String)) {
        SyncEngine.sharedInstance.initialize(urlToSync, authorizationHandler: authorizationHandler);
    } //F.E.
    
    /// Initializer for Sync Engine.
    ///
    /// - Parameters:
    ///   - urlToSync: Http request url for Sync data
    ///   - authentication: Authentication Header if any
    private func initialize(_ urlToSync:String, authorizationHandler:(()->(name:String, password:String))?) {
        _urlToSync = URL(string: urlToSync);
        
        //Adding Language Key
        _headers["language"] = GIST_CONFIG.currentLanguageCode;
        
        //Security Headers
        if let authHeader = authorizationHandler?(), let data = "\(authHeader.name):\(authHeader.password)".data(using: .utf8) {
            
            let credential = data.base64EncodedString(options: [])
            
            _headers["Authorization"] = "Basic \(credential)";
        }
    } //F.E.
    
    private func setupSyncedFile() {
        var hasToSync:Bool = true;
        
        if let syncedFileUrlRes:String = self.filePath(for: self.syncedFile) {
            
            //Localization
            if (syncedFileUrlRes.range(of: "lproj") != nil && syncedFileUrlRes.range(of: "Base.lproj") == nil) {
                _languageCode = "-" + GIST_CONFIG.currentLanguageCode
            } else {
                _languageCode = "";
            }
             
            //If File does not exist
            if (FileManager.default.fileExists(atPath: self.syncedFileUrl.path) == false) {
                do {
                    try FileManager.default.copyItem(at: URL(fileURLWithPath: syncedFileUrlRes), to: syncedFileUrl);
                     
                    hasToSync = false; // NO Sync required, if new file created
                } catch  {
                    let nserror = error as NSError
                    NSLog("Unresolved error \(nserror), \(nserror.userInfo)")
                    abort()
                }
            }
            
        } else {
            NSLog("Unresolved error : \(self.syncedFile).plist file not found in the resource folder: For ref., You may download 'Synced PLists' folder from git repo (https://github.com/cubixlabs/GIST-Framework).");
            abort();
        }
        
        
        //Fetching Data
        _dictData = NSMutableDictionary(contentsOf: self.syncedFileUrl);//NSDictionary(contentsOfURL: self.syncedFileUrl);
        
        if (hasToSync) {
            #if DEBUG
                //Sync
                self.syncFromResource(hasToOverride: true); // Has to override if DEBUG
            #else
                //Sync
                self.syncFromResource();
            #endif
        }<commit_msg>Resolving issue of versioning<commit_after>//
//  SyncEngine.swift
//  GISTFramework
//
//  Created by <NAME> on 14/06/2016.
//  Copyright © 2016 Social Cubix. All rights reserved.
//

import UIKit

/**
 SyncEngine is framework to Sync Data from Server.
 It syncs application's Colors, Constants, Font Sizes/Styles and Texts/ Strings.
 */
open class SyncEngine: NSObject {
    
    //MARK: - Properties
    
    private static var _sharedInstance: SyncEngine = SyncEngine(customData: true);
    
    /// A singleton sharedInstance for SyncEngine
    class var sharedInstance: SyncEngine {
        get {
            return self._sharedInstance;
        }
    }
    
    private var _urlToSync:URL!
    private var _headers:[String:String] = [:];
    
    private var _languageCode:String = "";
    
    private var _isCustomData = false;
    
    private lazy var syncedFile: String = {
        return "\(type(of: self))";
    }()
    
    private lazy var applicationDocumentsDirectory: URL = {
        let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
        return urls[urls.count-1]
    }();
    
    private var _versionNumber:String?
    private var versionNumber:String {
        get {
            if (_versionNumber == nil) {
                _versionNumber = AppInfo.versionNBuildNumber;
            }
            
            return _versionNumber!;
        }
    }
    
    private var syncedFolderUrl: URL {
        get {
            return self.applicationDocumentsDirectory.appendingPathComponent("\(self.versionNumber)");
        }
    }
    
    private var syncedFileUrl: URL {
        get {
            return self.applicationDocumentsDirectory.appendingPathComponent("\(self.versionNumber)/\(self.syncedFile + self._languageCode).plist");
        }
    }
    
    //Flag if dict date is updated
    private var _hasUpdate:Bool = false;
    
    private var _dictData:NSMutableDictionary?
    internal var dictData:NSDictionary? {
        get {
            return _dictData;
        }
    } //P.E.
    
    /// Holds Last Synced Server Data
    open static var lastSyncedServerDate:String? {
        get {
            return SyncEngine.sharedInstance.lastSyncedServerDate;
        }
    } //P.E.
    
    private var lastSyncedServerDate:String? {
        get {
            return UserDefaults.standard.object(forKey: "LAST_SYNCED_SERVER_DATE" + _languageCode) as? String;
        }
        
        set {
            UserDefaults.standard.set(newValue, forKey: "LAST_SYNCED_SERVER_DATE" + _languageCode);
            UserDefaults.standard.synchronize();
        }
    } //P.E.
    
    private var lastSyncedResponseDate:Date? {
        get {
            return UserDefaults.standard.object(forKey: "LAST_SYNCED_RESPONSE_DATE" + _languageCode) as? Date;
        }
        
        set {
            UserDefaults.standard.set(newValue, forKey: "LAST_SYNCED_RESPONSE_DATE" + _languageCode);
            UserDefaults.standard.synchronize();
        }
    } //P.E.
    
    //MARK: - Constructors
    
    override init() {
        super.init();
         
        self.setupSyncedFile();
    } //P.E.
    
    //MARK: - Methods
    
    /// Static Initializer for Sync Engine.
    ///
    /// - Parameters:
    ///   - urlToSync: Http request url for Sync data
    ///   - authentication: Authentication Header if any
    public static func initialize(_ urlToSync:String, authorizationHandler: @autoclosure @escaping ()->(name:String, password:String)) {
        SyncEngine.sharedInstance.initialize(urlToSync, authorizationHandler: authorizationHandler);
    } //F.E.
    
    /// Initializer for Sync Engine.
    ///
    /// - Parameters:
    ///   - urlToSync: Http request url for Sync data
    ///   - authentication: Authentication Header if any
    private func initialize(_ urlToSync:String, authorizationHandler:(()->(name:String, password:String))?) {
        _urlToSync = URL(string: urlToSync);
        
        //Adding Language Key
        _headers["language"] = GIST_CONFIG.currentLanguageCode;
        
        //Security Headers
        if let authHeader = authorizationHandler?(), let data = "\(authHeader.name):\(authHeader.password)".data(using: .utf8) {
            
            let credential = data.base64EncodedString(options: [])
            
            _headers["Authorization"] = "Basic \(credential)";
        }
    } //F.E.
    
    private func setupSyncedFile() {
        var hasToSync:Bool = true;
        
        if let syncedFileUrlRes:String = self.filePath(for: self.syncedFile) {
            
            //Localization
            if (syncedFileUrlRes.range(of: "lproj") != nil && syncedFileUrlRes.range(of: "Base.lproj") == nil) {
                _languageCode = "-" + GIST_CONFIG.currentLanguageCode
            } else {
                _languageCode = "";
            }
             
            //If Folder does not exist
            if (FileManager.default.fileExists(atPath: self.syncedFolderUrl.path) == false) {
                do {
                    try FileManager.default.createDirectory(at: self.syncedFolderUrl, withIntermediateDirectories: true, attributes: nil)
                } catch  {
                    let error = error as NSError
                    NSLog("Unresolved error \(error), \(error.userInfo)")
                    abort()
                }
            }
            
            //If File does not exist
            if (FileManager.default.fileExists(atPath: self.syncedFileUrl.path) == false) {
                do {
                    try FileManager.default.copyItem(at: URL(fileURLWithPath: syncedFileUrlRes), to: syncedFileUrl);
                    
                    hasToSync = false; // NO Sync required, if new file created
                } catch  {
                    let error = error as NSError
                    NSLog("Unresolved error \(error), \(error.userInfo)")
                    abort()
                }
            }
            
        } else {
            NSLog("Unresolved error : \(self.syncedFile).plist file not found in the resource folder: For ref., You may download 'Synced PLists' folder from git repo (https://github.com/cubixlabs/GIST-Framework).");
            abort();
        }
        
        
        //Fetching Data
        _dictData = NSMutableDictionary(contentsOf: self.syncedFileUrl);//NSDictionary(contentsOfURL: self.syncedFileUrl);
        
        if (hasToSync) {
            #if DEBUG
                //Sync
                self.syncFromResource(hasToOverride: true); // Has to override if DEBUG
            #else
                //Sync
                self.syncFromResource();
            #endif
        }
{'fraction_non_alphanumeric': 0.10195666235446313, 'fraction_numerical': 0.00258732212160414, 'mean_word_length': 1.8259081562714188, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 9, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2973277', 'n_tokens_mistral': 3521, 'n_tokens_neox': 3393, 'n_words': 780}