"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

function _bluebird() {
  const data = require("bluebird");

  _bluebird = function () {
    return data;
  };

  return data;
}

function _defineProperty2() {
  const data = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));

  _defineProperty2 = function () {
    return data;
  };

  return data;
}

function _zlib() {
  const data = require("zlib");

  _zlib = function () {
    return data;
  };

  return data;
}

function _utils() {
  const data = require("../../utils");

  _utils = function () {
    return data;
  };

  return data;
}

function _constants() {
  const data = require("../../constants");

  _constants = function () {
    return data;
  };

  return data;
}

function _ref() {
  const data = _interopRequireDefault(require("./ref"));

  _ref = function () {
    return data;
  };

  return data;
}

// import logger from '../../logger/logger';
function parse(buffer, types) {
  const firstNullByteLocation = buffer.indexOf(_constants().NULL_BYTE);
  const headers = buffer.slice(0, firstNullByteLocation).toString();
  const contents = buffer.slice(firstNullByteLocation + 1, buffer.length);
  const [type] = headers.split(_constants().SPACE_DELIMITER);
  return types[type].parse(contents);
}

class BitObject {
  constructor() {
    (0, _defineProperty2().default)(this, "validateBeforePersist", true);
  }

  // validate the object before persisting
  id() {
    throw new Error('id() was not implemented...');
  } // eslint-disable-next-line no-unused-vars


  toBuffer(pretty) {
    throw new Error('toBuffer() was not implemented...');
  } // eslint-disable-next-line no-unused-vars


  static parse(data) {
    throw new Error('parse() was not implemented...');
  }

  refs() {
    return [];
  }

  getHeader(buffer) {
    return `${this.constructor.name} ${this.hash().toString()} ${buffer.toString().length}${_constants().NULL_BYTE}`;
  }

  collectRefs(repo) {
    var _this = this;

    return (0, _bluebird().coroutine)(function* () {
      const refsCollection = [];

      function addRefs(_x) {
        return _addRefs.apply(this, arguments);
      }

      function _addRefs() {
        _addRefs = (0, _bluebird().coroutine)(function* (object) {
          const refs = object.refs();
          const objs = yield Promise.all(refs.map(ref => ref.load(repo, true)));
          refsCollection.push(...refs); // $FlowFixMe

          yield Promise.all(objs.map(obj => addRefs(obj)));
        });
        return _addRefs.apply(this, arguments);
      }

      yield addRefs(_this);
      return refsCollection;
    })();
  }

  collectRaw(repo) {
    var _this2 = this;

    return (0, _bluebird().coroutine)(function* () {
      const refs = yield _this2.collectRefs(repo);
      return Promise.all(refs.map(ref => ref.loadRaw(repo)));
    })();
  }

  asRaw(repo) {
    return repo.loadRaw(this.hash());
  }

  collect(repo) {
    const objects = [];

    function addRefs(object) {
      const objs = object.refs().map(ref => {
        return ref.loadSync(repo);
      });
      objects.concat(objs); // $FlowFixMe

      objs.forEach(obj => addRefs(obj));
    }

    addRefs(this);
    return objects;
  }
  /**
   * indexing method
   */


  hash() {
    // console.log(`sha ${sha1(this.id())}, id ${this.id()}`); // uncomment when debugging hash issues
    return new (_ref().default)(BitObject.makeHash(this.id()));
  }

  compress() {
    return (0, _utils().deflate)(this.serialize());
  }

  serialize() {
    const buffer = this.toBuffer();
    return Buffer.concat([Buffer.from(this.getHeader(buffer)), buffer]);
  }
  /**
   * see `this.parseSync` for the sync version
   */


  static parseObject(fileContents, types) {
    return (0, _utils().inflate)(fileContents).then(buffer => parse(buffer, types));
  }
  /**
   * prefer using `this.parseObject()`, unless it must be sync.
   */


  static parseSync(fileContents, types) {
    const buffer = (0, _zlib().inflateSync)(fileContents);
    return parse(buffer, types);
  }

  static makeHash(str) {
    return (0, _utils().sha1)(str);
  }

}

exports.default = BitObject;