//
//  String+Extension.swift
//  GSAE
//
//  Created by Mazy on 2018/5/30.
//  Copyright © 2018年 GSAE. All rights reserved.
//

import UIKit
import Foundation

// MARK: - Date
//extension String {
//    func dateStringWithFormat(_ dateFormat: String = "yyyy-MM-dd HH:mm:ss") -> Date? {
//        let formatter = DateFormatter()
//        formatter.dateFormat = dateFormat
//        formatter.timeZone = TimeZone(identifier:"Asia/Shanghai")
//        return formatter.date(from: self)
//    }
//}

import CommonCrypto

extension String {
    
    var md5Value: String {
        let length = Int(CC_MD5_DIGEST_LENGTH)
        var digest = [UInt8](repeating: 0, count: length)

        if let d = self.data(using: .utf8) {
            _ = d.withUnsafeBytes { body -> String in
                CC_MD5(body.baseAddress, CC_LONG(d.count), &digest)
                return ""
            }
        }

        return (0 ..< length).reduce("") {
            $0 + String(format: "%02x", digest[$1])
        }
    }
}

extension String {
    /// 判断是否是数字
    var isPureDigit: Bool {
        let scan: Scanner = Scanner(string: self)
        var val: Int = 0
        return scan.scanInt(&val) && scan.isAtEnd
    }
}

// MARK: - judge two string is same ignore case Insensitive
extension String {
    func isEqualTo<T>(_ otherString: T) -> Bool where T : StringProtocol {
        return self.caseInsensitiveCompare(otherString) == ComparisonResult.orderedSame
    }
}

extension String {
    func toNSRange(_ range: Range<String.Index>) -> NSRange {
        guard let from = range.lowerBound.samePosition(in: utf16), let to = range.upperBound.samePosition(in: utf16) else {
            return NSMakeRange(0, 0)
        }
        return NSMakeRange(utf16.distance(from: utf16.startIndex, to: from), utf16.distance(from: from, to: to))
    }
    
    func toRange(_ range: NSRange) -> Range<String.Index>? {
        guard let from16 = utf16.index(utf16.startIndex, offsetBy: range.location, limitedBy: utf16.endIndex) else { return nil }
        guard let to16 = utf16.index(from16, offsetBy: range.length, limitedBy: utf16.endIndex) else { return nil }
        guard let from = String.Index(from16, within: self) else { return nil }
        guard let to = String.Index(to16, within: self) else { return nil }
        return from ..< to
    }
}


// MARK: - Base64
extension String {
    
    /// Base64 encoding a string
    var base64EncodedString: String? {
        if let data = self.data(using: .utf8) {
            return data.base64EncodedString()
        }
        return nil
    }
    
    /// Base64 decoding a string
    var base64DecodedString: String? {
        if let data = Data(base64Encoded: self) {
            return String(data: data, encoding: .utf8)
        }
        return nil
    }
}

extension String {
    
    /// 过滤指定字符串(可自定义添加自己过滤的字符串)
    var removeSpecialSubStrings: String {
        return replacingOccurrences(of: "\n", with: "")
            .replacingOccurrences(of: "\r", with: "")
            .replacingOccurrences(of: "\0", with: "")
            .replacingOccurrences(of: " ", with: "")
    }
}

extension String {
    
    subscript (bounds: CountableClosedRange<Int>) -> String {
        let start = index(startIndex, offsetBy: bounds.lowerBound)
        let end = index(startIndex, offsetBy: bounds.upperBound)
        return String(self[start...end])
    }
    
    subscript (bounds: CountableRange<Int>) -> String {
        let start = index(startIndex, offsetBy: bounds.lowerBound)
        let end = index(startIndex, offsetBy: bounds.upperBound)
        return String(self[start..<end])
    }
}

extension String {
    /// 普通字符串转属性字符串
    func toMutableAttr() -> NSMutableAttributedString {
        return NSMutableAttributedString(string: self)
    }
    
    func widthOfString(usingFont font: UIFont) -> CGFloat {
        let fontAttributes = [NSAttributedString.Key.font: font]
        let size = self.size(withAttributes: fontAttributes)
        return size.width
    }
    
    func heightOfString(usingFont font: UIFont) -> CGFloat {
        let fontAttributes = [NSAttributedString.Key.font: font]
        let size = self.size(withAttributes: fontAttributes)
        return size.height
    }
    
    func sizeOfString(usingFont font: UIFont) -> CGSize {
        let fontAttributes = [NSAttributedString.Key.font: font]
        return self.size(withAttributes: fontAttributes)
    }
}

extension String {
    
    /// 字符串转URL
    func toURL() -> URL? {
        return URL(string: self)
    }
    
    /// 字符串 转 二进制
    func toData() -> Data? {
        return self.data(using: String.Encoding.utf8)
    }
    
}

extension String {
    
    var length: Int {
        return self.count
    }
    
