//
//  IdeabusToolBox.m
//  baseCode
//
//  Created by WiFi@MBP on 2017/10/11.
//  Copyright © 2017年 WiFi@MBP. All rights reserved.
//

#import "IdeabusToolBox.h"

@implementation IdeabusToolBox

#pragma mark - 系統類
#pragma mark 獲取系統UUID(使用KeyChain記錄)
+ (NSString *)ib_GetDeviceUUID {
    NSString *UUID = [self readKeyChain];
    if (UUID) {
        return UUID;
    }else {
        UUID = [NSString stringWithFormat:@"%@-%@",[UIDevice currentDevice].identifierForVendor.UUIDString,[self ib_MD5:[self ib_GetTimeStampOfNow]]];
        [self saveKeyChain:UUID];
        return UUID;
    }
}
#pragma mark 檢測系統版本
+ (NSString *)ib_SeeSystemVersion {
    return [[UIDevice currentDevice] systemVersion];
}

#pragma mark 檢查是否為特定系統版本
+ (BOOL)ib_IsSystemVersion:(float)sv {
    return ([[self ib_SeeSystemVersion] floatValue] >= sv);
}

#pragma mark 系統目前使用語言
+ (NSString *)ib_Language {
    NSString *language = [NSLocale preferredLanguages].firstObject;
    return language;
}

+ (NSString *)ib_CountryCode {
    NSString *countryCode = [NSLocale currentLocale].countryCode;
    return countryCode;
}

#pragma mark 設備型號
+ (NSString *)deviceModel {
#if TARGET_OS_SIMULATOR
    // Simulator doesn't return the identifier for the actual physical model, but returns it as an environment variable
    return [NSString stringWithFormat:@"%s", getenv("SIMULATOR_MODEL_IDENTIFIER")];
#else
    // See https://www.theiphonewiki.com/wiki/Models for identifiers
    struct utsname systemInfo;
    uname(&systemInfo);
    return [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
#endif
}

+ (BOOL)isLandscape {
    NSArray *scenes = [UIApplication.sharedApplication connectedScenes].allObjects;
    for (UIScene *scene in scenes) {
        if ([scene isKindOfClass:[UIWindowScene class]]) {
            UIWindowScene *windowScene = (UIWindowScene *)scene;
            NSArray *windows = windowScene.windows;
            if (windows.count > 0) {
                return UIInterfaceOrientationIsLandscape(windowScene.interfaceOrientation);
            }
        }
    }
    return NO;
}

// 英吋到 InchScreenType 的映射字典（基於數值映射）
+ (NSDictionary<NSNumber *, NSNumber *> *)sizeToTypeMap {
    static NSDictionary<NSNumber *, NSNumber *> *sizeToTypeMap = nil;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            sizeToTypeMap = @{
                @6.9: @(InchScreen69),  // 假設 InchScreen69 是新定義的 enum 值
                @6.3: @(InchScreen63),
                @6.7: @(InchScreen67),
                @6.5: @(InchScreen65),
                @6.1: @(InchScreen61),
                @5.8: @(InchScreen58),
                @5.5: @(InchScreen55),
                @5.4: @(InchScreen54),
                @4.7: @(InchScreen47),
                @4.0: @(InchScreen40),
                @3.5: @(InchScreen35),
                @13.0: @(InchScreen130),  // iPad
                @12.9: @(InchScreen129),
                @11.0: @(InchScreen111),
                @10.9: @(InchScreen109),
                @10.5: @(InchScreen105),
                @10.2: @(InchScreen102),
                @9.7: @(InchScreen97),
                @8.3: @(InchScreen83),
                @7.9: @(InchScreen79)
            };
        });
    return sizeToTypeMap;
}

#pragma mark 檢查螢幕尺寸
// 設備型號到螢幕尺寸的映射
+ (NSDictionary<NSNumber *, NSArray<NSString *> *> *)screenSizeToModelsMap {
    static NSDictionary<NSNumber *, NSArray<NSString *> *> *map = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        map = @{
            // iPhone 系列
            @6.9: @[@"iPhone17,2", @"iPhone17,4"],
            @6.3: @[@"iPhone17,1", @"iPhone17,3", @"iPhone16,1", @"iPhone16,2"],
            @6.7: @[@"iPhone15,5", @"iPhone15,3", @"iPhone14,8", @"iPhone14,3", @"iPhone13,4", @"iPhone12,5"],
            @6.5: @[@"iPhone12,5", @"iPhone11,4", @"iPhone11,6"],
            @6.1: @[@"iPhone15,4", @"iPhone15,2", @"iPhone14,7", @"iPhone14,2", @"iPhone13,3", @"iPhone13,2", @"iPhone12,1", @"iPhone11,8"],
            @5.8: @[@"iPhone12,3", @"iPhone11,2", @"iPhone10,3", @"iPhone10,6"],
            @5.5: @[@"iPhone10,5", @"iPhone10,2", @"iPhone9,4", @"iPhone9,2", @"iPhone8,2", @"iPhone7,1"],
            @5.4: @[@"iPhone14,4", @"iPhone13,1"],
            @4.7: @[@"iPhone14,6", @"iPhone12,8", @"iPhone10,4", @"iPhone10,1", @"iPhone9,3", @"iPhone9,1", @"iPhone8,1", @"iPhone7,2"],
            @4.0: @[@"iPhone8,4", @"iPhone6,2", @"iPhone6,1", @"iPhone5,4", @"iPhone5,3", @"iPhone5,2", @"iPhone5,1"],
            @3.5: @[@"iPhone4,1", @"iPhone3,3", @"iPhone3,2", @"iPhone3,1", @"iPhone2,1", @"iPhone1,2", @"iPhone1,1"],

            // iPad 系列
            @13.0: @[@"iPad14,5", @"iPad14,6"],
            @12.9: @[@"iPad13,8", @"iPad13,9", @"iPad13,10", @"iPad13,11", @"iPad8,5", @"iPad8,6", @"iPad8,7", @"iPad8,8", @"iPad8,9", @"iPad8,10", @"iPad8,11", @"iPad8,12", @"iPad7,1", @"iPad7,2", @"iPad6,7", @"iPad6,8"],
            @11.0: @[@"iPad14,3", @"iPad14,4", @"iPad13,4", @"iPad13,5", @"iPad13,6", @"iPad13,7", @"iPad8,1", @"iPad8,2", @"iPad8,3", @"iPad8,4"],
            @10.9: @[@"iPad13,16", @"iPad13,17", @"iPad14,8", @"iPad14,9", @"iPad13,1", @"iPad13,2"],
            @10.5: @[@"iPad11,3", @"iPad11,4"],
            @10.2: @[@"iPad12,1", @"iPad12,2", @"iPad11,6", @"iPad11,7", @"iPad7,11", @"iPad7,12"],
            @9.7: @[@"iPad7,5", @"iPad7,6", @"iPad6,11", @"iPad6,12", @"iPad5,3", @"iPad5,4", @"iPad4,1", @"iPad4,2", @"iPad4,3", @"iPad3,1", @"iPad3,2", @"iPad3,3", @"iPad3,4", @"iPad3,5", @"iPad3,6", @"iPad2,1", @"iPad2,2", @"iPad2,3", @"iPad2,4", @"iPad1,1"],
            @8.3: @[@"iPad14,1", @"iPad14,2"],
            @7.9: @[@"iPad11,1", @"iPad11,2", @"iPad5,1", @"iPad5,2", @"iPad4,4", @"iPad4,5", @"iPad4,6", @"iPad4,7", @"iPad4,8", @"iPad4,9", @"iPad2,5", @"iPad2,6", @"iPad2,7"]
        };
    });
    return map;
}

+ (InchScreenType)GetInchScreenTypeWithDeviceModel {
    NSString *machine = [self deviceModel];  // 假設 deviceModel 是類別方法
    NSDictionary<NSNumber *, NSArray<NSString *> *> *sizeToModelsMap = [self screenSizeToModelsMap];
    NSDictionary<NSNumber *, NSNumber *> *sizeToTypeMap = [self sizeToTypeMap];  // 使用靜態 sizeToTypeMap
    
    InchScreenType inchScreenType = InchScreenUnknown;
    
    // 遍歷 sizeToModelsMap，找到包含當前型號的英吋鍵
    for (NSNumber *sizeKey in sizeToModelsMap) {
        NSArray<NSString *> *models = sizeToModelsMap[sizeKey];
        if ([models containsObject:machine]) {
            NSNumber *typeValue = sizeToTypeMap[sizeKey];
            if (typeValue) {
                inchScreenType = (InchScreenType)[typeValue intValue];
            }
            break;  // 找到後立即停止
        }
    }
    
    return inchScreenType;
}

