//
//  Preferences.swift
//  TagTunes
//
//  Created by Kim Wittenburg on 29.08.15.
//  Copyright © 2015 Kim Wittenburg. All rights reserved.
//

import Cocoa

/// A custom interface for the `NSUserDefaults`. It is recommended to use this
/// class insted of accessing the user defaults directly to prevent errors due
/// to misspelled strings.
///
/// All properties in this class are KCO compliant.
@objc public class Preferences: NSObject {

    // MARK: Types
    
    private struct UserDefaultsConstants {
    
        static let saveArtworkKey = "Save Artwork"
        
        static let keepSearchResultsKey = "Keep Search Results"
        
        static let removeSavedAlbumsKey = "Remove Saved Albums"
        
        static let artworkTargetKey = "Artwork Target"
        
        static let useCensoredNamesKey = "Use Censored Names"
        
        static let tagSavingBehaviorsKey = "Tag Saving Behaviors"
    }
    
    public enum TagSavingBehavior: String {
        
        /// Sets the tag's value to the value returned from the Search API.
        case Save = "save"
        
        /// Sets the tag's value to an empty string.
        case Clear = "clear"
        
        /// Does not alter the tag's value.
        case Ignore = "ignore"
        
    }
        
    // MARK: Initialization
    
    public static var sharedPreferences = Preferences()
    
    /// Initializes the default preferences. This method must be called the very
    /// first time the application is launched. It is perfectly valid to call
    /// this method every time the application launches. Existing values are not
    /// overridden.
    public func initializeDefaultValues() {
        NSUserDefaults.standardUserDefaults().registerDefaults([
            UserDefaultsConstants.saveArtworkKey: false,
            UserDefaultsConstants.keepSearchResultsKey: false,
            UserDefaultsConstants.removeSavedAlbumsKey: false,
            UserDefaultsConstants.useCensoredNamesKey: false
            ])
        if NSUserDefaults.standardUserDefaults().dictionaryForKey(UserDefaultsConstants.tagSavingBehaviorsKey) == nil {
            var savingBehaviors: [Track.Tag: TagSavingBehavior] = [:]
            for tag in Track.Tag.allTags {
                savingBehaviors[tag] = tag.isReturnedBySearchAPI ? .Save : .Clear
            }
            tagSavingBehaviors = savingBehaviors
        }
        let initialArtworkFolder = NSURL.fileURLWithPath(NSFileManager.defaultManager().URLsForDirectory(.DownloadsDirectory, inDomains: .UserDomainMask)[0].filePathURL!.path!, isDirectory: true)
        if NSUserDefaults.standardUserDefaults().URLForKey(UserDefaultsConstants.artworkTargetKey) == nil {
            artworkTarget = initialArtworkFolder
        }
    }
    
    // MARK: General Preferences
    
    /// If `true` the album artwork should be saved to the `artworkTarget` URL
    /// when an item is saved.
    public dynamic var saveArtwork: Bool {
        set {
            NSUserDefaults.standardUserDefaults().setBool(newValue, forKey: UserDefaultsConstants.saveArtworkKey)
        }
        get {
            return NSUserDefaults.standardUserDefaults().boolForKey(UserDefaultsConstants.saveArtworkKey)
        }
    }
    
    /// The URL of the folder album artwork is saved to.
    ///
    /// The URL must be a valid file URL pointing to a directory.
    public dynamic var artworkTarget: NSURL {
        set {
            NSUserDefaults.standardUserDefaults().setURL(newValue, forKey: UserDefaultsConstants.artworkTargetKey)
        }
        get {
            return NSUserDefaults.standardUserDefaults().URLForKey(UserDefaultsConstants.artworkTargetKey)!
        }
    }
    
    /// If `true` the search results are not removed from the main outline view
    /// when the user selects a result.
    public dynamic var keepSearchResults: Bool {
        set {
            NSUserDefaults.standardUserDefaults().setBool(newValue, forKey: UserDefaultsConstants.keepSearchResultsKey)
        }
        get {
            return NSUserDefaults.standardUserDefaults().boolForKey(UserDefaultsConstants.keepSearchResultsKey)
        }
    }
    
    // MARK: Tag Preferences
    
    /// If `true` TagTunes displays and saves censored names instead of the
    /// original names.
    public dynamic var useCensoredNames: Bool {
        set {
            NSUserDefaults.standardUserDefaults().setBool(newValue, forKey: UserDefaultsConstants.useCensoredNamesKey)
        }
        get {
            return NSUserDefaults.standardUserDefaults().boolForKey(UserDefaultsConstants.useCensoredNamesKey)
        }
    }
    
    /// The ways different tags are saved (or not saved).
    public var tagSavingBehaviors: [Track.Tag: TagSavingBehavior] {
        set {
            let savableData = newValue.map { ($0.rawValue, $1.rawValue) }
            NSUserDefaults.standardUserDefaults().setObject(savableData, forKey: UserDefaultsConstants.tagSavingBehaviorsKey)
        }
        get {
            let savableData = NSUserDefaults.standardUserDefaults().dictionaryForKey(UserDefaultsConstants.tagSavingBehaviorsKey)!
            return savableData.map { (Track.Tag(rawValue: $0)!, TagSavingBehavior(rawValue: $1 as! String)!) }
        }
    }
    
}