    /// 字符串截取
    ///
    /// - Parameters:
    ///   - startIndex: 开始位置
    ///   - endIndex: 结束位置
    /// - Returns: 截取后的str
    func range(startIndex: Int, endIndex: Int) -> String {
        if self.count < startIndex {
            return ""
        }
        if self.count < endIndex {
            return ""
        }
        let startS = self.index(self.startIndex, offsetBy: startIndex)
        let endS = self.index(self.startIndex, offsetBy: endIndex)
        let newS = self[startS..<endS]
        return String(newS)
    }
    // MARK: -  修改了
    func integer(range: Range<Int>) -> String {
        if self.count < range.lowerBound {
            return ""
        }
        if self.count < range.upperBound {
            return ""
        }
        let index3 = self.index(self.startIndex, offsetBy: range.lowerBound)
        let index4 = self.index(self.startIndex, offsetBy: range.upperBound)
        let sub4 = self[index3..<index4]
        return String(sub4)
    }
//    subscript(integerRange: Range<Int>) -> String {
//       let start = index(startIndex, offsetBy: integerRange.lowerBound)
//      let end = index(startIndex, offsetBy: integerRange.upperBound)
//       return String(self[start..<end])
//    }
    
    /// 如果字符串为空显示占位字符串
    func empty(_ string: String) -> String {
        return self.count > 0 ? self : string
    }
    
    /// 字符串分割字符串数组
//    func split(_ separator: String) -> [String] {
//        return self.components(separatedBy: separator).filter {
//            !$0.trimmed().isEmpty
//        }
//    }
    
//    func trimmed() -> String {
//        return self.trimmingCharacters(in: .whitespacesAndNewlines)
//    }
    
    /// 字符串是否为空
    func isEmptyString() -> Bool {
        return self.replacingOccurrences(of: " ", with: "").isEmpty
    }
}

extension Optional where Wrapped == String {
    var isNilOrEmpty: Bool {
        return self?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true
    }
}

extension String {
    
    /// 获取0-9a-z随机数 默认8位
    ///
    /// - Parameter count: 随机几位数
    /// - Returns: str
    func getRandomStr(_ count: Int = 8) -> String {
        let string = "0123456789abcdefghijklmnopqrstuvwxyz"
        var str = ""
        for _ in 1...count {
            str += string.charAt(pos: Int(arc4random()%36))!
        }
        return str
    }
    //获取下标对应的字符
    func charAt(pos: Int) -> String? {
        if pos < 0 || pos >= count {
            return nil //判断边界条件
        }
        let index = self.index(self.startIndex, offsetBy: pos)
        let str = self[index]
        return String(str)
    }
    
    
    /**
     截取数字字符串，小数位大于8位则截取小数8位后的数字
     
     - parameter string: 要截取的字符串
     
     - returns: 返回新的字符串
     */
    func subString(def:Int = 8) -> String{
        let stringArr = self.components(separatedBy: ".")
        var newString = ""
        if stringArr.count == 2 {
            if stringArr[1].length > def{
                newString = String(format: "%.\(def)f", (self.toDouble()))
            }else{
                newString = self
            }
            if newString.toDouble() == 0{
                newString = "0"
            }
        }else{
            newString = self
        }
        return newString
    }
    
    /**
     计算文字的高度
     
     - parameter font:
     - parameter size:
     
     - returns:
     */
    func textSizeWithFont(_ font: UIFont, constrainedToSize size:CGSize) -> CGSize {
        var textSize:CGSize!
        let newStr = NSString(string: self)
        if size.equalTo(CGSize.zero) {
            let attributes = [NSAttributedString.Key.font: font]
            textSize = newStr.size(withAttributes: attributes)
        } else {
            let option = NSStringDrawingOptions.usesLineFragmentOrigin
            let attributes = [NSAttributedString.Key.font: font]
            let stringRect = newStr.boundingRect(with: size, options: option, attributes: attributes, context: nil)
            textSize = stringRect.size
        }
        return textSize
    }
    
    func heightWithConstrainedWidth(_ width: CGFloat, font: UIFont) -> CGFloat {
        
        let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
        let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [.font : font], context: nil)
        