// 使用邏輯像素尺寸映射
+ (NSDictionary<NSValue *, NSNumber *> *)logicalSizeToScreenSizeMap {
    static NSDictionary<NSValue *, NSNumber *> *map = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        map = @{
            // iPhone 型號及對應邏輯尺寸 (points) -> 實際螢幕尺寸 (inch)
            [NSValue valueWithCGSize:CGSizeMake(440, 956)]: @6.9,   // iPhone 16/17 Pro Max
            [NSValue valueWithCGSize:CGSizeMake(402, 874)]: @6.3,   // iPhone 16/17 Pro
            [NSValue valueWithCGSize:CGSizeMake(430, 932)]: @6.7,   // iPhone 14/15 Pro Max
            [NSValue valueWithCGSize:CGSizeMake(428, 926)]: @6.7,   // iPhone 12/13 Pro Max
            [NSValue valueWithCGSize:CGSizeMake(414, 896)]: @6.5,   // iPhone XS Max, 11 Pro Max
            [NSValue valueWithCGSize:CGSizeMake(393, 852)]: @6.1,   // iPhone 14/15 Pro
            [NSValue valueWithCGSize:CGSizeMake(390, 844)]: @6.1,   // iPhone 12/13/14/15/16/17 標準版
            [NSValue valueWithCGSize:CGSizeMake(375, 812)]: @5.8,   // iPhone X/XS/11 Pro, 12/13 mini
            [NSValue valueWithCGSize:CGSizeMake(414, 736)]: @5.5,   // iPhone 6/7/8 Plus
            [NSValue valueWithCGSize:CGSizeMake(375, 667)]: @4.7,   // iPhone 6/7/8, SE 2/3
            [NSValue valueWithCGSize:CGSizeMake(360, 780)]: @5.4,   // iPhone 12/13 mini
            [NSValue valueWithCGSize:CGSizeMake(320, 568)]: @4.0,   // iPhone 5/5s/5c/SE 1
            [NSValue valueWithCGSize:CGSizeMake(320, 480)]: @3.5,   // iPhone 4/4s

            // iPad 型號及對應邏輯尺寸 (points) -> 實際螢幕尺寸 (inch)
            [NSValue valueWithCGSize:CGSizeMake(1032, 1376)]: @13.0, // iPad Pro 13" M4
            [NSValue valueWithCGSize:CGSizeMake(1024, 1366)]: @12.9, // iPad Pro 12.9"
            [NSValue valueWithCGSize:CGSizeMake(834, 1210)]: @11.0,  // iPad Pro 11" M4
            [NSValue valueWithCGSize:CGSizeMake(834, 1194)]: @11.0,  // iPad Pro 11"
            [NSValue valueWithCGSize:CGSizeMake(820, 1180)]: @10.9,  // iPad Air 10.9", iPad 10.9"
            [NSValue valueWithCGSize:CGSizeMake(834, 1112)]: @10.5,  // iPad Air 10.5"
            [NSValue valueWithCGSize:CGSizeMake(810, 1080)]: @10.2,  // iPad 10.2"
            [NSValue valueWithCGSize:CGSizeMake(768, 1024)]: @9.7,   // iPad 9.7" (衝突處理)
            [NSValue valueWithCGSize:CGSizeMake(744, 1133)]: @8.3,   // iPad Mini 8.3"
        };
    });
    return map;
}

+ (InchScreenType)GetInchScreenTypeWithUIScreen {
    // 獲取當前螢幕邏輯尺寸（已處理橫豎屏，寬度較小）
    CGSize screenSize = CGSizeMake(DEVICE_WIDTH, DEVICE_HEIGHT);
    NSValue *sizeKey = [NSValue valueWithCGSize:screenSize];
    
    // 從字典查詢英吋值
    NSDictionary<NSValue *, NSNumber *> *logicalSizeToScreenSizeMap = [self logicalSizeToScreenSizeMap];
    NSDictionary<NSNumber *, NSNumber *> *sizeToTypeMap = [self sizeToTypeMap];
    
    NSNumber *inch = logicalSizeToScreenSizeMap[sizeKey];
    InchScreenType inchScreenType = InchScreenUnknown;
    
    if (inch) {
        NSNumber *typeValue = sizeToTypeMap[inch];
        if (typeValue) {
            inchScreenType = (InchScreenType)[typeValue intValue];
        }
    }
    
    return inchScreenType;
}

+ (InchScreenType)GetInchScreenType {
    InchScreenType inchScreenType = InchScreenUnknown;
    // 主要方法：型號匹配（無衝突，最可靠）
    InchScreenType inchScreenTypeForDeviceModel = [self GetInchScreenTypeWithDeviceModel];
    // 驗證方法：邏輯尺寸匹配
    InchScreenType inchScreenTypeForUIScreen = [self GetInchScreenTypeWithUIScreen];
    // 優先取型號結果
    if (inchScreenTypeForDeviceModel == inchScreenTypeForUIScreen) {
        inchScreenType = inchScreenTypeForDeviceModel;
    } else if (inchScreenTypeForDeviceModel != InchScreenUnknown) {
        inchScreenType = inchScreenTypeForDeviceModel;
    } else if (inchScreenTypeForUIScreen != InchScreenUnknown) {
        inchScreenType = inchScreenTypeForUIScreen;
    }
    return inchScreenType;
}

#pragma mark 带物理凹槽的刘海屏或者使用 Home Indicator 类型的设备
+ (BOOL)isNotchedScreen {
    InchScreenType inchScreenType = [self GetInchScreenType];
    return inchScreenType == InchScreen54 || inchScreenType == InchScreen58 || inchScreenType == InchScreen61 || inchScreenType == InchScreen65 ||  inchScreenType == InchScreen67;
}

#pragma mark 判斷是否為可NFC執行設備
+ (BOOL)ib_IsNFCWorking {
    NSString *deviceModel = [self deviceModel];;
    deviceModel = [deviceModel stringByReplacingOccurrencesOfString:@"," withString:@"."];
    if ([deviceModel hasPrefix:@"iPhone"]) {
        deviceModel = [deviceModel stringByReplacingOccurrencesOfString:@"iPhone" withString:@""];
        return (deviceModel.floatValue > 9.0);
    } else {
        return NO;
    }
}

#pragma mark - 加/解密類
#pragma mark MD5
+ (NSString *)ib_MD5:(NSString *)str {
    unsigned int outputLength = CC_MD5_DIGEST_LENGTH;
    unsigned char output[outputLength];
    CC_MD5(str.UTF8String, [self UTF8Length:str], output);
    return [self toHexString:output length:outputLength];
}

#pragma mark SHA1
+ (NSString *)ib_SHA1:(NSString *)str {
    unsigned int outputLength = CC_SHA1_DIGEST_LENGTH;
    unsigned char output[outputLength];
    CC_SHA1(str.UTF8String, [self UTF8Length:str], output);
    return [self toHexString:output length:outputLength];
}

#pragma mark SHA256
+ (NSString *)ib_SHA256:(NSString *)str {
    unsigned int outputLength = CC_SHA256_DIGEST_LENGTH;
    unsigned char output[outputLength];
    CC_SHA256(str.UTF8String, [self UTF8Length:str], output);
    return [self toHexString:output length:outputLength];
}

#pragma mark SHA512
+ (NSString *)ib_SHA512:(NSString *)str {
    unsigned int outputLength = CC_SHA512_DIGEST_LENGTH;
    unsigned char output[outputLength];
    CC_SHA512(str.UTF8String, [self UTF8Length:str], output);
    return [self toHexString:output length:outputLength];
}

#pragma mark  Base64加密（NSString）
+ (NSString *)ib_Base64EncodedString:(NSString *)string {
    NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
    return [self ib_Base64EncodingWithData:data];
}

#pragma mark Base64加密（NSData）
+ (NSString *)ib_Base64EncodingWithData:(NSData *)sourceData {
    return [sourceData base64EncodedStringWithOptions:
            NSDataBase64Encoding64CharacterLineLength];
}

