/* automatically generated by JSInstrument */

/*

* create %{js_object_name} as a global object
*/

!function(root){

if (root && (typeof root.%{js_object_name} === 'undefined')) {
  root.%{js_object_name} = {
    /**
     * Const for coverage data types
     */
    TYPES: ['line', 'func', 'branch'],
    /**
     * Coverage data
     * data = {
     *   filename: {
     *     line: [lines],
     *     func: [lines],
     *     branch: [lines]
     *   }
     * }
     */
    data: {},
    /**
     * register instrumented lines for the file
     */
    register: function(file, lines, func_lines, branch_lines) {
      // replace the dot in the filename by underscore to be competible with mongodb
      file = file.replace(/\./g, '_')
      // can't register twice for one file
      if(!this.data[file]) {
        this.data[file] = {
          line: [],
          func: [],
          branch: []
        };
        for (var i in lines) {
          this.data[file].line[lines[i]] = 0;
        }
        for (var i in func_lines) {
          this.data[file].func[func_lines[i]] = 0;
        }
        for (var i in branch_lines) {
          this.data[file].branch[branch_lines[i]] = 0;
        }
      }
    },
    /**
     * Hit a data
     */
    _hit: function(type, file, line) {
      if (file && (this.TYPES.indexOf(type) !== -1)) {
        file = file.replace(/\./g, '_');
        if (this.data[file] && this.data[file][type]) {
          this.data[file][type][line] = (this.data[file][type][line]) ? (this.data[file][type][line] + 1) : 1;
        }
      }
    },
    /**
     * Hit a line
     */
    hit_line: function(file, line) {
      this._hit('line', file, line);
    },
    /**
     * Hit a func
     */
    hit_func: function(file, line) {
      this._hit('func', file, line);
    },
    /**
     * Hit a branch
     */
    hit_branch: function(file, line) {
      this._hit('branch', file, line);
    },
    /**
     * Upload coverage data to server
     */
    upload: function(mark, case_name, case_action, force) {
      // if uploading
      if(!force && this._uploading) return;

      var self = this;
      this._uploading = true;

      try {
        $.post('%{upload_url}', this.serialize(mark, case_name, case_action)).done(function() {
          // data uploaded
        }).always(function() {
          self._uploading = false;
        });
      } catch (e) {
        this._uploading = false;
      }
    },
    /**
     * force upload despite if it is uploading
     */
    force_upload: function(mark, case_name, case_action) {
      this.upload(mark, case_name, case_action, true);
    },
    /**
     * serialize data for data uploading
     */
    serialize: function(mark, case_name, case_action) {
      var data = this.data;
      var json = [];

      for (var file in data) {
        var file_json = [];

        for (var i in this.TYPES) {
          var type = this.TYPES[i];
          var type_coverage = data[file][type];

          var array = [];
          var length = type_coverage.length;
          for (var line = 0; line < length; line++) {
            var value = type_coverage[line];
            if (value === undefined || value === null) {
              value = '';
            }
            array.push(value);
          }
          file_json.push(this._quote(type) + ':[' + array.join(',') + ']');
        }

        json.push(this._quote(file) + ':{' + file_json.join(',') + '}');
      }

      var result = '{' + json.join(',') + '}';

      var r = {
        project: '%{project_name}',
        commit: '%{commit_hash}',
        batch: '%{batch_text}',
        mark: mark,
        case_name: case_name,
        case_action: case_action,
        data: result
      }

      /**
       * data compress method for uploading
       * false or undefined to disable data compress
       */
      var data_compress_method = %{data_compress_method};
      if (data_compress_method) {
        var result_compressed = data_compress_method(result);
        var result_encoded = btoa(result_compressed);
        r.data_compressed = true;
        r.data = result_encoded;
      }

      return r;
    },
    _quote: function(s) {
      var pad = function(s) {
        return '0000'.substr(s.length) + s;
      }
      return '"' + s.replace(/[\u0000-\u001f"\\\u007f-\uffff]/g, function (c) {
        switch (c) {
          case '\b': return '\\b';
          case '\f': return '\\f';
          case '\n': return '\\n';
          case '\r': return '\\r';
          case '\t': return '\\t';
          case '"': return '\\"';
          case '\\': return '\\\\';
          default: return '\\u' + pad(c.charCodeAt(0).toString(16));
        }
      }) + '"';
    }
  };
}

// register the instrumented lines for current file
root.%{js_object_name}.register('%{src_filename}',
  // line coverage
  %{instrumented_lines},
  // function coverage
  %{instrumented_func_lines},
  // branch coverage
  %{instrumented_branch_lines}
);

}(this);