text: /*
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements.  See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership.  The ASF licenses this file
   * to you 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/Foundation.h>
  #import <UIKit/UIKit.h>
  
  #import <WeexSDK/WXDefine.h>
  #import <WeexSDK/WXType.h>
  #import <WeexSDK/WXLog.h>
  #import <WeexSDK/WXSDKInstance.h>
  
  // The default screen width which helps us to calculate the real size or scale in different devices.
  static const CGFloat WXDefaultScreenWidth = 750.0;
  
  #define WX_ENUMBER_CASE(_invoke, idx, code, obj, _type, op, _flist) \
  case code:{\
      _type *_tmp = malloc(sizeof(_type));\
      memset(_tmp, 0, sizeof(_type));\
      *_tmp = [obj op];\
      [_invoke setArgument:_tmp atIndex:(idx) + 2];\
      *(_flist + idx) = _tmp;\
      break;\
  }
  #define WX_EPCHAR_CASE(_invoke, idx, code, obj, _type, op, _flist) \
  case code:{\
      _type *_tmp = (_type  *)[obj op];\
      [_invoke setArgument:&_tmp atIndex:(idx) + 2];\
      *(_flist + idx) = 0;\
      break;\
  }\
  
  #define WX_ALLOC_FLIST(_ppFree, _count) \
  do {\
      _ppFree = (void *)malloc(sizeof(void *) * (_count));\
      memset(_ppFree, 0, sizeof(void *) * (_count));\
  } while(0)
  
  #define WX_FREE_FLIST(_ppFree, _count) \
  do {\
      for(int i = 0; i < (_count); i++){\
          if(*(_ppFree + i ) != 0) {\
              free(*(_ppFree + i));\
          }\
      }\
      free(_ppFree);\
  }while(0)
  
  #define WX_ARGUMENTS_SET(_invocation, _sig, idx, _obj, _ppFree) \
  do {\
      const char *encode = [_sig getArgumentTypeAtIndex:(idx) + 2];\
      switch(encode[0]){\
          WX_EPCHAR_CASE(_invocation, idx, _C_CHARPTR, _obj, char *, UTF8String, _ppFree)\
          WX_ENUMBER_CASE(_invocation, idx, _C_INT, _obj, int, intValue, _ppFree)\
          WX_ENUMBER_CASE(_invocation, idx, _C_SHT, _obj, short, shortValue, _ppFree)\
          WX_ENUMBER_CASE(_invocation, idx, _C_LNG, _obj, long, longValue, _ppFree)\
          WX_ENUMBER_CASE(_invocation, idx, _C_LNG_LNG, _obj, long long, longLongValue, _ppFree)\
          WX_ENUMBER_CASE(_invocation, idx, _C_UCHR, _obj, unsigned char, unsignedCharValue, _ppFree)\
          WX_ENUMBER_CASE(_invocation, idx, _C_UINT, _obj, unsigned int, unsignedIntValue, _ppFree)\
          WX_ENUMBER_CASE(_invocation, idx, _C_USHT, _obj, unsigned short, unsignedShortValue, _ppFree)\
          WX_ENUMBER_CASE(_invocation, idx, _C_ULNG, _obj, unsigned long, unsignedLongValue, _ppFree)\
          WX_ENUMBER_CASE(_invocation, idx, _C_ULNG_LNG, _obj,unsigned long long, unsignedLongLongValue, _ppFree)\
          WX_ENUMBER_CASE(_invocation, idx, _C_FLT, _obj, float, floatValue, _ppFree)\
          WX_ENUMBER_CASE(_invocation, idx, _C_DBL, _obj, double, doubleValue, _ppFree)\
          WX_ENUMBER_CASE(_invocation, idx, _C_BOOL, _obj, bool, boolValue, _ppFree)\
          WX_ENUMBER_CASE(_invocation, idx, _C_CHR, _obj, char, charValue, _ppFree)\
          default: { [_invocation setArgument:&_obj atIndex:(idx) + 2]; *(_ppFree + idx) = 0; break;}\
      }\
  }while(0)
  
  #define WXPointEqualToPoint __WXPointEqualToPoint
  CG_INLINE bool
  __WXPointEqualToPoint(CGPoint point1, CGPoint point2)
  {
      return fabs (point1.x - point2.x) < 0.00001 && fabs (point1.y - point2.y) < 0.00001;
  }
  
  #ifdef __cplusplus
  extern "C" {
  #endif
      
  /**
   * @abstract execute asynchronous action block on the main thread.
   *
   */
  void WXPerformBlockOnMainThread( void (^ _Nonnull block)(void));
  
  /**
   * @abstract execute synchronous action block on the main thread.
   *
   */
  void WXPerformBlockSyncOnMainThread( void (^ _Nonnull block)(void));
  
  /**
   * @abstract execute action block on the specific thread.
   *
   */
  void WXPerformBlockOnThread(void (^ _Nonnull block)(void), NSThread *_Nonnull thread);
  
  /**
   * @abstract swizzling methods.
   *
   */
  void WXSwizzleInstanceMethod(_Nonnull Class className, _Nonnull SEL original, _Nonnull SEL replaced);
  
  void WXSwizzleInstanceMethodWithBlock(_Nonnull Class className, _Nonnull SEL original, _Nonnull id block, _Nonnull SEL replaced);
  
  _Nonnull SEL WXSwizzledSelectorForSelector(_Nonnull SEL selector);
      
  #ifdef __cplusplus
  }
  #endif
  
  @interface WXUtility : NSObject
  
  + (void)performBlock:(void (^_Nonnull)(void))block onThread:(NSThread *_Nonnull)thread;
  
  /**
   * @abstract Check if system is in dark mode.
   *
   * @return Boolean
   *
   */
  + (BOOL)isSystemInDarkScheme;
  
  /**
   * @abstract Returns the environment of current application, you can get some necessary properties such as appVersion、sdkVersion、appName etc.
   *
   * @return A dictionary object which contains these properties.
   *
   */
  + (NSDictionary *_Nonnull)getEnvironment;
  + (NSDictionary *_Nonnull)getEnvironmentForJSContext;
  + (BOOL)isEnvironmentUsingDarkScheme;
  
  + (NSDictionary *_Nonnull)getDebugEnvironment;
  
  + (WXLayoutDirection)getEnvLayoutDirection;
  
  /**
   * @abstract UserAgent Generation
   *
   * @return A ua string by splicing (deviceName、appVersion、sdkVersion、externalField、screenSize)
   *
   */
  + (NSString *_Nonnull)userAgent;
  
  /**
   * @abstract JSON Decode Method
   *
   * @param json String.
   *
   * @return A json object by decoding json string.
   *
   */
  + (id _Nullable)objectFromJSON:(NSString * _Nonnull)json;
  
  /**
   Convert all sub-structure objects of source to immutable container.
  
   @param source Source object.
   @return Converted object using immutable container.
   */
  + (id _Nullable)convertContainerToImmutable:(id _Nullable)source;
  
  #define WXDecodeJson(json)  [WXUtility objectFromJSON:json]
  
  /**
   * @abstract JSON Encode Method
   *
   * @param object Object.
   *
   * @return A json string by encoding json object.
   *
   */
  + (NSString * _Nullable)JSONString:(id _Nonnull)object;
  
  #define WXEncodeJson(obj)  [WXUtility JSONString:obj]
  
  /**
   * @abstract Returns a Foundation object from given JSON data. A Foundation object from the JSON data in data, or nil if an error occurs.
   *
   * @param data A data object containing JSON data.
   * @param error If an error occurs, upon return contains an NSError object that describes the problem.
   *
   * @return A Foundation object from the JSON data in data, or nil if an error occurs.
   *
   */
  + (id _Nullable)JSONObject:(NSData * _Nonnull)data error:(NSError * __nullable * __nullable)error;
  
  #define WXJSONObjectFromData(data) [WXUtility JSONObject:data error:nil]
  /**
   * @abstract JSON Object Copy Method
   *
   * @param object Object.
   *
   * @return A json object by copying.
   *
   */
  + (id _Nullable)copyJSONObject:(id _Nonnull)object;
  
  #define WXCopyJson(obj)     [WXUtility copyJSONObject:obj]
  
  /**
   *
   *  Checks if a String is whitespace, empty ("") or nil
   *  @code
   *    [WXUtility isBlankString: nil]       = true
   *    [WXUtility isBlankString: ""]        = true
   *    [WXUtility isBlankString: " "]       = true
   *    [WXUtility isBlankString: "bob"]     = false
   *    [WXUtility isBlankString: "  bob  "] = false
   *  @endcode
   *  @param string the String to check, may be null
   *
   *  @return true if the String is null, empty or whitespace
   */
  + (BOOL)isBlankString:(NSString * _Nullable)string ;
  
  
  /**
   check a point is valid or not. A zero point is also valid
  
   @param point a point value to check
   @return true if point.x and point.y are all valid value for a number.
   */
  + (BOOL)isValidPoint:(CGPoint)point;
  
  /**
   * @abstract Returns a standard error object
   *
   * @param code code.
   *
   * @param message message.
   *
   * @return A error object type of NSError.
   *
   */
  + (NSError * _Nonnull)errorWithCode:(NSInteger)code message:(NSString * _Nullable)message;
  
  /**
   * @abstract Returns a Font Object by setting some properties such as size、weight、style and fontFamily.
   *
   * @param size font size
   *
   * @param textWeight font weight
   *
   * @param textStyle  The type of WXTextStyle (Normal or Italic).
   *
   * @param fontFamily font family
   *
   * @param scaleFactor please use instance's scale factor
   *
   * @return A font object according to the above params.
   *
   */
  + (UIFont *_Nonnull)fontWithSize:(CGFloat)size textWeight:(CGFloat)textWeight textStyle:(WXTextStyle)textStyle fontFamily:(NSString *_Nullable)fontFamily scaleFactor:(CGFloat)scaleFactor;
  
  + (UIFont *_Nonnull)fontWithSize:(CGFloat)size textWeight:(CGFloat)textWeight textStyle:(WXTextStyle)textStyle fontFamily:(NSString *_Nullable)fontFamily scaleFactor:(CGFloat)scaleFactor useCoreText:(BOOL)useCoreText;
  
  /**
   * @abstract download remote font from specified url
   * @param fontURL for remote font
   *
   */
  + (void)getIconfont:(NSURL * _Nonnull)fontURL completion:( void(^ _Nullable )(NSURL * _Nonnull url, NSError * _Nullable error)) completionBlock;
  
  /**
   * @abstract Returns the main screen's size when the device is in portrait mode,.
   */
  + (CGSize)portraitScreenSize;
  
  /**
   * @abstract Returns the default pixel scale factor
   * @discussion If orientation is equal to landscape, the value is caculated as follows: WXScreenSize().height / WXDefaultScreenWidth, otherwise, WXScreenSize().width / WXDefaultScreenWidth.
   */
  + (CGFloat)defaultPixelScaleFactor;
  
  /**
   * @return true if the device is iPad
   */
  + (BOOL)deviceIsiPad;
  
  #if defined __cplusplus
  extern "C" {
  #endif
  /**
   * @abstract Returns the scale of the main screen.
   *
   */
  CGFloat WXScreenScale(void);
  
  /**
   * @abstract Returns a Round float coordinates to the main screen pixel.
   *
   */
  CGFloat WXRoundPixelValue(CGFloat value);
  
  /**
   * @abstract Returns a Floor float coordinates to the main screen pixel.
   *
   */
  CGFloat WXFloorPixelValue(CGFloat value);
  
  /**
   * @abstract Returns a Ceil float coordinates to the main screen pixel.
   *
   */
  CGFloat WXCeilPixelValue(CGFloat value);
      
  #if defined __cplusplus
  };
  #endif
      
  /**
   *  @abstract check whether the file is exist
   *
   */
  
  + (BOOL)isFileExist:(NSString * _Nonnull)filePath;
  /**
   *  @abstract Returns the document directory path.
   *
   */
  + (NSString *_Nonnull)documentDirectory;
  
  #define WXDocumentPath     [WXUtility documentDirectory]
  
  /**
   *  @abstract Returns the system cache directory path.
   *
   */
  + (NSString *_Nonnull)cacheDirectory;
  
  #define WXCachePath     [WXUtility cacheDirectory]
  
  /**
   *  @abstract Returns the system library directory path.
   *
   */
  + (NSString *_Nonnull)libraryDirectory;
  
  #define WXLibraryPath  [WXUtility libraryDirectory]
  
  /**
   *  @abstract Returns the global cache whose size is 5M.
   *
   */
  + (NSCache *_Nonnull)globalCache;
  
  #define WXGlobalCache   [WXUtility globalCache]
  
  + (NSURL *_Nonnull)urlByDeletingParameters:(NSURL *_Nonnull)url;
  
  /**
   *  @abstract Returns the contents of file.
   *
   */
  + (NSString *_Nullable)stringWithContentsOfFile:(NSString *_Nonnull)filePath;
  
  /**
   *  @abstract Returns md5 string.
   *
   */
  + (NSString *_Nullable)md5:(NSString *_Nullable)string;
  
  /**
   *  @abstract Returns Creates a Universally Unique Identifier (UUID) string.
   *
   */
  + (NSString *_Nullable)uuidString;
  
  /**
   *  @abstract convert date string with formatter yyyy-MM-dd to date.
   *
   */
  + (NSDate *_Nullable)dateStringToDate:(NSString *_Nullable)dateString;
  
  /**
   *  @abstract convert time string with formatter HH:mm to date.
   *
   */
  + (NSDate *_Nullable)timeStringToDate:(NSString *_Nullable)timeString;
  
  /**
   *  @abstract convert date to date string with formatter yyyy-MM-dd .
   *
   */
  + (NSString *_Nullable)dateToString:(NSDate *_Nullable)date;
  
  /**
   *  @abstract convert date to time string with formatter HH:mm .
   *
   */
  + (NSString *_Nullable)timeToString:(NSDate *_Nullable)date;
  
  /**
   *  @abstract get the repeat substring number of string.
   *
   */
  + (NSUInteger)getSubStringNumber:(NSString *_Nullable)string subString:(NSString *_Nullable)subString;
  
  /**
   *  @abstract Returns a resized pixel which is calculated according to the WXScreenResizeRadio.
   *
   */
  CGFloat WXPixelScale(CGFloat value, CGFloat scaleFactor);
  
  CGFloat WXScreenResizeRadio(void) DEPRECATED_MSG_ATTRIBUTE("Use [WXUtility defaultPixelScaleFactor] instead");
  CGFloat WXPixelResize(CGFloat value) DEPRECATED_MSG_ATTRIBUTE("Use WXPixelScale Instead");
  CGRect WXPixelFrameResize(CGRect value) DEPRECATED_MSG_ATTRIBUTE("Use WXPixelScale Instead");
  CGPoint WXPixelPointResize(CGPoint value) DEPRECATED_MSG_ATTRIBUTE("Use WXPixelScale Instead");
  + (UIFont  * _Nullable )fontWithSize:(CGFloat)size textWeight:(CGFloat)textWeight textStyle:(WXTextStyle)textStyle fontFamily:(NSString * _Nullable)fontFamily DEPRECATED_MSG_ATTRIBUTE("Use +[WXUtility fontWithSize:textWeight:textStyle:fontFamily:scaleFactor:]");
  
  
  /**
   @discusstion construct a gradientLayer from the colors locations, gradientType
   @param colors The array of UIColor objects defining the color of each gradient
   stop. Defaults to nil
   @param locations An optional array of NSNumber objects defining the location of each
    gradient stop as a value in the range [0,1].
   @param frame the layer frame
   @param gradientType WXGradientType value specify the gradient location
   @return gradient layer
   */
  + (CAGradientLayer *_Nullable)gradientLayerFromColors:(NSArray*_Nullable)colors
                                             locations:(NSArray*_Nullable)locations
                                                 frame:(CGRect)frame
                                          gradientType:(WXGradientType)gradientType;
  
  /**
   @discusstion parse gradient-color string to a dictionary, then you can get gradientLayer from @see gradientLayerFromColors:colors:locations:frame:locations
   @param backgroundImage  linear-gradient string like linear-gradient(to right, #a80077,rgba(200, 54, 54, 0.5))
   @return dictionary with endColor, startColor and gradientType value
   @code
      NSDictionary * linearGradient = [self linearGradientWithBackgroundImage:@"linear-gradient(to right, #a80077,rgba(200, 54, 54, 0.5))"];
      CAGradientLayer * gradientLayer = [self gradientLayerFromColors:@[linearGradient[@"startColor"], linearGradient[@"endColor"]],nil,bounds,[linearGradient[@"gradientType"] integerValue]];
   @endcode
   */
  + (NSDictionary *_Nullable)linearGradientWithBackgroundImage:(NSString *_Nullable)backgroundImage;
  
  #if defined __cplusplus
  extern "C" {
  #endif
      
  /**
   *  @abstract compare float a and b, if a equal b, return true,or reture false.
   *
   */
  BOOL WXFloatEqual(CGFloat a, CGFloat b);
  /**
   *  @abstract compare float a and b, user give the compare precision, if a equal b, return true,or reture false.
   *
   */
  BOOL WXFloatEqualWithPrecision(CGFloat a, CGFloat b ,double precision);
  /**
   *  @abstract compare float a and b, if a less than b, return true,or reture false.
   *
   */
  BOOL WXFloatLessThan(CGFloat a, CGFloat b);
  /**
   *  @abstract compare float a and b,user give the compare precision, if a less than b,return true,or reture false.
   *
   */
  BOOL WXFloatLessThanWithPrecision(CGFloat a, CGFloat b,double precision);
  /**
   *  @abstract compare float a and b, if a great than b, return true,or reture false.
   *
   */
  BOOL WXFloatGreaterThan(CGFloat a, CGFloat b);
  /**
   *  @abstract compare float a and b, user give the compare precision,if a great than b, return true,or reture false.
   *
   */
  BOOL WXFloatGreaterThanWithPrecision(CGFloat a,CGFloat b,double precision);
  
  #if defined __cplusplus
  };
  #endif
  
  /**
   *  @abstract convert returnKeyType to type string .
   *
   */
  + (NSString *_Nullable)returnKeyType:(UIReturnKeyType)type;
  
  /**
   *  @abstract custorm monitor info
   *
   */
  + (void)customMonitorInfo:(WXSDKInstance *_Nullable)instance key:(NSString * _Nonnull)key value:(id _Nonnull)value;
  
  /**
   *  @abstract format to base64 dictionary
   *
   */
  + (NSDictionary *_Nonnull)dataToBase64Dict:(NSData *_Nullable)data;
  
  /**
   *  @abstract format to data
   *
   */
  + (NSData *_Nonnull)base64DictToData:(NSDictionary *_Nullable)base64Dict;
  
  /**
  *  @abstract Switch for RTL.
  *
  */
  + (void)setEnableRTLLayoutDirection:(BOOL)value;
  + (BOOL)enableRTLLayoutDirection;
  
  /**
  *  @abstract Switch for dark mode support.
  *
  */
  + (void)setDarkSchemeSupportEnable:(BOOL)value;
  + (BOOL)isDarkSchemeSupportEnabled;
  
  /**
  *  @abstract Switch for adapt iPad.
  *
  */
  + (void)setEnableAdaptiveLayout:(BOOL)value;
  + (BOOL)enableAdaptiveLayout;
  
  + (long) getUnixFixTimeMillis;
  
  + (long)getIntervalTime;
  
  + (NSArray<NSString *> *_Nullable)extractPropertyNamesOfJSValueObject:(JSValue *_Nullable)jsvalue;
  
  @end
  