#pragma mark  Base64解密（NSString）
+ (NSString *)ib_Base64DecodedString:(NSString *)string {
    NSData *data = [self ib_Base64EncodingWithString:string];
    return [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
}

#pragma mark Base64解密（NSData）
+ (id)ib_Base64EncodingWithString:(NSString *)sourceString {
    return [[NSData alloc]initWithBase64EncodedString:sourceString options:NSDataBase64DecodingIgnoreUnknownCharacters];
}

#pragma mark  DES加密（NSData）
+ (NSData *)ib_DESEncryptData:(NSData *)data
                    keyString:(NSString *)keyString
                           iv:(NSString *)ivString {
    NSData *iv = [ivString dataUsingEncoding:NSUTF8StringEncoding];
    return [self CCCryptData:data algorithm:kCCAlgorithmDES operation:kCCEncrypt keyString:keyString iv:iv];
}

#pragma mark  DES加密（NSString）
+ (NSString *)ib_DESEncryptString:(NSString *)string
                        keyString:(NSString *)keyString
                               iv:(NSString *)ivString {
    NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
    NSData *result = [self ib_DESEncryptData:data keyString:keyString iv:ivString];
    //BASE64編碼
    return [self ib_Base64EncodingWithData:result];
}

#pragma mark  DES解密（NSData）
+ (NSData *)ib_DESDecryptData:(NSData *)data
                    keyString:(NSString *)keyString
                           iv:(NSString *)ivString {
    NSData *iv = [ivString dataUsingEncoding:NSUTF8StringEncoding];
    return [self CCCryptData:data algorithm:kCCAlgorithmDES operation:kCCDecrypt keyString:keyString iv:iv];
}

#pragma mark  DES解密（NSString）
+ (NSString *)ib_DESDecryptString:(NSString *)string
                        keyString:(NSString *)keyString
                               iv:(NSString *)ivString {
    //BASE64解碼
    NSData *data = [self ib_Base64EncodingWithString:string];
    NSData *result = [self ib_DESDecryptData:data keyString:keyString iv:ivString];
    return [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
}

#pragma mark  AES加密（NSData）
+ (NSData *)ib_AESEncryptData:(NSData *)data
                    keyString:(NSString *)keyString
                           iv:(NSString *)ivString {
    NSData *iv = [ivString dataUsingEncoding:NSUTF8StringEncoding];
    return [self CCCryptData:data algorithm:kCCAlgorithmAES operation:kCCEncrypt keyString:keyString iv:iv];
}

#pragma mark  AES加密（NSString）
+ (NSString *)ib_AESEncryptString:(NSString *)string
                        keyString:(NSString *)keyString
                               iv:(NSString *)ivString {
    NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
    NSData *result = [self ib_AESEncryptData:data keyString:keyString iv:ivString];
    //BASE64編碼
    return [self ib_Base64EncodingWithData:result];
}

#pragma mark  AES解密（NSData）
+ (NSData *)ib_AESDecryptData:(NSData *)data
                    keyString:(NSString *)keyString
                           iv:(NSString *)ivString {
    NSData *iv = [ivString dataUsingEncoding:NSUTF8StringEncoding];
    return [self CCCryptData:data algorithm:kCCAlgorithmAES operation:kCCDecrypt keyString:keyString iv:iv];
}

#pragma mark  AES解密（NSString）
+ (NSString *)ib_AESDecryptString:(NSString *)string
                        keyString:(NSString *)keyString
                               iv:(NSString *)ivString {
    //BASE64解碼
    NSData *data = [self ib_Base64EncodingWithString:string];
    NSData *result = [self ib_AESDecryptData:data keyString:keyString iv:ivString];
    return [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
}

#pragma mark - 檔案存取類
#pragma 取得應用沙盒位置
+ (NSString *)ib_GetSandBox:(SandBoxs)key
                   FileName:(NSString *)fileName {
    NSString *sandBox = nil;
    NSArray *arry = nil;
    switch (key) {
        case Root:
            sandBox = NSHomeDirectory();
            break;
        case Documents:
            arry = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
            sandBox = [arry lastObject];
            break;
        case Libaray:
            arry = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,NSUserDomainMask,YES);
            sandBox = [arry lastObject];
            break;
        case Caches:
            arry = NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask, YES);
            sandBox = [arry lastObject];
            break;
        case Preferences:
            arry = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
            sandBox = [[arry lastObject] stringByAppendingPathComponent:@"Preferences"];
            break;
        case Tmp:
            sandBox = NSTemporaryDirectory();
            break;
        default:
            break;
    }
    if (fileName.length > 0) {
        // 创建数据库目录
        NSString *dirPath = [sandBox stringByAppendingPathComponent:fileName];
        NSFileManager* fileManager = [NSFileManager defaultManager];
        BOOL isDir = NO;
        BOOL isCreated = [fileManager fileExistsAtPath:dirPath isDirectory:&isDir];
        if ((isCreated == NO) || (isDir == NO)) {
            NSError* error = nil;
#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
            NSDictionary* attributes = @{ NSFileProtectionKey : NSFileProtectionNone };
#else
            NSDictionary* attributes = nil;
#endif
            BOOL success = [fileManager createDirectoryAtPath:dirPath
                                  withIntermediateDirectories:YES
                                                   attributes:attributes
                                                        error:&error];
            if (success) {
                return dirPath;
            }else {
                return sandBox;
            }
        }else {
            return dirPath;
        }
    }else {
        return sandBox;
    }
}

#pragma mark 建立檔案路經
+ (NSString *)ib_SetFileName:(NSString *)fileName
                saveFilePath:(NSString *)FilePathName
             saveFilePathKey:(SandBoxs)key {
    return [[self ib_GetSandBox:key FileName:FilePathName] stringByAppendingPathComponent:fileName];
}

#pragma mark 檢查檔案存在
+ (BOOL)ib_CheckingFile:(NSString *)filePath {
    NSFileManager *fileManager  = [NSFileManager defaultManager];
    return [fileManager fileExistsAtPath: filePath];
}
#pragma mark 刪除檔案
+ (void)ib_DeleteFile:(NSString *)filePath {
    NSLog(@"ib_DeleteFile:%@",filePath);
    NSFileManager *fileManager  = [NSFileManager defaultManager];
    if ([self ib_CheckingFile:filePath]) {
        [fileManager removeItemAtPath:filePath error:nil];
    }
}

#pragma mark - NSUserDefaults存取類
#pragma mark 將變量存至NSUserDefaults
+ (void)ib_SaveNSUserDefaults:(id)value Key:(NSString *)key {
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    [userDefaults setObject:value forKey:key];
    [userDefaults synchronize];
}

#pragma mark 從NSUserDefaults讀取變量
+ (id)ib_ReadNSUserDefaults:(NSString *)key {
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    if ([userDefaults objectForKey:key]) {
        return [userDefaults objectForKey:key];
    }else {
        return nil;
    }
}

#pragma mark 從NSUserDefaults刪除資料
+ (void)ib_DeleteNSUserDefaults:(NSString *)key {
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    [userDefaults removeObjectForKey:key];
    [userDefaults synchronize];
}

#pragma mark 判斷NSUserDefaults 某個key值是否存
+ (BOOL)ib_DetermineNSUserDefaultExist:(NSString *)key {
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    return [[[userDefaults dictionaryRepresentation] allKeys] containsObject:key];
}

#pragma mark 刪除所有UserDefault資料
+ (void)ib_RemoveAllDefaultData {
    NSUserDefaults *userDefatlut = [NSUserDefaults standardUserDefaults];
    NSDictionary *dictionary = [userDefatlut dictionaryRepresentation];
    for(NSString* key in [dictionary allKeys]){
        [userDefatlut removeObjectForKey:key];
        [userDefatlut synchronize];
    }
}

#pragma mark - Plist存取類
#pragma mark 讀取設定用plist資料
+ (id)ib_AppMetaDataWithKey:(NSString *)key {
    NSDictionary *appDictionary = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"AppMetaData" ofType:@"plist"]];
    return [appDictionary objectForKey:key];
}

#pragma mark 將變量存至本地Plist文件
+ (void)ib_WriteToPlist:(id)value
                    key:(NSString *)key
               fileName:(NSString *)fileName {
    NSMutableDictionary *dic = nil;
    fileName = [NSString stringWithFormat:@"%@.plist",fileName];
    NSString *filePath = [self ib_SetFileName:fileName saveFilePath:@"" saveFilePathKey:Documents];
    NSLog(@"filePath:%@",filePath);
    if ([self ib_CheckingFile:filePath]) {
        dic = [NSMutableDictionary dictionaryWithContentsOfFile:filePath];
    } else {
        dic =  [NSMutableDictionary dictionary];
    }
    if ([dic objectForKey:key]) {
        [dic removeObjectForKey:key];
    }
    [dic setObject:value forKey:key];
    if ([dic writeToFile:filePath atomically:YES]) {
        NSLog(@"write %@ success",key);
    }else {
        NSLog(@"write %@ fail",key);
    }
}

#pragma mark 讀取本地Plist文件某個變量的值
+ (id)ib_ReadFromPlistByKey:(NSString *)key
                   fileName:(NSString *)fileName {
    fileName = [NSString stringWithFormat:@"%@.plist",fileName];
    NSString *filePath = [self ib_SetFileName:fileName saveFilePath:@"" saveFilePathKey:Documents];
    if ([self ib_CheckingFile:filePath]) {
        NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithContentsOfFile:filePath];
        return [dic objectForKey:key];
    }else {
        return nil;
    }
}

#pragma mark 刪除本地Plist文件某個變量
+ (void)ib_RemoveFromPlistByKey:(NSString *)key
                       fileName:(NSString *)fileName {
    fileName = [NSString stringWithFormat:@"%@.plist",fileName];
    NSString *filePath = [self ib_SetFileName:fileName saveFilePath:@"" saveFilePathKey:Documents];
    if ([self ib_CheckingFile:filePath]) {
        NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithContentsOfFile:filePath];
        if ([dic objectForKey:key]) {
            [dic removeObjectForKey:key];
        }
        if ([dic writeToFile:filePath atomically:YES]) {
            NSLog(@"removeFromPlist success");
        }else {
            NSLog(@"removeFromPlist fail");
        }
    }else {
        NSLog(@"file does not exist");
    }
}

#pragma mark - 圖片處理類
#pragma mark 以等比例大小，縮放圖片
+ (UIImage *)ib_ScaleImage:(UIImage *)image
                    toSize:(CGSize)rectsize
                     Scale:(BOOL)scale {
    CGFloat ratio = 1.0;
    CGFloat hratio = 1.0;
    ratio = rectsize.width/image.size.width;
    hratio = rectsize.height/image.size.height;
    CGSize tSize = CGSizeMake(image.size.width*ratio, image.size.height*hratio);
    UIGraphicsBeginImageContextWithOptions(tSize,NO,scale?[[UIScreen mainScreen]scale]:1);
    [image drawInRect:CGRectMake((tSize.width - image.size.width*ratio)/2, (rectsize.height - image.size.height*hratio)/2, image.size.width*ratio, image.size.height*hratio)];
    UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return scaledImage;
}

#pragma mark 以縮放倍率，縮放圖片
+ (UIImage *)ib_ScaleImage:(UIImage *)image
                   toScale:(float)scaleSize
                     Scale:(BOOL)scale  {
    CGSize tSize = CGSizeMake(image.size.width * scaleSize, image.size.height * scaleSize);
    UIGraphicsBeginImageContextWithOptions(tSize,NO,scale?[[UIScreen mainScreen]scale]:1);
    [image drawInRect:CGRectMake(0, 0, image.size.width * scaleSize, image.size.height * scaleSize)];
    UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return scaledImage;
}

#pragma mark 以固定寬度，縮放圖片
+ (UIImage *)ib_ScaleImage:(UIImage *)image
                   byWidth:(CGFloat)width
                     Scale:(BOOL)scale {
    CGFloat ratio = 1.0;
    ratio = width/image.size.width;
    CGFloat mHeight, mWidth;
    mHeight = image.size.height*ratio;
    mWidth = image.size.width*ratio;
    CGSize tSize = CGSizeMake(mWidth, mHeight);
    UIGraphicsBeginImageContextWithOptions(tSize,NO,scale?[[UIScreen mainScreen]scale]:1);
    [image drawInRect:CGRectMake((mWidth - mWidth)/2, (mHeight - mHeight)/2, mWidth, mHeight)];
    UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return scaledImage;
}

#pragma mark 以固定高度，縮放圖片
+ (UIImage *)ib_ScaleImage:(UIImage *)image
                  byHeight:(CGFloat)height
                     Scale:(BOOL)scale {
    CGFloat ratio = 1.0;
    ratio = height/image.size.height;
    CGFloat mHeight, mWidth;
    mHeight = image.size.height*ratio;
    mWidth = image.size.width*ratio;
    CGSize tSize = CGSizeMake(mWidth, mHeight);
    UIGraphicsBeginImageContextWithOptions(tSize,NO,scale?[[UIScreen mainScreen]scale]:1);
    [image drawInRect:CGRectMake((mWidth - mWidth)/2, (mHeight - mHeight)/2, mWidth, mHeight)];
    UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return scaledImage;
}

