text: /*
  * Copyright (C) 2019 Intel Corporation
  * SPDX-License-Identifier: MIT
  */
  
  /* global
      require:false
  */
  
  (() => {
      const PluginRegistry = require('./plugins');
      const { ArgumentError } = require('./exceptions');
  
      /**
          * Class representing a state of an object on a specific frame
          * @memberof module:API.cvat.classes
      */
      class ObjectState {
          /**
              * @param {Object} serialized - is an dictionary which contains
              * initial information about an ObjectState;
              * </br> Necessary fields: objectType, shapeType, frame, updated, group
              * </br> Optional fields: keyframes, clientID, serverID
              * </br> Optional fields which can be set later: points, zOrder, outside,
              * occluded, hidden, attributes, lock, label, color, keyframe
          */
          constructor(serialized) {
              const data = {
                  label: null,
                  attributes: {},
  
                  points: null,
                  outside: null,
                  occluded: null,
                  keyframe: null,
  
                  zOrder: null,
                  lock: null,
                  color: null,
                  hidden: null,
                  pinned: null,
                  keyframes: serialized.keyframes,
                  group: serialized.group,
                  updated: serialized.updated,
  
                  clientID: serialized.clientID,
                  serverID: serialized.serverID,
  
                  frame: serialized.frame,
                  objectType: serialized.objectType,
                  shapeType: serialized.shapeType,
                  updateFlags: {},
              };
  
              // Shows whether any properties updated since last reset() or interpolation
              Object.defineProperty(data.updateFlags, 'reset', {
                  value: function reset() {
                      this.label = false;
                      this.attributes = false;
  
                      this.points = false;
                      this.outside = false;
                      this.occluded = false;
                      this.keyframe = false;
  
                      this.zOrder = false;
                      this.pinned = false;
                      this.lock = false;
                      this.color = false;
                      this.hidden = false;
  
                      return reset;
                  },
                  writable: false,
              });
  
              Object.defineProperties(this, Object.freeze({
                  // Internal property. We don't need document it.
                  updateFlags: {
                      get: () => data.updateFlags,
                  },
                  frame: {
                      /**
                          * @name frame
                          * @type {integer}
                          * @memberof module:API.cvat.classes.ObjectState
                          * @readonly
                          * @instance
                      */
                      get: () => data.frame,
                  },
                  objectType: {
                      /**
                          * @name objectType
                          * @type {module:API.cvat.enums.ObjectType}
                          * @memberof module:API.cvat.classes.ObjectState
                          * @readonly
                          * @instance
                      */
                      get: () => data.objectType,
                  },
                  shapeType: {
                      /**
                          * @name shapeType
                          * @type {module:API.cvat.enums.ObjectShape}
                          * @memberof module:API.cvat.classes.ObjectState
                          * @readonly
                          * @instance
                      */
                      get: () => data.shapeType,
                  },
                  clientID: {
                      /**
                          * @name clientID
                          * @type {integer}
                          * @memberof module:API.cvat.classes.ObjectState
                          * @readonly
                          * @instance
                      */
                      get: () => data.clientID,
                  },
                  serverID: {
                      /**
                          * @name serverID
                          * @type {integer}
                          * @memberof module:API.cvat.classes.ObjectState
                          * @readonly
                          * @instance
                      */
                      get: () => data.serverID,
                  },
                  label: {
                      /**
                          * @name shape
                          * @type {module:API.cvat.classes.Label}
                          * @memberof module:API.cvat.classes.ObjectState
                          * @instance
                      */
                      get: () => data.label,
                      set: (labelInstance) => {
                          data.updateFlags.label = true;
                          data.label = labelInstance;
                      },
                  },
                  color: {
                      /**
                          * @name color
                          * @type {string}
                          * @memberof module:API.cvat.classes.ObjectState
                          * @instance
                      */
                      get: () => data.color,
                      set: (color) => {
                          data.updateFlags.color = true;
                          data.color = color;
                      },
                  },
                  hidden: {
                      /**
                          * @name hidden
                          * @type {boolean}
                          * @memberof module:API.cvat.classes.ObjectState
                          * @instance
                      */
                      get: () => data.hidden,
                      set: (hidden) => {
                          data.updateFlags.hidden = true;
                          data.hidden = hidden;
                      },
                  },
                  points: {
                      /**
                          * @name points
                          * @type {number[]}
                          * @memberof module:API.cvat.classes.ObjectState
                          * @throws {module:API.cvat.exceptions.ArgumentError}
                          * @instance
                      */
                      get: () => data.points,
                      set: (points) => {
                          if (Array.isArray(points)) {
                              data.updateFlags.points = true;
                              data.points = [...points];
                          } else {
                              throw new ArgumentError(
                                  'Points are expected to be an array '
                                      + `but got ${typeof (points) === 'object'
                                          ? points.constructor.name : typeof (points)}`,
                              );
                          }
                      },
                  },
                  group: {
                      /**
                          * Object with short group info { color, id }
                          * @name group
                          * @type {object}
                          * @memberof module:API.cvat.classes.ObjectState
                          * @instance
                          * @readonly
                      */
                      get: () => data.group,
                  },
                  zOrder: {
                      /**
                          * @name zOrder
                          * @type {integer | null}
                          * @memberof module:API.cvat.classes.ObjectState
                          * @instance
                      */
                      get: () => data.zOrder,
                      set: (zOrder) => {
                          data.updateFlags.zOrder = true;
                          data.zOrder = zOrder;
                      },
                  },
                  outside: {
                      /**
                          * @name outside
                          * @type {boolean}
                          * @memberof module:API.cvat.classes.ObjectState
                          * @instance
                      */
                      get: () => data.outside,
                      set: (outside) => {
                          data.updateFlags.outside = true;
                          data.outside = outside;
                      },
                  },
                  keyframe: {
                      /**
                          * @name keyframe
                          * @type {boolean}
                          * @memberof module:API.cvat.classes.ObjectState
                          * @instance
                      */
                      get: () => data.keyframe,
                      set: (keyframe) => {
                          data.updateFlags.keyframe = true;
                          data.keyframe = keyframe;
                      },
                  },
                  keyframes: {
                      /**
                          * Object of keyframes { first, prev, next, last }
                          * @name keyframes
                          * @type {object | null}
                          * @memberof module:API.cvat.classes.ObjectState
                          * @readonly
                          * @instance
                      */
                      get: () => {
                          if (typeof (data.keyframes) === 'object') {
                              return { ...data.keyframes };
                          }
  
                          return null;
                      },
                  },
                  occluded: {
                      /**
                          * @name occluded
                          * @type {boolean}
                          * @memberof module:API.cvat.classes.ObjectState
                          * @instance
                      */
                      get: () => data.occluded,
                      set: (occluded) => {
                          data.updateFlags.occluded = true;
                          data.occluded = occluded;
                      },
                  },
                  lock: {
                      /**
                          * @name lock
                          * @type {boolean}
                          * @memberof module:API.cvat.classes.ObjectState
                          * @instance
                      */
                      get: () => data.lock,
                      set: (lock) => {
                          data.updateFlags.lock = true;
                          data.lock = lock;
                      },
                  },
                  pinned: {
                      /**
                          * @name pinned
                          * @type {boolean | null}
                          * @memberof module:API.cvat.classes.ObjectState
                          * @instance
                      */
                      get: () => {
                          if (typeof (data.pinned) === 'boolean') {
                              return data.pinned;
                          }
  
                          return null;
                      },
                      set: (pinned) => {
                          data.updateFlags.pinned = true;
                          data.pinned = pinned;
                      },
                  },
                  updated: {
                      /**
                          * Timestamp of the latest updated of the object
                          * @name updated
                          * @type {number}
                          * @memberof module:API.cvat.classes.ObjectState
                          * @instance
                          * @readonly
                      */
                      get: () => data.updated,
                  },
                  attributes: {
                      /**
                          * Object is id:value pairs where "id" is an integer
                          * attribute identifier and "value" is an attribute value
                          * @name attributes
                          * @type {Object}
                          * @memberof module:API.cvat.classes.ObjectState
                          * @throws {module:API.cvat.exceptions.ArgumentError}
                          * @instance
                      */
                      get: () => data.attributes,
                      set: (attributes) => {
                          if (typeof (attributes) !== 'object') {
                              throw new ArgumentError(
                                  'Attributes are expected to be an object '
                                      + `but got ${typeof (attributes) === 'object'
                                          ? attributes.constructor.name : typeof (attributes)}`,
                              );
                          }
  
                          for (const attrID of Object.keys(attributes)) {
                              data.updateFlags.attributes = true;
                              data.attributes[attrID] = attributes[attrID];
                          }
                      },
                  },
              }));
  
              this.label = serialized.label;
              this.lock = serialized.lock;
  
              if (typeof (serialized.zOrder) === 'number') {
                  this.zOrder = serialized.zOrder;
              }
              if (typeof (serialized.occluded) === 'boolean') {
                  this.occluded = serialized.occluded;
              }
              if (typeof (serialized.outside) === 'boolean') {
                  this.outside = serialized.outside;
              }
              if (typeof (serialized.keyframe) === 'boolean') {
                  this.keyframe = serialized.keyframe;
              }
              if (typeof (serialized.pinned) === 'boolean') {
                  this.pinned = serialized.pinned;
              }
              if (typeof (serialized.hidden) === 'boolean') {
                  this.hidden = serialized.hidden;
              }
              if (typeof (serialized.color) === 'string') {
                  this.color = serialized.color;
              }
              if (Array.isArray(serialized.points)) {
                  this.points = serialized.points;
              }
              if (typeof (serialized.attributes) === 'object') {
                  this.attributes = serialized.attributes;
              }
  
              data.updateFlags.reset();
          }
  
          /**
              * Method saves/updates an object state in a collection
              * @method save
              * @memberof module:API.cvat.classes.ObjectState
              * @readonly
              * @instance
              * @async
              * @throws {module:API.cvat.exceptions.PluginError}
              * @throws {module:API.cvat.exceptions.ArgumentError}
              * @returns {module:API.cvat.classes.ObjectState} updated state of an object
          */
          async save() {
              const result = await PluginRegistry
                  .apiWrapper.call(this, ObjectState.prototype.save);
              return result;
          }
  
          /**
              * Method deletes an object from a collection
              * @method delete
              * @memberof module:API.cvat.classes.ObjectState
              * @readonly
              * @instance
              * @param {integer} frame current frame number
              * @param {boolean} [force=false] delete object even if it is locked
              * @async
              * @returns {boolean} true if object has been deleted
              * @throws {module:API.cvat.exceptions.PluginError}
              * @throws {module:API.cvat.exceptions.ArgumentError}
          */
          async delete(frame, force = false) {
              const result = await PluginRegistry
                  .apiWrapper.call(this, ObjectState.prototype.delete, frame, force);
              return result;
          }
      }
  
      // Updates element in collection which contains it
      ObjectState.prototype.save.implementation = async function () {
          if (this.__internal && this.__internal.save) {
              return this.__internal.save();
          }
  
          return this;
      };
  
      // Delete element from a collection which contains it
      ObjectState.prototype.delete.implementation = async function (frame, force) {
          if (this.__internal && this.__internal.delete) {
              if (!Number.isInteger(+frame) || +frame < 0) {
                  throw new ArgumentError('Frame argument must be a non negative integer');
              }
  
              return this.__internal.delete(frame, force);
          }
  
          return false;
      };
  
      module.exports = ObjectState;
  })();
  