text: // Copyright (C) 2019-2020 Intel Corporation
  //
  // SPDX-License-Identifier: MIT
  
  (() => {
      const serverProxy = require('./server-proxy');
      const Collection = require('./annotations-collection');
      const AnnotationsSaver = require('./annotations-saver');
      const AnnotationsHistory = require('./annotations-history');
      const { checkObjectType } = require('./common');
      const { Task } = require('./session');
      const { Loader, Dumper } = require('./annotation-formats');
      const { ScriptingError, DataError, ArgumentError } = require('./exceptions');
      const i18next = require('i18next').default;
  
      const jobCache = new WeakMap();
      const taskCache = new WeakMap();
  
      function getCache(sessionType) {
          if (sessionType === 'task') {
              return taskCache;
          }
  
          if (sessionType === 'job') {
              return jobCache;
          }
  
          throw new ScriptingError(i18next.t('Unknown session type was received ${sessionType}',{sessionType: `${sessionType}`}));
      }
  
      async function getAnnotationsFromServer(session) {
          const sessionType = session instanceof Task ? 'task' : 'job';
          const cache = getCache(sessionType);
  
          if (!cache.has(session)) {
              const rawAnnotations = await serverProxy.annotations.getAnnotations(sessionType, session.id);
  
              // Get meta information about frames
              const startFrame = sessionType === 'job' ? session.startFrame : 0;
              const stopFrame = sessionType === 'job' ? session.stopFrame : session.size - 1;
              const frameMeta = {};
              for (let i = startFrame; i <= stopFrame; i++) {
                  frameMeta[i] = await session.frames.get(i);
              }
  
              const history = new AnnotationsHistory();
              const collection = new Collection({
                  labels: session.labels || session.task.labels,
                  history,
                  startFrame,
                  stopFrame,
                  frameMeta,
              });
              collection.import(rawAnnotations);
  
              const saver = new AnnotationsSaver(rawAnnotations.version, collection, session);
  
              cache.set(session, {
                  collection,
                  saver,
                  history,
              });
          }
      }
  
      async function closeSession(session) {
          const sessionType = session instanceof Task ? 'task' : 'job';
          const cache = getCache(sessionType);
  
          if (cache.has(session)) {
              cache.delete(session);
          }
      }
  
      async function getAnnotations(session, frame, allTracks, filters) {
          const sessionType = session instanceof Task ? 'task' : 'job';
          const cache = getCache(sessionType);
  
          if (cache.has(session)) {
              return cache.get(session).collection.get(frame, allTracks, filters);
          }
  
          await getAnnotationsFromServer(session);
          return cache.get(session).collection.get(frame, allTracks, filters);
      }
  
      async function saveAnnotations(session, onUpdate) {
          const sessionType = session instanceof Task ? 'task' : 'job';
          const cache = getCache(sessionType);
  
          if (cache.has(session)) {
              await cache.get(session).saver.save(onUpdate);
          }
  
          // If a collection wasn't uploaded, than it wasn't changed, finally we shouldn't save it
      }
  
      function searchAnnotations(session, filters, frameFrom, frameTo) {
          const sessionType = session instanceof Task ? 'task' : 'job';
          const cache = getCache(sessionType);
  
          if (cache.has(session)) {
              return cache.get(session).collection.search(filters, frameFrom, frameTo);
          }
  
          throw new DataError(
              i18next.t('Collection has not been initialized yet. Call annotations.get() or annotations.clear(true) before'),
          );
      }
  
      function searchEmptyFrame(session, frameFrom, frameTo) {
          const sessionType = session instanceof Task ? 'task' : 'job';
          const cache = getCache(sessionType);
  
          if (cache.has(session)) {
              return cache.get(session).collection.searchEmpty(frameFrom, frameTo);
          }
  
          throw new DataError(
              i18next.t('Collection has not been initialized yet. Call annotations.get() or annotations.clear(true) before'),
          );
      }
  
      function mergeAnnotations(session, objectStates) {
          const sessionType = session instanceof Task ? 'task' : 'job';
          const cache = getCache(sessionType);
  
          if (cache.has(session)) {
              return cache.get(session).collection.merge(objectStates);
          }
  
          throw new DataError(
              i18next.t('Collection has not been initialized yet. Call annotations.get() or annotations.clear(true) before'),
          );
      }
  
      function splitAnnotations(session, objectState, frame) {
          const sessionType = session instanceof Task ? 'task' : 'job';
          const cache = getCache(sessionType);
  
          if (cache.has(session)) {
              return cache.get(session).collection.split(objectState, frame);
          }
  
          throw new DataError(
              i18next.t('Collection has not been initialized yet. Call annotations.get() or annotations.clear(true) before'),
          );
      }
  
      function groupAnnotations(session, objectStates, reset) {
          const sessionType = session instanceof Task ? 'task' : 'job';
          const cache = getCache(sessionType);
  
          if (cache.has(session)) {
              return cache.get(session).collection.group(objectStates, reset);
          }
  
          throw new DataError(
              i18next.t('Collection has not been initialized yet. Call annotations.get() or annotations.clear(true) before'),
          );
      }
  
      function hasUnsavedChanges(session) {
          const sessionType = session instanceof Task ? 'task' : 'job';
          const cache = getCache(sessionType);
  
          if (cache.has(session)) {
              return cache.get(session).saver.hasUnsavedChanges();
          }
  
          return false;
      }
  
      async function clearAnnotations(session, reload) {
          checkObjectType('reload', reload, 'boolean', null);
          const sessionType = session instanceof Task ? 'task' : 'job';
          const cache = getCache(sessionType);
  
          if (cache.has(session)) {
              cache.get(session).collection.clear();
          }
  
          if (reload) {
              cache.delete(session);
              await getAnnotationsFromServer(session);
          }
      }
  
      function annotationsStatistics(session) {
          const sessionType = session instanceof Task ? 'task' : 'job';
          const cache = getCache(sessionType);
  
          if (cache.has(session)) {
              return cache.get(session).collection.statistics();
          }
  
          throw new DataError(
              i18next.t('Collection has not been initialized yet. Call annotations.get() or annotations.clear(true) before'),
          );
      }
  
      function putAnnotations(session, objectStates) {
          const sessionType = session instanceof Task ? 'task' : 'job';
          const cache = getCache(sessionType);
  
          if (cache.has(session)) {
              return cache.get(session).collection.put(objectStates);
          }
  
          throw new DataError(
              i18next.t('Collection has not been initialized yet. Call annotations.get() or annotations.clear(true) before'),
          );
      }
  
      function selectObject(session, objectStates, x, y) {
          const sessionType = session instanceof Task ? 'task' : 'job';
          const cache = getCache(sessionType);
  
          if (cache.has(session)) {
              return cache.get(session).collection.select(objectStates, x, y);
          }
  
          throw new DataError(
              i18next.t('Collection has not been initialized yet. Call annotations.get() or annotations.clear(true) before'),
          );
      }
  
      async function uploadAnnotations(session, file, loader) {
          const sessionType = session instanceof Task ? 'task' : 'job';
          if (!(loader instanceof Loader)) {
              throw new ArgumentError(i18next.t('A loader must be instance of Loader class'));
          }
          await serverProxy.annotations.uploadAnnotations(sessionType, session.id, file, loader.name);
      }
  
      async function dumpAnnotations(session, name, dumper) {
          if (!(dumper instanceof Dumper)) {
              throw new ArgumentError(i18next.t('A dumper must be instance of Dumper class'));
          }
  
          let result = null;
          const sessionType = session instanceof Task ? 'task' : 'job';
          if (sessionType === 'job') {
              result = await serverProxy.annotations.dumpAnnotations(session.task.id, name, dumper.name);
          } else {
              result = await serverProxy.annotations.dumpAnnotations(session.id, name, dumper.name);
          }
  
          return result;
      }
  
      function importAnnotations(session, data) {
          const sessionType = session instanceof Task ? 'task' : 'job';
          const cache = getCache(sessionType);
  
          if (cache.has(session)) {
              return cache.get(session).collection.import(data);
          }
  
          throw new DataError(
              i18next.t('Collection has not been initialized yet. Call annotations.get() or annotations.clear(true) before'),
          );
      }
  
      function exportAnnotations(session) {
          const sessionType = session instanceof Task ? 'task' : 'job';
          const cache = getCache(sessionType);
  
          if (cache.has(session)) {
              return cache.get(session).collection.export();
          }
  
          throw new DataError(
              i18next.t('Collection has not been initialized yet. Call annotations.get() or annotations.clear(true) before'),
          );
      }
  
      async function exportDataset(session, format) {
          if (!(format instanceof String || typeof format === 'string')) {
              throw new ArgumentError(i18next.t('Format must be a string'));
          }
          if (!(session instanceof Task)) {
              throw new ArgumentError(i18next.t('A dataset can only be created from a task'));
          }
  
          let result = null;
          result = await serverProxy.tasks.exportDataset(session.id, format);
  
          return result;
      }
  
      function undoActions(session, count) {
          const sessionType = session instanceof Task ? 'task' : 'job';
          const cache = getCache(sessionType);
  
          if (cache.has(session)) {
              return cache.get(session).history.undo(count);
          }
  
          throw new DataError(
              i18next.t('Collection has not been initialized yet. Call annotations.get() or annotations.clear(true) before'),
          );
      }
  
      function redoActions(session, count) {
          const sessionType = session instanceof Task ? 'task' : 'job';
          const cache = getCache(sessionType);
  
          if (cache.has(session)) {
              return cache.get(session).history.redo(count);
          }
  
          throw new DataError(
              i18next.t('Collection has not been initialized yet. Call annotations.get() or annotations.clear(true) before'),
          );
      }
  
      function freezeHistory(session, frozen) {
          const sessionType = session instanceof Task ? 'task' : 'job';
          const cache = getCache(sessionType);
  
          if (cache.has(session)) {
              return cache.get(session).history.freeze(frozen);
          }
  
          throw new DataError(
              i18next.t('Collection has not been initialized yet. Call annotations.get() or annotations.clear(true) before'),
          );
      }
  
      function clearActions(session) {
          const sessionType = session instanceof Task ? 'task' : 'job';
          const cache = getCache(sessionType);
  
          if (cache.has(session)) {
              return cache.get(session).history.clear();
          }
  
          throw new DataError(
              i18next.t('Collection has not been initialized yet. Call annotations.get() or annotations.clear(true) before'),
          );
      }
  
      function getActions(session) {
          const sessionType = session instanceof Task ? 'task' : 'job';
          const cache = getCache(sessionType);
  
          if (cache.has(session)) {
              return cache.get(session).history.get();
          }
  
          throw new DataError(
              i18next.t('Collection has not been initialized yet. Call annotations.get() or annotations.clear(true) before'),
          );
      }
  
      module.exports = {
          getAnnotations,
          putAnnotations,
          saveAnnotations,
          hasUnsavedChanges,
          mergeAnnotations,
          searchAnnotations,
          searchEmptyFrame,
          splitAnnotations,
          groupAnnotations,
          clearAnnotations,
          annotationsStatistics,
          selectObject,
          uploadAnnotations,
          dumpAnnotations,
          importAnnotations,
          exportAnnotations,
          exportDataset,
          undoActions,
          redoActions,
          freezeHistory,
          clearActions,
          getActions,
          closeSession,
      };
  })();
  