<commit_before>//
//  GameViewController.swift
//  BreakBaloon
//
//  Created by Emil on 19/06/2016.
//  Copyright (c) 2016 Snowy_1803. All rights reserved.
//

import AVFoundation
import CommonCrypto
import GameKit
import SpriteKit
import UIKit
import WatchConnectivity

class GameViewController: UIViewController, WCSessionDelegate {
    static let defaultAudioVolume: Float = 1.0
    static let defaultMusicVolume: Float = 0.8
    
    var skView: SKView?
    
    var backgroundMusicPlayer: AVAudioPlayer!
    var audioPlayer: AVAudioPlayer!
    var audioVolume: Float = GameViewController.defaultAudioVolume
    var currentGame: AbstractGameScene?
    var currentMusicFileName = "Race.m4a"
    var currentMusicInt: Int {
        get {
            for i in 0..<GameViewController.getMusicURLs().count {
                if GameViewController.getMusicURLs()[i].absoluteString.hasSuffix(currentMusicFileName) {
                    return i
                }
            }
            return -1
        }
        set(value) {
            let cmps = GameViewController.getMusicURLs()[value].absoluteString.components(separatedBy: "/")
            currentMusicFileName = cmps[cmps.count - 1]
        }
    }

    var currentTheme: AbstractTheme = AbstractThemeUtils.themeList.first!
    var currentThemeInt: Int {
        get {
            AbstractThemeUtils.themeList.firstIndex(where: { theme in
                theme.id == currentTheme.id
            })!
        }
        set(value) {
            currentTheme = AbstractThemeUtils.themeList[value]
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // INIT RANDOM BALOONS LEVELS
        for level in RandGameLevel.levels {
            level.load()
        }
        
        print("Path:", FileSaveHelper(fileName: "", fileExtension: .none).fullyQualifiedPath)
        loadMusicAndStartScene()
        
        _ = UIApplication.shared.appDelegate.triggerDeepLinkIfPresent()

        if WCSession.isSupported() {
            print("Activating Watch Connectivity")
            WCSession.default.delegate = self
            WCSession.default.activate()
        }
    }
    
    func loadMusicAndStartScene() {
        if GameViewController.getMusicURLs().isEmpty {
            do {
                try Downloadable(type: .m4aMusic, name: "Race", author: "Snowy", id: "Race.m4a", version: "x", description: "", levelRequirement: 0).download(nil, wait: true)
            } catch {
                print("Couldn't download content")
                fatalError()
            }
        }
        let data = UserDefaults.standard
        if data.string(forKey: "currentMusic") == nil {
            data.set("Race.m4a", forKey: "currentMusic")
        }
        if data.string(forKey: "currentTheme") == nil {
            data.set("/Default", forKey: "currentTheme")
        }
        if data.object(forKey: "audio-true") == nil {
            data.set(GameViewController.defaultMusicVolume, forKey: "audio-true")
        }
        if data.object(forKey: "audio-false") == nil {
            data.set(GameViewController.defaultAudioVolume, forKey: "audio-false")
        }
        if UserDefaults.standard.object(forKey: "elementalcube.sessid") != nil {
            ECLoginManager.shared.logIn(sessid: UserDefaults.standard.string(forKey: "elementalcube.sessid")!, delegate: nil)
        }
        currentTheme = AbstractThemeUtils.withID(UserDefaults.standard.string(forKey: "currentTheme")!)!
        let welcome: URL = Bundle.main.url(forResource: "Welcome", withExtension: "wav")!
        
        print(UserDefaults.standard.dictionaryRepresentation())
        do {
            print(try FileManager.default.contentsOfDirectory(atPath: FileSaveHelper(fileName: "", fileExtension: .none).fullyQualifiedPath))
        } catch let error as NSError {
            print("Couldn't view documents. Error: \(error.localizedDescription)")
        }
        
        do {
            audioPlayer = try AVAudioPlayer(contentsOf: welcome)
        } catch {
            print(error)
        }
        audioVolume = data.float(forKey: "audio-false")
        audioPlayer.volume = audioVolume
        audioPlayer.prepareToPlay()
        audioPlayer.play()
        reloadBackgroundMusic()
        
        // (enforced by storyboard)
        // swiftlint:disable:next force_cast
        skView = (view as! SKView)
        #if DEBUG
            skView!.showsFPS = true
            skView!.showsNodeCount = true
        #endif
        skView!.ignoresSiblingOrder = true
        skView!.preferredFramesPerSecond = 120
        
        let scene: SKScene = StartScene(size: skView!.bounds.size)
        scene.scaleMode = .aspectFill
        skView!.presentScene(scene)
        
        // Game Center setup
        GKLocalPlayer.local.authenticateHandler = { [unowned self] viewController, error in
            if let viewController = viewController {
                present(viewController, animated: true)
            } else if let error = error {
                print("Game Center auth failed")
                print(error)
            } else {
                print("Game Center authenticated!")
            }
        }
    }
    
    func reloadBackgroundMusic() {
        currentMusicFileName = UserDefaults.standard.string(forKey: "currentMusic")!
        let bgMusicURL: URL = GameViewController.getMusicURL(currentMusicFileName)!
        do {
            try backgroundMusicPlayer = AVAudioPlayer(contentsOf: bgMusicURL)
        } catch let error as NSError {
            print("ERROR WHILE LOADING AUDIO FILE. REMOVING THE CORRUPTED AUDIO FILE. Error: \(error.localizedDescription)")
            do {
                try FileManager.default.removeItem(at: bgMusicURL)
            } catch let error as NSError {
                print("Couldn't delete the corrupted file. Error: \(error.localizedDescription)")
            }
            UserDefaults.standard.set("Race.m4a", forKey: "currentMusic")
        }
        backgroundMusicPlayer.numberOfLoops = -1
        backgroundMusicPlayer.volume = UserDefaults.standard.float(forKey: "audio-true")
        backgroundMusicPlayer.prepareToPlay()
        backgroundMusicPlayer.play()
    }
    
    class func getMusicURLs() -> [URL] {
        var urls: [URL] = []
        let path = FileSaveHelper(fileName: "", fileExtension: .none).fullyQualifiedPath
        let enumerator = FileManager.default.enumerator(atPath: path)
        
        while let element = enumerator?.nextObject() as? String {
            if element.hasSuffix(".m4a") {
                urls.append(URL(fileURLWithPath: "\(path)/\(element)"))
            }
        }<commit_msg>Fix possible crash on first launch if music failed to download<commit_after>//
//  GameViewController.swift
//  BreakBaloon
//
//  Created by Emil on 19/06/2016.
//  Copyright (c) 2016 Snowy_1803. All rights reserved.
//

import AVFoundation
import CommonCrypto
import GameKit
import SpriteKit
import UIKit
import WatchConnectivity

class GameViewController: UIViewController, WCSessionDelegate {
    static let defaultAudioVolume: Float = 1.0
    static let defaultMusicVolume: Float = 0.8
    
    var skView: SKView?
    
    var backgroundMusicPlayer: AVAudioPlayer!
    var audioPlayer: AVAudioPlayer!
    var audioVolume: Float = GameViewController.defaultAudioVolume
    var currentGame: AbstractGameScene?
    var currentMusicFileName = "Race.m4a"
    var currentMusicInt: Int {
        get {
            for i in 0..<GameViewController.getMusicURLs().count {
                if GameViewController.getMusicURLs()[i].absoluteString.hasSuffix(currentMusicFileName) {
                    return i
                }
            }
            return -1
        }
        set(value) {
            let cmps = GameViewController.getMusicURLs()[value].absoluteString.components(separatedBy: "/")
            currentMusicFileName = cmps[cmps.count - 1]
        }
    }

    var currentTheme: AbstractTheme = AbstractThemeUtils.themeList.first!
    var currentThemeInt: Int {
        get {
            AbstractThemeUtils.themeList.firstIndex(where: { theme in
                theme.id == currentTheme.id
            })!
        }
        set(value) {
            currentTheme = AbstractThemeUtils.themeList[value]
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // INIT RANDOM BALOONS LEVELS
        for level in RandGameLevel.levels {
            level.load()
        }
        
        print("Path:", FileSaveHelper(fileName: "", fileExtension: .none).fullyQualifiedPath)
        loadMusicAndStartScene()
        
        _ = UIApplication.shared.appDelegate.triggerDeepLinkIfPresent()

        if WCSession.isSupported() {
            print("Activating Watch Connectivity")
            WCSession.default.delegate = self
            WCSession.default.activate()
        }
    }
    
    func loadMusicAndStartScene() {
        if GameViewController.getMusicURLs().isEmpty {
            do {
                try Downloadable(type: .m4aMusic, name: "Race", author: "Snowy", id: "Race.m4a", version: "x", description: "", levelRequirement: 0).download(nil, wait: true)
            } catch {
                print("Couldn't download Race.m4a :(")
                print(error)
            }
        }
        let data = UserDefaults.standard
        if data.string(forKey: "currentMusic") == nil {
            data.set("Race.m4a", forKey: "currentMusic")
        }
        if data.string(forKey: "currentTheme") == nil {
            data.set("/Default", forKey: "currentTheme")
        }
        if data.object(forKey: "audio-true") == nil {
            data.set(GameViewController.defaultMusicVolume, forKey: "audio-true")
        }
        if data.object(forKey: "audio-false") == nil {
            data.set(GameViewController.defaultAudioVolume, forKey: "audio-false")
        }
        if UserDefaults.standard.object(forKey: "elementalcube.sessid") != nil {
            ECLoginManager.shared.logIn(sessid: UserDefaults.standard.string(forKey: "elementalcube.sessid")!, delegate: nil)
        }
        currentTheme = AbstractThemeUtils.withID(UserDefaults.standard.string(forKey: "currentTheme")!)!
        let welcome: URL = Bundle.main.url(forResource: "Welcome", withExtension: "wav")!
        
        print(UserDefaults.standard.dictionaryRepresentation())
        do {
            print(try FileManager.default.contentsOfDirectory(atPath: FileSaveHelper(fileName: "", fileExtension: .none).fullyQualifiedPath))
        } catch let error as NSError {
            print("Couldn't view documents. Error: \(error.localizedDescription)")
        }
        
        do {
            audioPlayer = try AVAudioPlayer(contentsOf: welcome)
        } catch {
            print(error)
        }
        audioVolume = data.float(forKey: "audio-false")
        audioPlayer.volume = audioVolume
        audioPlayer.prepareToPlay()
        audioPlayer.play()
        reloadBackgroundMusic()
        
        // (enforced by storyboard)
        // swiftlint:disable:next force_cast
        skView = (view as! SKView)
        #if DEBUG
            skView!.showsFPS = true
            skView!.showsNodeCount = true
        #endif
        skView!.ignoresSiblingOrder = true
        skView!.preferredFramesPerSecond = 120
        
        let scene: SKScene = StartScene(size: skView!.bounds.size)
        scene.scaleMode = .aspectFill
        skView!.presentScene(scene)
        
        // Game Center setup
        GKLocalPlayer.local.authenticateHandler = { [unowned self] viewController, error in
            if let viewController = viewController {
                present(viewController, animated: true)
            } else if let error = error {
                print("Game Center auth failed")
                print(error)
            } else {
                print("Game Center authenticated!")
            }
        }
    }
    
    func reloadBackgroundMusic() {
        currentMusicFileName = UserDefaults.standard.string(forKey: "currentMusic") ?? "Race.m4a"
        guard let bgMusicURL = GameViewController.getMusicURL(currentMusicFileName) else {
            print("Could not find the background music")
            return // fail
        }
        do {
            try backgroundMusicPlayer = AVAudioPlayer(contentsOf: bgMusicURL)
            backgroundMusicPlayer.numberOfLoops = -1
            backgroundMusicPlayer.volume = UserDefaults.standard.float(forKey: "audio-true")
            backgroundMusicPlayer.prepareToPlay()
            backgroundMusicPlayer.play()
        } catch {
            print("ERROR WHILE LOADING AUDIO FILE. REMOVING THE CORRUPTED AUDIO FILE")
            print(error)
            do {
                try FileManager.default.removeItem(at: bgMusicURL)
            } catch {
                print("Couldn't delete the corrupted file")
                print(error)
            }
            UserDefaults.standard.set("Race.m4a", forKey: "currentMusic")
        }
    }
    
    class func getMusicURLs() -> [URL] {
        var urls: [URL] = []
        let path = FileSaveHelper(fileName: "", fileExtension: .none).fullyQualifiedPath
        let enumerator = FileManager.default.enumerator(atPath: path)
        
        while let element = enumerator?.nextObject() as? String {
            if element.hasSuffix(".m4a") {
                urls.append(URL(fileURLWithPath: "\(path)/\(element)"))
            }
        }
{'fraction_non_alphanumeric': 0.09818181818181818, 'fraction_numerical': 0.005194805194805195, 'mean_word_length': 2.115117891816921, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 7, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1768719', 'n_tokens_mistral': 3758, 'n_tokens_neox': 3592, 'n_words': 756}