#pragma mark 兩張圖覆盖合成圖片
+ (UIImage*)ib_MaskImage:(UIImage *)image
                withMask:(UIImage *)maskImage
                   Scale:(BOOL)scale {
    UIGraphicsBeginImageContextWithOptions(image.size,NO,scale?[[UIScreen mainScreen]scale]:1);
    [image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
    [maskImage drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
    UIImage *resultImg = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return resultImg;
}

#pragma mark 對於特定UIView的截圖
+ (UIImage*)ib_CaptureView:(UIView *)view Scale:(BOOL)scale {
    UIGraphicsBeginImageContextWithOptions(view.frame.size,NO,scale?[[UIScreen mainScreen]scale]:1);
    [view.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

#pragma mark 固定框架圖片（留白居中圖）
+(UIImage *)ib_FitSquareImage:(UIImage *)image
                       toSize:(CGSize)size
                        Scale:(BOOL)scale {
    UIImage *img = nil;
    if (size.width > size.height) {
        img = [self ib_ScaleImage:image byHeight:size.height Scale:scale];
    }else {
        img = [self ib_ScaleImage:image byWidth:size.width Scale:scale];
    }
    UIGraphicsBeginImageContextWithOptions(size,NO,scale?[[UIScreen mainScreen]scale]:1);
    CGFloat imageX = (size.width-img.size.width)*0.5;
    CGFloat imageY = (size.height-img.size.height)*0.5;
    [img drawInRect:CGRectMake(imageX, imageY, img.size.width, img.size.height)];//上圖
    UIImage *resultImg = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return resultImg;
}

#pragma mark 固定滿版圖片(填滿居中圖)
+(UIImage *)ib_FillSquareImage:(UIImage *)image
                        toSize:(CGSize)size
                         Scale:(BOOL)scale {
    UIImage *img = nil;
    if (size.width > size.height) {
        img = [self ib_ScaleImage:image byWidth:size.width Scale:scale];
    }else {
        img = [self ib_ScaleImage:image byHeight:size.height Scale:scale];
    }
    UIGraphicsBeginImageContextWithOptions(size,NO,scale?[[UIScreen mainScreen]scale]:1);
    CGFloat imageX = (size.width-img.size.width)*0.5;
    CGFloat imageY = (size.height-img.size.height)*0.5;
    [img drawInRect:CGRectMake(imageX, imageY, img.size.width, img.size.height)];//上圖
    UIImage *resultImg = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return resultImg;
}

#pragma mark 將圖剪裁呈圓形圖
+ (UIImage *)ib_CircleImageWithImage:(UIImage *)image
                         borderWidth:(CGFloat)borderWidth
                         borderColor:(UIColor *)borderColor
                               Scale:(BOOL)scale {
    UIImage *oldImage = image;
    CGFloat imageW = oldImage.size.width + 2 * borderWidth;
    CGFloat imageH = oldImage.size.height + 2 * borderWidth;
    CGSize imageSize = CGSizeMake(imageW, imageH);
    UIGraphicsBeginImageContextWithOptions(imageSize, NO, scale?[[UIScreen mainScreen]scale]:1);
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    [borderColor set];
    CGFloat bigRadius = imageW * 0.5;
    CGFloat centerX = bigRadius;
    CGFloat centerY = bigRadius;
    CGContextAddArc(ctx, centerX, centerY, bigRadius, 0, M_PI * 2, 0);
    CGContextFillPath(ctx);
    CGFloat smallRadius = bigRadius - borderWidth;
    CGContextAddArc(ctx, centerX, centerY, smallRadius, 0, M_PI * 2, 0);
    CGContextClip(ctx);
    [oldImage drawInRect:CGRectMake(borderWidth, borderWidth, oldImage.size.width, oldImage.size.height)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}

#pragma mark 顏色轉圖片
+ (UIImage*)ib_CreateImageWithColor:(UIColor*)color
                             toSize:(CGSize)rectsize
                              Scale:(BOOL)scale {
    CGRect rect = CGRectMake(0.0f, 0.0f, rectsize.width, rectsize.height);
    UIGraphicsBeginImageContextWithOptions(rectsize,NO,scale?[[UIScreen mainScreen]scale]:1);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(context, [color CGColor]);
    CGContextFillRect(context, rect);
    UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return theImage;
}

#pragma mark - UICokor類
#pragma mark 隨機取色
/// 隨機取色
/// - Parameter type: <#type description#>
+ (UIColor *)ib_RainbowColor:(ColorType)type {
    // 1. 隨機透明度：0.25 ~ 1.00
    // 確保顏色不會因為太淡而看不見
    CGFloat alpha = (arc4random_uniform(76) + 25) * 0.01;
    switch (type) {
        case ColorHSB:
            // 這裡傳入 arc4random_uniform(5) 是為了讓 HSB 模式
            // 隨機挑選一種「亮度/飽和度」的風格 (Dark, Warm, Bright 等)
            // 這是很聰明的寫法！能讓 HSB 顏色變化更豐富
            return [IdeabusToolBox ib_HSBRainbowColor:arc4random_uniform(5) Alpha:alpha];
        case ColorGolden:
            // 黃金比例不需要 Type 參數，因為它是靠 static 變數輪播的
            return [IdeabusToolBox ib_GoldenRatioColorWithAlpha:alpha];
        default:
            // 其他標準模式 (Primary, Dark, Bright...) 走原本的 RGB 邏輯
            return [IdeabusToolBox ib_RainbowColor:type Alpha:alpha];
    }
}

/// 隨機取色
/// - Parameters:
///   - type: type description
///   - alpha: alpha description
+ (UIColor *)ib_RainbowColor:(ColorType)type Alpha:(CGFloat)alpha {
    // 1. 判斷是否為全域隨機
    BOOL isPrimary = (type == ColorPrimary);
    // 2. 設定隨機精度 (10000 份)
    uint32_t precision = 10000;
    // 3. 根據類型決定偏移量 (0.0, 0.25, 0.5, 0.75) 與 範圍縮放 (1.0 或 0.25)
    // 這裡保留原本的數學邏輯，但變數名更清楚
    CGFloat offset = isPrimary ? 0.0 : (type % 4) * 0.25;
    CGFloat scale  = isPrimary ? 1.0 : 0.25;
    // 4. 定義隨機產生器 Block
    CGFloat (^randVal)(void) = ^CGFloat {
        return offset + (arc4random_uniform(precision + 1) / (CGFloat)precision) * scale;
    };
    return [UIColor colorWithDisplayP3Red:randVal() green:randVal() blue:randVal() alpha:alpha];
}

+ (UIColor *)ib_HSBRainbowColor:(ColorType)type Alpha:(CGFloat)alpha {
    CGFloat hue = arc4random_uniform(256) / 255.0; // 0.0 ~ 1.0 全色相隨機
    CGFloat saturation = 0;
    CGFloat brightness = 0;
    switch (type) {
        case ColorDarkBlack:
            saturation = 0.2; // 低飽和
            brightness = 0.15 + (arc4random_uniform(10) / 100.0); // 0.15~0.25 (極暗)
            break;
        case ColorDark:
            saturation = 0.6 + (arc4random_uniform(20) / 100.0); // 高飽和
            brightness = 0.3 + (arc4random_uniform(20) / 100.0); // 0.3~0.5 (暗色)
            break;
        case ColorWarm:
            // 暖色通常飽和度適中，亮度偏高
            saturation = 0.4 + (arc4random_uniform(20) / 100.0);
            brightness = 0.7 + (arc4random_uniform(20) / 100.0); // 0.7~0.9
            break;
        case ColorBright:
            // 亮色/粉嫩色：低飽和、高亮度
            saturation = 0.2 + (arc4random_uniform(20) / 100.0);
            brightness = 0.95; // 極亮
            break;
        case ColorPrimary:
        default:
            saturation = 0.8; // 鮮豔
            brightness = 0.8; // 明亮
            break;
    }
    return [UIColor colorWithHue:hue saturation:saturation brightness:brightness alpha:alpha];
}

+ (UIColor *)ib_GoldenRatioColorWithAlpha:(CGFloat)alpha {
    // ---------------------------------------------------------
    // 1. 決定色相 (Hue) - 黃金比例算法
    // ---------------------------------------------------------
    // 使用 static 變數記住上一次的位置
    static CGFloat currentHue = 0.0;
    // 黃金比例共軛數 (0.618...)
    // 讓顏色在色環上每次都跳躍約 137.5 度，確保相鄰的顏色差異最大
    const CGFloat goldenRatioConjugate = 0.618033988749895;
    currentHue += goldenRatioConjugate;
    currentHue = fmod(currentHue, 1.0); // 確保數值在 0.0 ~ 1.0 之間
    // ---------------------------------------------------------
    // 2. 決定飽和度 (Saturation) 與 亮度 (Brightness) - 廣色域隨機
    // ---------------------------------------------------------
    // 初始飽和度範圍: 0.20 (淡) ~ 0.80 (濃)
    CGFloat saturation = 0.20 + (arc4random_uniform(61) * 0.01);
    // 初始亮度範圍: 0.15 (暗) ~ 0.95 (亮)
    CGFloat brightness = 0.15 + (arc4random_uniform(81) * 0.01);
    // ---------------------------------------------------------
    // 3. 視覺校正邏輯 (Smart Correction)
    // ---------------------------------------------------------
    // [防髒邏輯]
    // 如果顏色很暗 (B < 0.4)，但飽和度又低，看起來會像「大便」或「髒泥巴」。
    // 修正：強迫提升飽和度，讓它變成「深邃的寶石色」(如深紅、深綠)。
    if (brightness < 0.4) {
        saturation = MAX(saturation, 0.6);
    }
    // [防白邏輯]
    // 如果飽和度很低 (S < 0.3)，且亮度又很高，看起來會像「幾乎全白」，UI 會看不清楚。
    // 修正：強迫降低亮度，讓它變成有質感的「灰色系」或「莫蘭迪色」。
    if (saturation < 0.3) {
        brightness = MIN(brightness, 0.8);
    }
    return [UIColor colorWithHue:currentHue saturation:saturation brightness:brightness alpha:alpha];
}

#pragma mark 十六進位值轉換UIColor
+ (UIColor *)ib_ColorFromHexString:(NSString *)hexString {
    NSString *cleanString = [hexString stringByReplacingOccurrencesOfString:@"#" withString:@""];
    if([cleanString length] == 3) {
        cleanString = [NSString stringWithFormat:@"%@%@%@%@%@%@",
                       [cleanString substringWithRange:NSMakeRange(0, 1)],[cleanString substringWithRange:NSMakeRange(0, 1)],
                       [cleanString substringWithRange:NSMakeRange(1, 1)],[cleanString substringWithRange:NSMakeRange(1, 1)],
                       [cleanString substringWithRange:NSMakeRange(2, 1)],[cleanString substringWithRange:NSMakeRange(2, 1)]];
    }
    if([cleanString length] == 6) {
        cleanString = [cleanString stringByAppendingString:@"ff"];
    }
    unsigned int baseValue;
    [[NSScanner scannerWithString:cleanString] scanHexInt:&baseValue];
    float red = ((baseValue >> 24) & 0xFF)/255.0f;
    float green = ((baseValue >> 16) & 0xFF)/255.0f;
    float blue = ((baseValue >> 8) & 0xFF)/255.0f;
    float alpha = ((baseValue >> 0) & 0xFF)/255.0f;
    return [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
}

#pragma mark Image變成Color
+ (UIColor *)ib_ColorWithPatternImage:(NSString *)imageName
                               toSize:(CGSize)rectsize {
    UIImage *bgImage = [self ib_ScaleImage:[UIImage imageNamed:imageName] toSize:rectsize Scale:YES];
    return [UIColor colorWithPatternImage:bgImage];
}

#pragma mark 互補色
+ (UIColor *)ib_ComplementaryColor:(UIColor *)color {
    CGFloat alpha = CGColorGetAlpha(color.CGColor);
    return [IdeabusToolBox ib_ComplementaryColor:color Alpha:alpha];
}

+ (UIColor *)ib_ComplementaryColor:(UIColor *)color Alpha:(CGFloat)alpha {
    CGFloat hue, saturation, brightness, valpha;
    CGFloat red, green, blue;
    
    // 1. 取得顏色資訊 (HSB & RGB)
    BOOL hsbSuccess = [color getHue:&hue saturation:&saturation brightness:&brightness alpha:&valpha];
    BOOL rgbSuccess = [color getRed:&red green:&green blue:&blue alpha:&valpha];
    
    if (!hsbSuccess || !rgbSuccess) {
        const CGFloat *components = CGColorGetComponents(color.CGColor);
        return (components[0] > 0.5) ? [UIColor blackColor] : [UIColor whiteColor];
    }
    
    // ---------------------------------------------------------
    // 2. 判斷背景基底色 (Base Background)
    // ---------------------------------------------------------
    // 直接存取 currentTraitCollection，不需要 @available 檢查
    CGFloat baseC = 1.0; // 預設白色 (Light Mode)
    
    if (UITraitCollection.currentTraitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
        baseC = 0.0; // 夜間模式背景是黑色
    }
    
    // ---------------------------------------------------------
    // 3. 混合背景色計算真實顏色 (Alpha Blending)
    // ---------------------------------------------------------
    // 公式：(原色 * Alpha) + (背景色 * (1 - Alpha))
    // 模擬人眼在半透明色塊下看到的真實顏色
    
    CGFloat visibleRed   = (red * valpha)   + (baseC * (1.0 - valpha));
    CGFloat visibleGreen = (green * valpha) + (baseC * (1.0 - valpha));
    CGFloat visibleBlue  = (blue * valpha)  + (baseC * (1.0 - valpha));
    
    // ---------------------------------------------------------
    // 4. 計算視覺感知亮度 (Luminance)
    // ---------------------------------------------------------
    // 使用 WCAG 標準公式：綠色權重最高，藍色最低
    CGFloat luminance = (visibleRed * 0.299) + (visibleGreen * 0.587) + (visibleBlue * 0.114);
    
    // ---------------------------------------------------------
    // 5. 決定文字亮度 (二分法)
    // ---------------------------------------------------------
    CGFloat finalBrightness;
    
    // 門檻 0.55：
    // 亮度 > 0.55 (背景偏亮) -> 給深色字 (0.15)
    // 亮度 <= 0.55 (背景偏暗) -> 給亮色字 (0.95)
    if (luminance > 0.55) {
        finalBrightness = 0.15;
    } else {
        finalBrightness = 0.95;
    }
    
    // ---------------------------------------------------------
    // 6. 處理互補色調
    // ---------------------------------------------------------
    CGFloat newHue = fmod(hue + 0.5, 1.0); // 色相轉 180 度
    CGFloat newSaturation = (saturation > 0.1) ? 0.15 : 0.0; // 飽和度壓低至 15%
    
    return [UIColor colorWithHue:newHue saturation:newSaturation brightness:finalBrightness alpha:alpha];
}

#pragma mark - 文字類
#pragma mark ＊＊判斷字串是否符合規則＊＊
#pragma mark 使用正則表達式判斷字串
+ (BOOL)ib_CheckingString:(NSString *)str
                Predicate:(NSString *)regex {
    NSPredicate *checkingString = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];
    return [checkingString evaluateWithObject:str];
}

#pragma mark 判斷字符串是否只包含字母
+ (BOOL)ib_IsOnlyLetters:(NSString*)str {
    NSString *regex = @"^[A-Za-z]+$";
    return [self ib_CheckingString:str Predicate:regex];
}

#pragma mark 判斷字符串是否只包含數字
+ (BOOL)ib_IsOnlyNumbers:(NSString*)str {
    NSString *regex = @"^[0-9]+$";
    return [self ib_CheckingString:str Predicate:regex];
}

#pragma mark 判斷字符串是否只包含字母和數字
+ (BOOL)ib_IsOnlyAlphaNumeric:(NSString*)str {
    NSString *regex = @"^[A-Za-z0-9]+$";
    return [self ib_CheckingString:str Predicate:regex];
}
#pragma mark 判斷是否為E-mail格式
+ (BOOL)ib_IsEmail:(NSString *)str {
    NSString *regex = @"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}";
    return [self ib_CheckingString:str Predicate:regex];
}

#pragma mark 判斷是否含有表情
+ (BOOL)ib_IsEmoji:(NSString *)string {
    __block BOOL returnValue = NO;
    [string enumerateSubstringsInRange:NSMakeRange(0, [string length])
                               options:NSStringEnumerationByComposedCharacterSequences
                            usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
                                const unichar hs = [substring characterAtIndex:0];
                                if (0xd800 <= hs && hs <= 0xdbff) {
                                    if (substring.length > 1) {
                                        const unichar ls = [substring characterAtIndex:1];
                                        const int uc = ((hs - 0xd800) * 0x400) + (ls - 0xdc00) + 0x10000;
                                        if (0x1d000 <= uc && uc <= 0x1f77f) {
                                            returnValue = YES;
                                        }
                                    }
                                } else if (substring.length > 1) {
                                    const unichar ls = [substring characterAtIndex:1];
                                    if (ls == 0x20e3) {
                                        returnValue = YES;
                                    }
                                } else {
                                    if (0x2100 <= hs && hs <= 0x27ff) {
                                        returnValue = YES;
                                    } else if (0x2B05 <= hs && hs <= 0x2b07) {
                                        returnValue = YES;
                                    } else if (0x2934 <= hs && hs <= 0x2935) {
                                        returnValue = YES;
                                    } else if (0x3297 <= hs && hs <= 0x3299) {
                                        returnValue = YES;
                                    } else if (hs == 0xa9 || hs == 0xae || hs == 0x303d || hs == 0x3030 || hs == 0x2b55 || hs == 0x2b1c || hs == 0x2b1b || hs == 0x2b50) {
                                        returnValue = YES;
                                    }
                                }
                            }];
    
    return returnValue;
}

#pragma mark 判斷是否全是空格
+ (BOOL)ib_CheckSingleBlank:(NSString *)string {
    __block NSInteger check = 0;
    [string enumerateSubstringsInRange:NSMakeRange(0, [string length])
                               options:NSStringEnumerationByComposedCharacterSequences
                            usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
                                const unichar hs = [substring characterAtIndex:0];
                                check += (hs == 32)?1:0;
                            }];
    BOOL returnValue = (check == [string length]);
    return returnValue;
}

#pragma mark 判斷是否含自訂字元
+ (BOOL)ib_CheckString:(NSString *)string Predicate:(NSString *)regex {
    __block NSInteger check = 0;
    [string enumerateSubstringsInRange:NSMakeRange(0, [string length])
                               options:NSStringEnumerationByComposedCharacterSequences
                            usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
                                NSRange range = [regex rangeOfString:substring];
                                check += (range.length == 0)?1:0;
                            }];
    BOOL returnValue = (check != [string length]);
    return returnValue;
}

#pragma mark ＊＊文字中空格及回車去掉＊＊
#pragma mark 去除DeviceToken的“ ”,“<”,“>”
+ (NSString *)ib_GetDeviceToken:(NSString *)devTokenDescription {
    NSString *deviceToken= [devTokenDescription stringByReplacingOccurrencesOfString:@" " withString:@""];
    deviceToken = [deviceToken stringByReplacingOccurrencesOfString:@"<" withString:@""];
    deviceToken = [deviceToken stringByReplacingOccurrencesOfString:@">" withString:@""];
    return deviceToken;
}

#pragma mark 將所有的空格及回車去掉
+ (NSString *)ib_RemoveSpaceAndNewlineForALL:(NSString *)str {
    NSString *temp = [str stringByReplacingOccurrencesOfString:@" " withString:@""];
    temp = [temp stringByReplacingOccurrencesOfString:@"\r" withString:@""];
    temp = [temp stringByReplacingOccurrencesOfString:@"\\r" withString:@""];
    temp = [temp stringByReplacingOccurrencesOfString:@"\n" withString:@""];
    temp = [temp stringByReplacingOccurrencesOfString:@"\\n" withString:@""];
    return temp;
}

#pragma mark 去掉字串兩端的空格及回車
+ (NSString *)ib_RemoveSpaceAndNewline:(NSString *)str {
    NSString *temp = [str stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
    NSString *text = [temp stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    return text;
}

#pragma mark - 時間類
#pragma mark 將日期NSString轉換成NSDate
+ (NSDate *)ib_DateNSStringToNSDate:(NSString *)str
                         withFormat:(NSString *)format {
    NSDateFormatter *dFormatter = [NSDateFormatter new];
    [dFormatter setCalendar: [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]];
    [dFormatter setDateFormat:format];
    NSDate *datetime = [dFormatter dateFromString:str];
    return datetime;
}

#pragma mark 將日期NSDate轉換成NSString
+ (NSString *)ib_DateNSDateToNSString:(NSDate *)date
                           withFormat:(NSString *)format {
    NSDateFormatter *dFormatter = [NSDateFormatter new];
    [dFormatter setCalendar: [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]];
    [dFormatter setDateFormat:format];
    return [dFormatter stringFromDate:date];
}

#pragma mark 取純日期格式NSDate（@"yyyy-MM-dd"）
+ (NSDate*)ib_ShortDate:(NSDate*)date {
    return [self ib_ShortDate:date withFormat:@"yyyy-MM-dd"];
}

+ (NSDate*)ib_ShortDate:(NSDate*)date withFormat:(NSString *)format {
    NSString* dateString = [self ib_DateNSDateToNSString:date withFormat:format];
    return [self ib_DateNSStringToNSDate:dateString withFormat:format];
}

#pragma mark 建立時間戳記(提早一小時):2016-03-29T14:57:42+08:00
+ (NSString *)ib_GetTimeStampOfNow {
    NSDate *date = [NSDate dateWithTimeInterval:-3600 sinceDate:[NSDate date]];
    NSString *pString = [self ib_DateNSDateToNSString:date withFormat:@"yyyy-MM-dd'T'HH:mm:ssZZZZ"];
    pString = [pString stringByReplacingOccurrencesOfString:@"GMT" withString:@""];
    return [NSString stringWithFormat:@"%@", pString];
}

#pragma mark 建立時間戳記(提早一小時):timeIntervalSince1970
+ (NSString *)ib_GetTimeStampOfUnix {
    NSDate *date = [NSDate dateWithTimeInterval:-3600 sinceDate:[NSDate date]];
    NSTimeInterval timeStamp = [date timeIntervalSince1970];
    NSNumber *timeStampObj = [NSNumber numberWithDouble:timeStamp];
    return [NSString stringWithFormat:@"%ld",[timeStampObj longValue]];
}

#pragma mark 當前時間，自訂回傳格式 format: @"yyyy-MM-dd HH:mm:ss"、@"yyyy年MM月dd日 HH时mm分ss秒"
+ (NSString *)ib_CurrentDateWithFormat:(NSString *)format {
    return [self ib_DateNSDateToNSString:[NSDate date] withFormat:format];
}

#pragma mark 檢查是否越期
+ (NSComparisonResult)ib_CheckingDate:(NSString *)date
                           withFormat:(NSString *)format {
    NSDate *today = [self ib_ShortDate:[NSDate date] withFormat:@"yyyy-MM-dd"];
    NSDate *datetime = [self ib_DateNSStringToNSDate:date withFormat:format];
    NSComparisonResult result = [today compare:datetime];
    return result;
}

#pragma mark 計算今天日期距離比對日期多久(Use NSString)，key回傳單位>>yy:年; MM:月; dd:日; HH:時; mm:分; ss:秒;
+ (NSNumber *)ib_TodayFromLastTime:(NSString *)lastTime
                    lastTimeFormat:(NSString *)format
                           withKey:(NSString *)key {
    NSDate *lastDate = [self ib_DateNSStringToNSDate:lastTime withFormat:format];
    NSString *new = [self ib_CurrentDateWithFormat:format];
    NSDate *today = [self ib_DateNSStringToNSDate:new withFormat:format];
    return [self ib_TimeIntervalFromLastTime:lastDate ToCurrentTime:today withKey:key];
}

#pragma mark 計算上次日期距離比對日期多久(Use NSString)，key回傳單位>>yy:年; MM:月; dd:日; HH:時; mm:分; ss:秒;
+ (NSNumber *)ib_TimeIntervalFromLastTime:(NSString *)lastTime
                           lastTimeFormat:(NSString *)format1
                            ToCurrentTime:(NSString *)currentTime
                        currentTimeFormat:(NSString *)format2
                                  withKey:(NSString *)key {
    NSDate *lastDate = [self ib_DateNSStringToNSDate:lastTime withFormat:format1];
    NSDate *currentDate = [self ib_DateNSStringToNSDate:currentTime withFormat:format2];
    return [self ib_TimeIntervalFromLastTime:lastDate ToCurrentTime:currentDate withKey:key];
}

#pragma mark 計算上次日期距離比對日期多久(Use NSDate)，key回傳單位>>yy:年; MM:月; dd:日; HH:時; mm:分; ss:秒;
+ (NSNumber *)ib_TimeIntervalFromLastTime:(NSDate *)lastTime
                            ToCurrentTime:(NSDate *)currentTime
                                  withKey:(NSString *)key {
    NSDateComponents *cmps = [self ib_PleaseInsertStarTime:currentTime endTime:lastTime];
    NSMutableDictionary *dic = [NSMutableDictionary new];
    [dic setValue:@(cmps.second) forKey:@"ss"];
    [dic setValue:@(cmps.minute) forKey:@"mm"];
    [dic setValue:@(cmps.hour) forKey:@"HH"];
    [dic setValue:@(cmps.day) forKey:@"dd"];
    [dic setValue:@(cmps.month) forKey:@"MM"];
    [dic setValue:@(cmps.year) forKey:@"yy"];
    return [dic objectForKey:key];
}

#pragma mark  計算兩個時間之間的間隔(Use NSString)
+ (NSDateComponents *)ib_PleaseInsertStarTime:(NSString *)startTime
                              startTimeFormat:(NSString *)format1
                                      endTime:(NSString *)endTime
                                endTimeFormat:(NSString *)format2 {
    NSDate *startDate = [self ib_DateNSStringToNSDate:startTime withFormat:format1];
    NSDate *endDate = [self ib_DateNSStringToNSDate:endTime withFormat:format2];
    return [self ib_PleaseInsertStarTime:startDate endTime:endDate];
}
#pragma mark  計算兩個時間之間的間隔(Use NSDate)
+ (NSDateComponents *)ib_PleaseInsertStarTime:(NSDate *)startTime
                                      endTime:(NSDate *)endTime {
    NSCalendar *calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
    NSCalendarUnit type = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
    NSDateComponents *cmps = [calendar components:type fromDate:startTime toDate:endTime options:0];
    NSLog(@"兩個時間相差%ld年%ld月%ld日%ld小時%ld分鐘%ld秒", cmps.year, cmps.month, cmps.day, cmps.hour, cmps.minute, cmps.second);
    return cmps;
}

#pragma mark  依據比對時間返回相對應日期格式(Use NSString)
+ (NSString*)ib_LocalizedShortDateStringWithNSString:(NSString *)timeString
                                          withFormat:(NSString *)format {
    NSDate *d_day = [self ib_DateNSStringToNSDate:timeString withFormat:format];
    return [self ib_LocalizedShortDateStringWithNSDate:d_day];
}

#pragma mark  依據比對時間返回相對應日期格式(Use NSDate)
+ (NSString*)ib_LocalizedShortDateStringWithNSDate:(NSDate*)date {
    NSDate *new = [self ib_ShortDate:[NSDate date]];
    NSDate *d_day = [self ib_ShortDate:date];
    NSDateComponents *cmps = [self ib_PleaseInsertStarTime:new endTime:d_day];
    if (cmps.day > 1) {
        return [self ib_DateNSDateToNSString:date withFormat:@"dd HH:mm"];
    }
    else if (cmps.month > 1) {
        return [self ib_DateNSDateToNSString:date withFormat:@"MM/dd HH:mm"];
    }
    else if (cmps.year > 1) {
        return [self ib_DateNSDateToNSString:date withFormat:@"yyyy/MM/dd HH:mm"];
    }
    else {
        return [self ib_DateNSDateToNSString:date withFormat:@"HH:mm"];
    }
}

#pragma mark - Button類
#pragma mark 建立Button
+ (id)ib_CreateButtoninitWithBar:(BOOL)inBar
                           Title:(NSString *)title
                      TitleColor:(UIColor *)titleColor
                 BackgroundColor:(UIColor *)backgroundColor
                            Size:(CGSize)size
                             Tag:(NSInteger)tag
                          Target:(id)target
                          Action:(SEL)action {
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    [button setTitle:title forState:UIControlStateNormal];
    [button setTitleColor:titleColor forState:UIControlStateNormal];
    [button setBackgroundColor:backgroundColor];
    [button setFrame:CGRectMake(0, 0, size.width, size.height)];
    button.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
    button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
    button.tag = tag;
    [button addTarget:target
               action:action
     forControlEvents:UIControlEventTouchUpInside|UIControlEventTouchUpOutside];
    if (inBar) {
        UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithCustomView:button];
        return barButtonItem;
    }else {
        return button;
    }
}

#pragma mark 使用圖片建立Button
+ (id)ib_CreateButtoninitWithBar:(BOOL)inBar
                           Title:(NSString *)title
                      TitleColor:(UIColor *)color
             ImageFileNameNormal:(UIImage *)normalImage
        ImageFileNameHighlighted:(UIImage *)highlightedImage
                             Tag:(NSInteger)tag
                          Target:(id)target
                          Action:(SEL)action {
    UIButton *button =
    [self ib_CreateButtoninitWithBar:NO Title:title TitleColor:color BackgroundColor:[UIColor clearColor] Size:normalImage.size Tag:tag Target:target Action:action];
    [button setTitleColor :color forState:UIControlStateNormal];
    [button setBackgroundImage:normalImage forState:UIControlStateNormal];
    [button setBackgroundImage:highlightedImage forState:UIControlStateHighlighted];
    if (inBar) {
        UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithCustomView:button];
        return barButtonItem;
    }else {
        return button;
    }
}

#pragma mark  Selected Button（勾選型Button）
+ (UIButton *)ib_CreateSelectedButtonTitle:(NSString *)title
                                TitleColor:(UIColor *)color
                                       Tag:(NSInteger)tag
                       ImageFileNameNormal:(UIImage *)normalImage
                     ImageFileNameSelected:(UIImage *)SelectedImage
                                    Target:(id)target
                                    Action:(SEL)action {
    if (!normalImage) {
        normalImage = [UIImage imageNamed:@"unchecked_checkbox@2x"];
    }
    if (!SelectedImage) {
        SelectedImage = [UIImage imageNamed:@"checked_checkbox@2x"];
    }
    UIButton *selectedBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    [selectedBtn setTitle:[NSString stringWithFormat:@" %@",title] forState:UIControlStateNormal];
    [selectedBtn setTitleColor:color forState:UIControlStateNormal];
    [selectedBtn setImage:normalImage forState:UIControlStateNormal];
    [selectedBtn setImage:SelectedImage forState:UIControlStateSelected];
    selectedBtn.tag = tag;
    selectedBtn.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
    selectedBtn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
    [selectedBtn.titleLabel sizeToFit];
    [selectedBtn setFrame:CGRectMake(0, 0, selectedBtn.titleLabel.frame.size.width+selectedBtn.imageView.image.size.width, selectedBtn.imageView.image.size.height)];
    [selectedBtn addTarget:target
                    action:action
          forControlEvents:UIControlEventTouchUpInside|UIControlEventTouchUpOutside];
    return selectedBtn;
}

#pragma mark  Icon Button（Icon型Button）
+ (UIButton *)ib_CreateIconButtonTitle:(NSString *)title
                            TitleColor:(UIColor *)color
                                   Tag:(NSInteger)tag
                   ImageFileNameNormal:(UIImage *)normalImage
              ImageFileNameHighlighted:(UIImage *)highlightedImage
                                Target:(id)target
                                Action:(SEL)action {
    UIButton *iconBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    [iconBtn setTitle:title forState:UIControlStateNormal];
    [iconBtn setTitleColor :color forState:UIControlStateNormal];
    [iconBtn setImage:normalImage forState:UIControlStateNormal];
    [iconBtn setImage:highlightedImage forState:UIControlStateHighlighted];
    iconBtn.tag = tag;
    [iconBtn addTarget:target
                action:action
          forControlEvents:UIControlEventTouchUpInside|UIControlEventTouchUpOutside];
    iconBtn.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
    iconBtn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
    iconBtn.titleLabel.adjustsFontSizeToFitWidth = YES;
    iconBtn.titleLabel.textAlignment = NSTextAlignmentCenter;
    CGSize size = [iconBtn.titleLabel sizeThatFits:iconBtn.imageView.frame.size];
    CGRect rect = [iconBtn.titleLabel.text
                   boundingRectWithSize:iconBtn.imageView.frame.size//限制最大的宽度和高度
                   options:NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesFontLeading |NSStringDrawingUsesLineFragmentOrigin//采用换行模式
                   attributes:@{NSFontAttributeName:iconBtn.titleLabel.font}//传人的字体字典
                   context:nil];
    int numberOfLines = rect.size.height/size.height+1;
    iconBtn.titleLabel.numberOfLines = numberOfLines;
    [iconBtn setFrame:CGRectMake(0, 0, iconBtn.imageView.image.size.width, iconBtn.imageView.image.size.height+iconBtn.titleLabel.frame.size.height+rect.size.height)];
    [iconBtn setImageEdgeInsets:UIEdgeInsetsMake(-rect.size.height,0, iconBtn.titleLabel.frame.size.height, 0)];
    [iconBtn setTitleEdgeInsets:UIEdgeInsetsMake(iconBtn.imageView.frame.size.height, -(iconBtn.imageView.frame.size.width), 0, 0)];
    return iconBtn;
}

#pragma mark 建立NavigationItem<可以調整BarButtonItem位置>
+ (NSMutableArray *)ib_SetBarButtonItemsOffset:(float)width
                                           Tag:(NSInteger)tag
                           ImageFileNameNormal:(UIImage *)normalImage
                      ImageFileNameHighlighted:(UIImage *)highlightedImage
                                        Target:(id)target
                                        Action:(SEL)action {
    UIBarButtonItem *barButtonItem = [self ib_CreateButtoninitWithBar:YES Title:nil TitleColor:nil ImageFileNameNormal:normalImage ImageFileNameHighlighted:highlightedImage Tag:tag Target:target Action:action];
    UIBarButtonItem *negativeSpacer =
    [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
    negativeSpacer.width = width;
    return [NSMutableArray arrayWithObjects:negativeSpacer,barButtonItem, nil];
}

#pragma mark - NSString
+ (CGRect)ib_GetRect:(NSString *)text MAXSize:(CGSize)size Font:(UIFont *)font {
    CGRect rect =
    [text boundingRectWithSize:CGSizeMake(size.width, MAXFLOAT)//限制最大的宽度和高度
                       options:NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesFontLeading | NSStringDrawingUsesLineFragmentOrigin//采用换行模式
                    attributes:@{NSFontAttributeName:font}//传人的字体字典
                       context:nil];
    return rect;
}
#pragma mark NSString 計算行數numberOfLines
+ (NSInteger)ib_GetNumberOfLines:(NSString *)text MAXSize:(CGSize)size Font:(UIFont *)font {
    CGRect rect = [IdeabusToolBox ib_GetRect:text MAXSize:size Font:font];
    NSInteger numberOfLines = rect.size.height/size.height;
    return numberOfLines;
}

#pragma mark - AlertCntroller
#pragma mark  UIAlertController：type 提示窗形式（0:UIAlertControllerStyleActionSheet 1:UIAlertControllerStyleAlert 無按鈕時，delay自動消失時間：(1.0 ~)
+ (void)ib_ShowAlertCntrollerWithViewController:(id)vc
                           AlertControllerStyle:(UIAlertControllerStyle)type
                                          Title:(NSString *)title
                                        Message:(NSString *)message
                                     AfterDelay:(NSTimeInterval)delay
                                      CallBlock:(void (^)(NSInteger btnIndex))block
                                     Completion:(void (^)(void))completion
                              CancelButtonTitle:(NSString *)cancelBtnTitle
                         DestructiveButtonTitle:(NSString *)destructiveBtnTitle
                              OtherButtonTitles:(NSString *)otherBtnTitles, ...  {
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:type];
    if ([[IdeabusToolBox deviceModel] hasPrefix:@"iPad"]) {
        alertController.popoverPresentationController.sourceView = vc;
    }
    if (destructiveBtnTitle.length) {
        if (![destructiveBtnTitle isEqualToString: @""]) {
            UIAlertAction * destructiveAction = [UIAlertAction actionWithTitle:destructiveBtnTitle style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
                block(1);
            }];
            [alertController addAction:destructiveAction];
        }
    }
    int index = (destructiveBtnTitle.length)?2:1;
    if (otherBtnTitles.length) {
        UIAlertAction *otherActions = [UIAlertAction actionWithTitle:otherBtnTitles style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            block(index);
        }];
        [alertController addAction:otherActions];
        va_list args;
        va_start(args, otherBtnTitles);
        if (otherBtnTitles.length) {
            NSString * otherString;
            while ((otherString = va_arg(args, NSString*))) {
                index++;
                UIAlertAction *otherActions = [UIAlertAction actionWithTitle:otherString style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
                    block(index);
                }];
                [alertController addAction:otherActions];
            }
        }
        va_end(args);
    }
    if (cancelBtnTitle.length) {
        UIAlertAction * cancelAction = [UIAlertAction actionWithTitle:cancelBtnTitle style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
            block(0);
        }];
        [alertController addAction:cancelAction];
    }
    if (alertController.actions.count == 0) {
        delay = (1.0 > delay)?1.0:delay;
        [NSTimer scheduledTimerWithTimeInterval:delay repeats:NO block:^(NSTimer * _Nonnull timer) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [alertController dismissViewControllerAnimated:YES completion:completion];
            });
            block(-1);
        }];
    }
    dispatch_async(dispatch_get_main_queue(), ^{
        [[self ib_GetViewController] presentViewController:alertController animated:YES completion:completion];
    });
}

