/* eslint-disable */
/**
 * @fileOverview
 *
 *
 *
 * @author: techird
 * @copyright: Baidu FEX, 2014
 */

define(function (require, exports, module) {
  /*!
   * https://github.com/Starcounter-Jack/Fast-JSON-Patch
   * json-patch-duplex.js 0.5.0
   * (c) 2013 Joachim Wester
   * MIT license
   */

  var _objectKeys = (function () {
    if (Object.keys) return Object.keys;

    return function (o) {
      var keys = [];
      for (var i in o) {
        if (o.hasOwnProperty(i)) {
          keys.push(i);
        }
      }
      return keys;
    };
  })();
  function escapePathComponent(str) {
    if (str.indexOf('/') === -1 && str.indexOf('~') === -1) return str;
    return str.replace(/~/g, '~0').replace(/\//g, '~1');
  }
  function deepClone(obj) {
    if (typeof obj === 'object') {
      return JSON.parse(JSON.stringify(obj));
    } else {
      return obj;
    }
  }

  // Dirty check if obj is different from mirror, generate patches and update mirror
  function _generate(mirror, obj, patches, path) {
    var newKeys = _objectKeys(obj);
    var oldKeys = _objectKeys(mirror);
    var changed = false;
    var deleted = false;

    for (var t = oldKeys.length - 1; t >= 0; t--) {
      var key = oldKeys[t];
      var oldVal = mirror[key];
      if (obj.hasOwnProperty(key)) {
        var newVal = obj[key];
        if (typeof oldVal == 'object' && oldVal != null && typeof newVal == 'object' && newVal != null) {
          _generate(oldVal, newVal, patches, path + '/' + escapePathComponent(key));
        } else {
          if (oldVal != newVal) {
            changed = true;
            patches.push({ op: 'replace', path: path + '/' + escapePathComponent(key), value: deepClone(newVal) });
          }
        }
      } else {
        patches.push({ op: 'remove', path: path + '/' + escapePathComponent(key) });
        deleted = true; // property has been deleted
      }
    }

    if (!deleted && newKeys.length == oldKeys.length) {
      return;
    }

    for (var t = 0; t < newKeys.length; t++) {
      var key = newKeys[t];
      if (!mirror.hasOwnProperty(key)) {
        patches.push({ op: 'add', path: path + '/' + escapePathComponent(key), value: deepClone(obj[key]) });
      }
    }
  }

  function compare(tree1, tree2) {
    var patches = [];
    _generate(tree1, tree2, patches, '');
    return patches;
  }

  return (module.exports = compare);
});
