"use strict";

function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
var ObjectId = require('bson').ObjectID;
var clone = require('clone');
var tv4 = require('tv4');
var DocumentSection = require('./document-section');
var TemplateReference = require('./template-reference');
var CheckboxCard = require('./checkbox-card');
var ConditionCard = require('./condition-card');
var ChemicalCard = require('./chemical-card');
var EquipmentCard = require('./equipment-card');
var InspectCard = require('./inspect-card');
var FileReference = require('./file-reference');
var ReferenceCard = require('./reference-card');
var TextCard = require('./text-card');
var Access = require('../common/access');
var PersonReference = require('../core/person-reference');
var ACCESS_PERMISSION = require('../../constant/common/access-permission.constant');
var CARD_TYPE = require('../../constant/procedure/card-type.constant');
var DOCUMENT_STATUS = require('../../constant/procedure/document-status.constant');
var Helper = require('../../helper/helper');
var Document = /*#__PURE__*/function () {
  function Document(opt) {
    _classCallCheck(this, Document);
    this._id = new ObjectId();
    this.seriesId = null;
    this.revision = 0;
    this.template = null;
    this.title = null;
    this.description = null;
    this.sections = [];
    this.status = DOCUMENT_STATUS.DRAFT;
    this.access = [];
    this.acknowledgement = {
      acknowledgeLabel: 'Acknowledged by:',
      prompt: 'I have read and understood this document',
      requiredSignatures: [],
      signatures: [],
      showAcknowledgement: false
    };
    this.createdBy = null;
    this.createdDate = null;
    this.lastModifiedBy = null;
    this.lastModifiedDate = null;
    this.expirationDate = null;
    this.readyForUseDate = null;
    this.readyForUseBy = null;
    this.label = {};
    this.workflowSteps = [];
    this.family = [];
    this.band = [];
    this.printedDate = null;
    if (opt) {
      this.fillObject(clone(opt));
    }
  }
  _createClass(Document, [{
    key: "fillObject",
    value: function fillObject(opt) {
      var _this = this;
      this._id = new ObjectId(opt._id);
      this.seriesId = new ObjectId(opt.seriesId);
      this.revision = opt.revision || this.revision;
      this.template = new TemplateReference(opt.template);
      this.title = opt.title ? opt.title : null;
      this.description = opt.description ? opt.description : null;
      this.access = opt.access && opt.access.length ? opt.access.map(function (item) {
        return new Access(item);
      }) : [];
      this.createdBy = opt.createdBy ? new PersonReference(opt.createdBy) : null;
      this.createdDate = opt.createdDate ? new Date(opt.createdDate) : null;
      this.lastModifiedBy = opt.lastModifiedBy ? new PersonReference(opt.lastModifiedBy) : null;
      this.lastModifiedDate = opt.lastModifiedDate ? new Date(opt.lastModifiedDate) : null;
      this.status = opt.status ? opt.status : DOCUMENT_STATUS.DRAFT;
      this.expirationDate = opt.expirationDate ? new Date(opt.expirationDate) : null;
      this.readyForUseDate = opt.readyForUseDate ? new Date(opt.readyForUseDate) : null;
      this.readyForUseBy = opt.readyForUseBy ? new PersonReference(opt.readyForUseBy) : null;
      this.workflowSteps = opt.workflowSteps ? opt.workflowSteps : [DOCUMENT_STATUS.DRAFT, DOCUMENT_STATUS.READY_FOR_USE];
      if (opt.acknowledgement) {
        this.acknowledgement.prompt = opt.acknowledgement.prompt || this.acknowledgement.prompt;
        this.acknowledgement.acknowledgeLabel = opt.acknowledgement.acknowledgeLabel || this.acknowledgement.acknowledgeLabel;
        if (Array.isArray(opt.acknowledgement.signatures)) {
          this.acknowledgement.signatures = this.acknowledgement.signatures.concat(opt.acknowledgement.signatures.map(function (signature) {
            return {
              person: new PersonReference(signature.person),
              date: signature.date ? new Date(signature.date) : new Date()
            };
          }));
        }
        if (Array.isArray(opt.acknowledgement.requiredSignatures)) {
          this.acknowledgement.requiredSignatures = this.acknowledgement.requiredSignatures.concat(opt.acknowledgement.requiredSignatures.map(function (signature) {
            return {
              person: new PersonReference(signature.person),
              hasSigned: !!_this.acknowledgement.signatures.some(function (sig) {
                return sig.person.userId === signature.person.userId;
              })
            };
          }));
        }
        this.acknowledgement.showAcknowledgement = opt.acknowledgement.showAcknowledgement || false;
      }
      if (opt.sections) {
        opt.sections.forEach(function (section) {
          _this.sections.push(new DocumentSection(section));
        });
      }
      if (opt.label) {
        var label = Object.keys(opt.label).reduce(function (acc, cur) {
          if (!cur.match('band:') && !cur.match('family:')) {
            acc[cur] = opt.label[cur];
          }
          return acc;
        }, {});
        this.label = _objectSpread(_objectSpread({}, label), this.getLabel());
      } else {
        this.label = {};
      }
      this.printedDate = opt.createdDate ? new Date(opt.createdDate) : null;
    }
  }, {
    key: "setExpirationDate",
    value: function setExpirationDate(duration) {
      var expirationDate = new Date();
      expirationDate.setHours(0, 0, 0, 0);
      expirationDate.setDate(expirationDate.getDate() + duration);
      this.expirationDate = expirationDate;
    }
  }, {
    key: "validate",
    value: function validate() {
      var validation = tv4.validateMultiple(this, Document.schema());
      var labelIsValid = Helper.validateLabel(this.label);
      if (!labelIsValid) {
        validation.errors.push(new Error('Invalid type (expecting string, boolean or number) for values on label'));
        validation.valid = false;
      }
      return validation;
    }
  }, {
    key: "calculateCounts",
    value: function calculateCounts() {
      var count = {};
      this.sections.forEach(function (section) {
        section.cards.forEach(function (card) {
          if (card.details.countLabel) {
            count[card.details.countLabel] = (count[card.details.countLabel] || 0) + card.details.count;
          } else if (card.type === 'CONDITION') {
            count = card.calculateCounts(count);
          }
        });
      });
      var labels = Object.keys(count);
      var counts = labels.map(function (label) {
        return count[label];
      });
      return {
        labels: labels,
        counts: counts
      };
    }
  }, {
    key: "getLabel",
    value: function getLabel() {
      var _this2 = this;
      var label = _objectSpread({}, this.label);
      this.sections.forEach(function (section) {
        section.cards.forEach(function (card) {
          if (typeof card.getLabel === 'function') {
            switch (card.type) {
              case 'CHEMICAL':
                _this2.family = _this2.family.concat(card.getLabel());
                break;
              case 'CHEMICAL_BAND':
                _this2.band = _this2.band.concat(card.getLabel());
                break;
              default:
                label = _objectSpread(_objectSpread({}, label), card.getLabel());
                break;
            }
          }
        });
      });
      return label;
    }
  }], [{
    key: "schema",
    value: function schema() {
      return {
        $schema: 'http://json-schema.org/draft-04/schema#',
        id: 'document.schema.json',
        type: 'object',
        additionalProperties: false,
        properties: {
          _id: {
            type: ['object', 'null']
          },
          seriesId: {
            type: 'object'
          },
          revision: {
            type: 'integer'
          },
          template: {
            $ref: 'template-reference.schema.json'
          },
          title: {
            type: 'string'
          },
          description: {
            type: ['string', 'null']
          },
          access: {
            type: 'array',
            item: {
              $ref: 'access.schema.json'
            }
          },
          acknowledgement: {
            type: 'object',
            properties: {
              acknowledgeLabel: {
                type: 'string'
              },
              prompt: {
                type: 'string'
              },
              requiredSignatures: {
                type: 'array',
                items: {
                  person: {
                    $ref: 'person-reference.schema.json'
                  },
                  hasSigned: {
                    type: 'boolean'
                  }
                }
              },
              signatures: {
                type: 'array',
                items: {
                  person: {
                    $ref: 'person-reference.schema.json'
                  },
                  date: {
                    type: 'object'
                  }
                }
              },
              showAcknowledgement: {
                type: 'boolean'
              }
            }
          },
          sections: {
            type: 'array',
            item: {
              $ref: 'document-section.schema.json'
            }
          },
          status: {
            type: 'string',
            "enum": Object.keys(DOCUMENT_STATUS)
          },
          createdBy: {
            $ref: 'person-reference.schema.json'
          },
          createdDate: {
            type: 'object'
          },
          label: {
            type: 'object',
            items: {
              not: ['object']
            }
          },
          family: {
            type: 'array',
            item: {
              type: 'object'
            }
          },
          band: {
            type: 'array',
            item: {
              type: 'object'
            }
          },
          lastModifiedBy: {
            $ref: 'person-reference.schema.json'
          },
          lastModifiedDate: {
            type: 'object'
          },
          expirationDate: {
            type: ['object', 'null']
          },
          readyForUseBy: {
            anyOf: [{
              type: 'null'
            }, {
              $ref: 'person-reference.schema.json'
            }]
          },
          readyForUseDate: {
            type: ['object', 'null']
          },
          workflowSteps: {
            type: 'array',
            item: {
              type: 'string'
            }
          },
          printedDate: {
            type: ['object', 'null']
          }
          // TODO: add validation for each card schema
        },

        required: Object.keys(new Document())
      };
    }
  }, {
    key: "cloneWithCommentsAllowed",
    value: function cloneWithCommentsAllowed(document, properties) {
      var copy = Document.clone(document, properties);
      copy.title = "".concat(document.title);
      copy.sections = copy.sections.map(function (section) {
        return _objectSpread(_objectSpread({}, section), {}, {
          allowableCards: section.allowableCards.map(function (allowableCard) {
            return _objectSpread(_objectSpread({}, allowableCard), {}, {
              allowComment: true
            });
          }),
          cards: section.cards.map(function (card) {
            return _objectSpread(_objectSpread({}, card), {}, {
              allowComment: true
            });
          })
        });
      });
      return new this(copy);
    }
  }, {
    key: "clone",
    value: function clone(document, properties) {
      var newVersion = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
      var user = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
      var access = user ? [Access.fromPerson(user, ACCESS_PERMISSION.OWNER)] : document.access;
      var copy = _objectSpread(_objectSpread(_objectSpread({}, document), {}, {
        createdBy: user ? new PersonReference(user) : null,
        createdDate: new Date(),
        expirationDate: null,
        lastModifiedBy: null,
        lastModifiedDate: null,
        readyForUseBy: null,
        readyForUseDate: null,
        status: DOCUMENT_STATUS.DRAFT,
        acknowledgement: _objectSpread(_objectSpread({}, document.acknowledgement), {}, {
          signatures: []
        })
      }, newVersion ? {} : {
        seriesId: new ObjectId(),
        revision: 0,
        title: "".concat(document.title, "-clone"),
        access: access
      }), properties);
      delete copy._id;
      copy.sections = copy.sections.map(function (section) {
        var cloneSection = _objectSpread(_objectSpread({}, section), {}, {
          id: new ObjectId(),
          cards: section.cards.map(function (card) {
            var attachments = newVersion ? card.attachments : [];
            if (card.type === CARD_TYPE.ACKNOWLEDGEMENT.type) {
              return _objectSpread(_objectSpread({}, card), {}, {
                id: new ObjectId(),
                attachments: attachments,
                details: _objectSpread(_objectSpread({}, card.details), {}, {
                  signatures: []
                })
              });
            }
            return _objectSpread(_objectSpread({}, card), {}, {
              id: new ObjectId(),
              attachments: attachments
            });
          })
        });
        return cloneSection;
      });
      return new this(copy);
    }
  }, {
    key: "fromTemplate",
    value: function fromTemplate(template, opt) {
      var status = template.createBySystem ? DOCUMENT_STATUS.READY_FOR_USE_BY_SYSTEM : DOCUMENT_STATUS.DRAFT;
      var sections = template.sectionDefinitions.map(function (sectionDefinition) {
        return _objectSpread(_objectSpread({}, sectionDefinition), {}, {
          id: new ObjectId(),
          cards: sectionDefinition.cardDefinitions.map(function (item) {
            return _objectSpread(_objectSpread({}, item), {}, {
              id: new ObjectId()
            });
          })
        });
      });
      return new this(_objectSpread(_objectSpread({}, opt), {}, {
        acknowledgement: template.acknowledgement,
        sections: sections,
        template: template,
        status: status
      }));
    }
  }]);
  return Document;
}();
tv4.addSchema(Access.schema());
tv4.addSchema(PersonReference.schema());
tv4.addSchema(TemplateReference.schema());
tv4.addSchema(DocumentSection.schema());
tv4.addSchema(CheckboxCard.schema());
tv4.addSchema(ChemicalCard.schema());
tv4.addSchema(ConditionCard.schema());
tv4.addSchema(EquipmentCard.schema());
tv4.addSchema(InspectCard.schema());
tv4.addSchema(FileReference.schema());
tv4.addSchema(ReferenceCard.schema());
tv4.addSchema(TextCard.schema());
module.exports = Document;