export class ObjectUtil {
  static equals(o1: any, o2: any): boolean {
    if (o1 === o2) {
      return true;
    }
    if (o1 === null || o2 === null) {
      return false;
    }
    if (o1 !== o1 && o2 !== o2) {
      return true; // NaN === NaN
    }
    const t1 = typeof o1;
    const t2 = typeof o2;
    let length: number;
    let key: any;
    let keySet: any;
    if (t1 === t2 && t1 === 'object') {
      if (Array.isArray(o1)) {
        if (!Array.isArray(o2)) {
          return false;
        }
        length = o1.length;
        if (length === o2.length) {
          for (key = 0; key < length; key++) {
            if (!ObjectUtil.equals(o1[key], o2[key])) {
              return false;
            }
          }
          return true;
        }
      } else {
        if (Array.isArray(o2)) {
          return false;
        }
        keySet = Object.create(null);

        for (key in o1) {
          if (o1.hasOwnProperty(key)) {
            if (!ObjectUtil.equals(o1[key], o2[key])) {
              return false;
            }
            keySet[key] = true;
          }
        }

        for (key in o2) {
          if (!(key in keySet) && typeof o2[key] !== 'undefined') {
            return false;
          }
        }
        return true;
      }
    }
    return false;
  }
}