#pragma mark  簡易提示窗：type 提示窗形式（0:UIAlertControllerStyleActionSheet 1:UIAlertControllerStyleAlert）無按鈕時，delay自動消失時間：(1.0 ~)
+ (void)ib_ShowMessageViewWith:(id)vc
                          Type:(UIAlertControllerStyle)type
                         Title:(NSString *)title
                       Message:(NSString *)message
             CancelButtonTitle:(NSString *)cancelBtnTitle
        DestructiveButtonTitle:(NSString *)destructiveBtnTitle
                    AfterDelay:(NSTimeInterval)delay
                     CallBlock:(void (^)(NSInteger btnIndex))block
                    Completion:(void (^)(void))completion {
    [self ib_ShowAlertCntrollerWithViewController:vc AlertControllerStyle:type Title:title Message:message AfterDelay:delay CallBlock:block Completion:completion CancelButtonTitle:cancelBtnTitle DestructiveButtonTitle:destructiveBtnTitle OtherButtonTitles:nil];
}

#pragma mark 有輸入匡的警告視窗
+ (void)ib_ShowMessageViewWithTextField:(id)vc
                                   Type:(UIAlertControllerStyle)type
      TextFieldWithConfigurationHandler:(void (^ __nullable)(UITextField *textField))configurationHandler
                                  Title:(NSString *_Nullable)title
                                Message:(NSString *_Nullable)message
                      CancelButtonTitle:(NSString *_Nullable)cancelBtnTitle
                 DestructiveButtonTitle:(NSString *_Nullable)destructiveBtnTitle
                              CallBlock:(void (^_Nullable)(NSString * _Nonnull str))block
                             Completion:(void (^_Nonnull)(void))completion {
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title?:@"" message:message preferredStyle:type];
    if ([[IdeabusToolBox deviceModel] hasPrefix:@"iPad"]) {
        alertController.popoverPresentationController.sourceView = vc;
    }
    [alertController addTextFieldWithConfigurationHandler:configurationHandler];
    if (destructiveBtnTitle) {
        UIAlertAction * destructiveAction = [UIAlertAction actionWithTitle:destructiveBtnTitle?:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            block(alertController.textFields.firstObject.text);
        }];
        [alertController addAction:destructiveAction];
    }
    if (cancelBtnTitle) {
        UIAlertAction * cancelAction = [UIAlertAction actionWithTitle:cancelBtnTitle?:@"Cancel" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
            block(nil);
        }];
        [alertController addAction:cancelAction];
    }
    dispatch_async(dispatch_get_main_queue(), ^{
        [[self ib_GetViewController] presentViewController:alertController animated:true completion:completion];
    });
}

