//
//  Copyright (c) 2018. Uber Technologies
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//  http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//

import Foundation

extension String {
    enum SwiftKeywords: String {
        case `throws` = "throws"
        case `rethrows` = "rethrows"
        case `try` = "try"
        case `for` = "for"
        case `in` = "in"
        case `where` = "where"
        case `while` = "while"
        case `default` = "default"
        case `fallthrough` = "fallthrough"
        case `do` = "do"
        case `switch` = "switch"
    }
    static let doneInit = "_doneInit"
    static let `static` = "static"
    static let `import` = "import "
    static public let `class` = "class"
    static public let `final` = "final"
    static let override = "override"
    static let mockType = "protocol"
    static let unknownVal = "Unknown"
    static let any = "Any"
    static let anyObject = "AnyObject"
    static let fatalError = "fatalError"
    static let available = "available"
    static let `open` = "open"
    static let initializer = "init"
    static let handlerSuffix = "Handler"
    static let observableVarPrefix = "Observable<"
    static let rxObservableVarPrefix = "RxSwift.Observable<"
    static let rxPublishSubject = "RxSwift.PublishSubject"
    static let publishSubject = "PublishSubject"
    static let behaviorSubject = "BehaviorSubject"
    static let replaySubject = "ReplaySubject"
    static let rx = "Rx"
    static let observableEmpty = "Observable.empty()"
    static let rxObservableEmpty = "RxSwift.Observable.empty()"
    static let `required` = "required"
    static let `convenience` = "convenience"
    static let closureArrow = "->"
    static let typealiasColon = "typealias:"
    static let `typealias` = "typealias"
    static let annotationArgDelimiter = ";"
    static let rxReplaySubject = "RxSwift.ReplaySubject"
    static let replaySubjectAllocSuffix = ".create(bufferSize: 1)"
    static let subjectSuffix = "Subject"
    static let underlyingVarPrefix = "underlying"
    static let setCallCountSuffix = "SetCallCount"
    static let callCountSuffix = "CallCount"
    static let closureVarSuffix = "Handler"
    static let initializerPrefix = "init("
    static let `escaping` = "@escaping"
    static let autoclosure = "@autoclosure"
    static public let mockAnnotation = "@mockable"
    static public let poundIf = "#if "
    static public let poundEndIf = "#endif"
    static public let headerDoc =
    """
    ///
    /// @Generated by Mockolo
    ///
    """

    var isThrowsOrRethrows: Bool {
        return self == SwiftKeywords.throws.rawValue || self == SwiftKeywords.rethrows.rawValue
    }

    var safeName: String {
        if let _ = SwiftKeywords(rawValue: self) {
            return "`\(self)`"
        }
        return self
    }
}

let separatorsForDisplay = CharacterSet(charactersIn: "<>[] :,()_-.&@#!{}@+\"\'")
let separatorsForLiterals = CharacterSet(charactersIn: "?<>[] :,()_-.&@#!{}@+\"\'")

extension StringProtocol {
    var isNotEmpty: Bool {
        return !isEmpty
    }
    
    var capitlizeFirstLetter: String {
        return prefix(1).capitalized + dropFirst()
    }
    
    func shouldParse(with exclusionList: [String]? = nil) -> Bool {
        guard hasSuffix(".swift") else { return false }
        guard let exlist = exclusionList else { return true }
        
        if let name = components(separatedBy: ".swift").first {
            for ex in exlist {
                if name.hasSuffix(ex) {
                    return false
                }
            }
            return true
        }
        
        return false
    }

    var literalComponents: [String] {
        return self.components(separatedBy: separatorsForLiterals)
    }

    var displayableComponents: [String] {
        let ret = self.replacingOccurrences(of: "?", with: "Optional")
        return ret.components(separatedBy: separatorsForDisplay)
    }

    var asTestableImport: String {
        return "@testable \(self.asImport)"
    }

    var asImport: String {
        return "import \(self)"
    }
    
    var moduleName: String? {
        guard self.hasPrefix(String.import) else { return nil }
        return self.dropFirst(String.import.count).trimmingCharacters(in: CharacterSet.whitespaces)
    }
}