        return ceil(boundingBox.height)
    }
    
    func heightWithConstrainted(width: CGFloat, font: UIFont) -> CGFloat {
        
        let label =  UILabel(frame: CGRect(x: 0, y: 0, width: width, height: .greatestFiniteMagnitude))
        label.numberOfLines = 0
        label.text = self
        label.font = font
        label.sizeToFit()
        
        return label.frame.height
    }
    
    // MARK: Trim API
    
    /// 去掉字符串前后的空格，根据参数确定是否过滤换行符
    ///
    /// - parameter trimNewline 是否过滤换行符，默认为false
    ///
    /// - returns:   处理后的字符串
    func trim(_ trimNewline: Bool = false) ->String {
        if trimNewline {
            return self.trimmingCharacters(in: .whitespacesAndNewlines)
        }
        
        return self.trimmingCharacters(in: .whitespaces)
    }
    
    // MARK: Substring API
    
    /// 获取子串的起始位置。
    ///
    /// - parameter substring 待查找的子字符串
    ///
    /// - returns:  如果找不到子串，返回NSNotFound，否则返回其所在起始位置
    func location(_ substring: String) ->Int {
        return (self as NSString).range(of: substring).location
    }
    
    /// 根据起始位置和长度获取子串。
    ///
    /// - parameter location  获取子串的起始位置
    /// - parameter length    获取子串的长度
    ///
    /// - returns:  如果位置和长度都合理，则返回子串，否则返回nil
    func substring(_ location: Int, length: Int) ->String? {
        if location < 0 && location >= self.length {
            return nil
        }
        
        if length <= 0 || length >= self.length {
            return nil
        }
        
        return (self as NSString).substring(with: NSMakeRange(location, length))
    }
    
    /// 根据下标获取对应的字符。若索引正确，返回对应的字符，否则返回nil
    ///
    /// - parameter index 索引位置
    ///
    /// - returns: 如果位置正确，返回对应的字符，否则返回nil
    subscript(index: Int) ->Character? {
        get {
            if let str = substring(index, length: 1) {
                return Character(str)
            }
            
            return nil
        }
    }
    
    /// 判断字符串是否包含子串。
    ///
    /// - parameter substring 子串
    ///
    /// - returns:  如果找到，返回true,否则返回false
    func isContain(_ substring: String) ->Bool {
        return (self as NSString).contains(substring)
    }
    
    // MARK: Alphanum API
    
    /// 判断字符串是否全是数字组成
    ///
    /// - returns:  若为全数字组成，返回true，否则返回false
    func isOnlyNumbers() ->Bool {
        let set = CharacterSet.decimalDigits.inverted
        let range = (self as NSString).rangeOfCharacter(from: set)
        let flag = range.location != NSNotFound
        return flag
    }
    
    /// 判断字符串是否全是字母组成
    ///
    /// - returns:  若为全字母组成，返回true，否则返回false
    func isOnlyLetters() ->Bool {
        let set = CharacterSet.letters.inverted
        let range = (self as NSString).rangeOfCharacter(from: set)
        
        return range.location != NSNotFound
    }
    
    /// 判断字符串是否全是字母和数字组成
    ///
    /// - returns:  若为全字母和数字组成，返回true，否则返回false
    func isAlphanum() ->Bool {
        let set = CharacterSet.alphanumerics.inverted
        let range = (self as NSString).rangeOfCharacter(from: set)
        
        return range.location != NSNotFound
    }
    
    // MARK: Validation API
    
    /// 判断字符串是否是有效的邮箱格式
    ///
    /// - returns:  若为有效的邮箱格式，返回true，否则返回false
//    func isValidEmail() ->Bool {
//        let regEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}"
//        let predicate = NSPredicate(format: "SELF MATCHES %@", regEx)
//        
//        return predicate.evaluate(with: self)
//    }
    
    /// 判断字符串是否 是 6到30字母数字组合
    ///
    /// - Parameter pasword: 输入字符串
    /// - Returns: 返回 true为符合
    func isPassword(pasword : String) -> Bool {
        let pwd =  "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,30}$"
        let regextestpwd = NSPredicate(format: "SELF MATCHES %@",pwd)
        if (regextestpwd.evaluate(with: pasword) == true) {
            return true
        }else{
            return false
        }
        
    }
    
    // MARK: Format API
    
    /**
     
     插入字符分隔字符串
     - parameter char:     要插入的字符
     - parameter interval: 间隔数
     */
    func insertCharByInterval(_ char: String, interval: Int) -> String {
        var text = self as NSString
        var newString = ""
        while (text.length > 0) {
            let subString = text.substring(to: min(text.length,interval))
            newString = newString + subString
            if (subString.length == interval) {
                newString = newString + char
            }
            text = text.substring(from: min(text.length,interval)) as NSString
        }
        return newString
    }
    
    
    // MARK: CAST TO OTHER TYPE API
    
    /// 转double
    ///
    /// - Parameters:
    ///   - def: 默认值
    ///   - decimal: 舍弃小数位精度
    /// - Returns:
    func toDouble(_ def: Double = 0.0, decimal: Int? = nil) -> Double {
        if !self.isEmpty {
            var doubleValue = Double(self) ?? def
            if let dec = decimal {
                doubleValue = doubleValue.floorF(places: dec)
            }
            return doubleValue
        } else {
            return def
        }
    }
    
    func toFloat(_ def: Float = 0.0) -> Float {
        if !self.isEmpty {
            return Float(self) ?? def
        } else {
            return def
        }
    }
    
    func toInt(_ def: Int = 0) -> Int {
        if !self.isEmpty {
            return Int(self) ?? 0
        } else {
            return def
        }
    }
    
    func toBool(_ def: Bool = false) -> Bool {
        if !self.isEmpty {
            let value = Int(self) ?? 0
            if value > 0 {
                return true
            } else {
                return false
            }
        } else {
            return def
        }
    }
}

extension String {
    
    func replacingOccurrences(strings: [String], with: String) -> String {
        var str = self
        strings.forEach() {
            str = str.replacingOccurrences(of: $0, with: with)
        }
        return str
    }
}

extension String {
    /// range转换为NSRange
    func nsRange(from range: Range<String.Index>) -> NSRange {
        return NSRange(range, in: self)
    }
}