#pragma mark - ViewController
#pragma mark - 獲取當前ViewController
+ (UIViewController *)ib_GetViewController {
    UIViewController *vc = [UIApplication sharedApplication].keyWindow.rootViewController;
    // modal
    if (vc.presentedViewController) {
        if ([vc.presentedViewController isKindOfClass:[UINavigationController class]]) {
            UINavigationController *navVc = (UINavigationController *)vc.presentedViewController;
            vc = navVc.visibleViewController;
        }
        else if ([vc.presentedViewController isKindOfClass:[UITabBarController class]]){
            UITabBarController *tabVc = (UITabBarController *)vc.presentedViewController;
            if ([tabVc.selectedViewController isKindOfClass:[UINavigationController class]]) {
                UINavigationController *navVc = (UINavigationController *)tabVc.selectedViewController;
                return navVc.visibleViewController;
            }
            else{
                return tabVc.selectedViewController;
            }
        }
        else{
            vc = vc.presentedViewController;
        }
    }
    // push
    else{
        if ([vc isKindOfClass:[UITabBarController class]]) {
            UITabBarController *tabVc = (UITabBarController *)vc;
            if ([tabVc.selectedViewController isKindOfClass:[UINavigationController class]]) {
                UINavigationController *navVc = (UINavigationController *)tabVc.selectedViewController;
                return navVc.visibleViewController;
            }
            else{
                return tabVc.selectedViewController;
            }
        }
        else if([vc isKindOfClass:[UINavigationController class]]){
            UINavigationController *navVc = (UINavigationController *)vc;
            vc = navVc.visibleViewController;
        }
    }
    return vc;
}

#pragma mark UIStoryboard建立UIViewController
+(id)ib_GetControllerWithStoryboardName:(NSString *)storyName Identifier:(NSString *)identifier {
    UIStoryboard *story = [UIStoryboard storyboardWithName: storyName bundle: nil];
    UIViewController *controll = [story instantiateViewControllerWithIdentifier: identifier];
    return controll;
}

#pragma mark 打開SFSafariViewController
+ (void)ib_PushSFSafariViewController:(NSString *)URLString completion:(void (^ __nullable)(void))completion {
    if (URLString.length > 0) {
        NSString *strUrl = [URLString stringByRemovingPercentEncoding];
        NSURL *url = [NSURL URLWithString:strUrl];
        SFSafariViewController *safariView = [[SFSafariViewController alloc] initWithURL:url];
        dispatch_async(dispatch_get_main_queue(), ^{
            [[self ib_GetViewController] presentViewController:safariView animated:YES completion:completion];
        });
    }
}

#pragma mark 返回上一頁
+ (void)ib_BackPreviouPageView {
    UIViewController *vc = [self ib_GetViewController];
    dispatch_async(dispatch_get_main_queue(), ^{
        if (vc.presentingViewController) {
            [vc dismissViewControllerAnimated:YES completion:nil];
        }else{
            [vc.navigationController popViewControllerAnimated:YES];
        }
    });
}

#pragma mark 跳轉系統頁面
+ (void)ib_goGeneral {
    dispatch_async(dispatch_get_main_queue(), ^{
        NSURL *url = [NSURL URLWithString: UIApplicationOpenSettingsURLString];
        [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
    });
}

#pragma mark - app内部直接评分
+ (void)showAppStoreScore {
    if ([IdeabusToolBox ib_ReadNSUserDefaults:@"AppStoreScore"]) {
        NSTimeInterval new = [[NSDate date] timeIntervalSince1970];
        NSNumber *appStoreScore = [IdeabusToolBox ib_ReadNSUserDefaults:@"AppStoreScore"];
        if ([SKStoreReviewController respondsToSelector:@selector(requestReview)] && new >= appStoreScore.doubleValue) {
            //防止键盘遮挡
            [[UIApplication sharedApplication].keyWindow endEditing:YES];
            [SKStoreReviewController requestReview];
            [self setAppStoreScoreMax:180 min:30];
        }
    } else {
        [self setAppStoreScoreMax:30 min:7];
    }
}
/**
 設定詢問時間點

 @param Max 設定最大詢問天數
 @param min 設定最小詢問天數
 */
+ (void)setAppStoreScoreMax:(int)Max min:(int)min {
    NSDate *date = [NSDate dateWithTimeInterval:arc4random_uniform(60*60*24*Max)+(60*60*24*min) sinceDate:[NSDate date]];
    NSTimeInterval timeStamp = [date timeIntervalSince1970];
    [IdeabusToolBox ib_SaveNSUserDefaults:[NSNumber numberWithDouble:timeStamp] Key:@"AppStoreScore"];
}

#pragma mark - 分享工具UIActivityViewController
+ (void)ib_ShareWithSourceView:(id _Nonnull )vc ActivityItems:(NSArray *_Nullable)activityItems CallBlock:(void (^_Nonnull)(BOOL completed))block {
    UIActivityViewController *activityVC = [[UIActivityViewController alloc]initWithActivityItems:activityItems applicationActivities:nil];
    if ([[IdeabusToolBox deviceModel] hasPrefix:@"iPad"]) {
        activityVC.popoverPresentationController.sourceView = vc;
    }
    activityVC.completionWithItemsHandler = ^(NSString *activityType,BOOL completed,NSArray *returnedItems,NSError *activityError) {
        block(completed);
    };
    dispatch_async(dispatch_get_main_queue(), ^{
        [[self ib_GetViewController] presentViewController:activityVC animated:YES completion:nil];
    });
}

#pragma mark - *******內部使用方法*******
#pragma mark - 無按鈕彈窗自動消失方法，此時self指下面方法，否則崩潰
+ (void)dismissAlertController:(UIAlertController *)alert {
    dispatch_async(dispatch_get_main_queue(), ^{
        [alert dismissViewControllerAnimated:YES completion:nil];
    });
}
#pragma mark - 加密公用方法
#pragma mark 取得字串長度
+ (unsigned int)UTF8Length:(NSString *)str {
    return (unsigned int) [str lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
}
#pragma mark 將加密結果編成字串
+ (NSString*) toHexString:(unsigned char*) data
                   length: (unsigned int) length {
    NSMutableString* hash = [NSMutableString stringWithCapacity:length * 2];
    for (unsigned int i = 0; i < length; i++) {
        [hash appendFormat:@"%02x", data[i]];
        data[i] = 0;
    }
    return hash;
}
#pragma mark AES/DES加密＆解密核心方法
/**
 *  AES/DES加密＆解密核心方法
 *
 *  @param data      加密/解密的數據
 *  @param algorithm 加密算法
 *  @param operation 加密/解密操作
 *  @param keyString 密鑰字符串
 *  @param iv        向量
 *
 *  @return 加密/解密結果
 */
+ (NSData *)CCCryptData:(NSData *)data
              algorithm:(CCAlgorithm)algorithm
              operation:(CCOperation)operation
              keyString:(NSString *)keyString
                     iv:(NSData *)iv {
    int keySize = (algorithm == kCCAlgorithmAES) ? kCCKeySizeAES128 : kCCKeySizeDES;
    int blockSize = (algorithm == kCCAlgorithmAES) ? kCCKeySizeAES128: kCCBlockSizeDES;
    // 設置密鑰
    NSData *keyData = [keyString dataUsingEncoding:NSUTF8StringEncoding];
    uint8_t cKey[keySize];
    bzero(cKey, sizeof(cKey));
    [keyData getBytes:cKey length:keySize];
    // 設置IV向量
    uint8_t cIv[blockSize];
    bzero(cIv, blockSize);
    int option = kCCOptionPKCS7Padding | kCCOptionECBMode;
    if (iv) {
        [iv getBytes:cIv length:blockSize];
        option = kCCOptionPKCS7Padding;
    }
    // 設置輸出緩衝
    size_t bufferSize = [data length] + blockSize;
    void *buffer = malloc(bufferSize);
    // 加/解密
    size_t cryptorSize = 0;
    CCCryptorStatus cryptStatus = CCCrypt(operation,
                                          algorithm,
                                          option,
                                          cKey,
                                          keySize,
                                          cIv,
                                          [data bytes],
                                          [data length],
                                          buffer,
                                          bufferSize,
                                          &cryptorSize);
    NSData *result = nil;
    if (cryptStatus == kCCSuccess) {
        result = [NSData dataWithBytesNoCopy:buffer length:cryptorSize];
    } else {
        free(buffer);
        NSLog(@"[錯誤] 加密或解密失敗 | 狀態編碼:\n%d", cryptStatus);
    }
    return result;
}

#pragma mark - KeyChain公用方法
#pragma mark KeyChain使用字典
+ (NSMutableDictionary *)getKeyChainQuery {
    NSString *key = [[NSBundle mainBundle]bundleIdentifier];
    return [NSMutableDictionary dictionaryWithObjectsAndKeys:
            (__bridge id)(kSecClassGenericPassword),kSecClass,
            key, kSecAttrService,
            key, kSecAttrAccount,
            kSecAttrAccessibleAfterFirstUnlock,kSecAttrAccessible,nil];
}
#pragma mark UUID寫入KeyChain中
+ (void)saveKeyChain:(id)UUID {
    NSMutableDictionary *keychainQuery = [self getKeyChainQuery];
    SecItemDelete((__bridge CFDictionaryRef)(keychainQuery));
    [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:UUID]
                      forKey:(__bridge id<NSCopying>)(kSecValueData)];
    SecItemAdd((__bridge CFDictionaryRef)(keychainQuery), NULL);
}
#pragma mark 從KeyChain讀取UUID
+ (id)readKeyChain {
    id UUID = nil;
    NSMutableDictionary *keychainQuery = [self getKeyChainQuery];
    [keychainQuery setObject:(id)kCFBooleanTrue forKey:(__bridge id<NSCopying>)(kSecReturnData)];
    [keychainQuery setObject:(__bridge id)(kSecMatchLimitOne) forKey:(__bridge id<NSCopying>)(kSecMatchLimit)];
    CFTypeRef result = NULL;
    if (SecItemCopyMatching((__bridge_retained CFDictionaryRef)keychainQuery, &result) == noErr){
        UUID = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge NSData*)result];
    }
    return UUID;
}





@end
