text: import { ATTRIBUTE_TYPES } from "./constants.js";
  
  /**
   * Extend the basic ActorSheet with some very simple modifications
   * @extends {ActorSheet}
   */
  export class SimpleActorSheet extends ActorSheet {
  
    /** @override */
  	static get defaultOptions() {
  	  return mergeObject(super.defaultOptions, {
    	  classes: ["worldbuilding", "sheet", "actor"],
    	  template: "systems/worldbuilding/templates/actor-sheet.html",
        width: 600,
        height: 600,
        tabs: [{navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "description"}],
        dragDrop: [{dragSelector: ".item-list .item", dropSelector: null}]
      });
    }
  
    /* -------------------------------------------- */
  
    /** @override */
    getData() {
      const data = super.getData();
      data.dtypes = ATTRIBUTE_TYPES;
      for ( let attr of Object.values(data.data.attributes) ) {
        attr.isCheckbox = attr.dtype === "Boolean";
        attr.isResource = attr.dtype === "Resource";
      }
      data.shorthand = !!game.settings.get("worldbuilding", "macroShorthand");
      return data;
    }
  
    /* -------------------------------------------- */
  
    /** @override */
  	activateListeners(html) {
      super.activateListeners(html);
  
      // Handle rollable attributes.
      html.find('.items .rollable').click(ev => {
        let button = $(ev.currentTarget);
        let r = new Roll(button.data('roll'), this.actor.getRollData());
        const li = button.parents(".item");
        const item = this.actor.getOwnedItem(li.data("itemId"));
        r.roll().toMessage({
          user: game.user._id,
          speaker: ChatMessage.getSpeaker({ actor: this.actor }),
          flavor: `<h2>${item.name}</h2><h3>${button.text()}</h3>`
        });
      });
  
      // Everything below here is only needed if the sheet is editable
      if (!this.options.editable) return;
  
      // Update Inventory Item
      html.find('.item-edit').click(ev => {
        const li = $(ev.currentTarget).parents(".item");
        const item = this.actor.getOwnedItem(li.data("itemId"));
        item.sheet.render(true);
      });
  
      // Delete Inventory Item
      html.find('.item-delete').click(ev => {
        const li = $(ev.currentTarget).parents(".item");
        this.actor.deleteOwnedItem(li.data("itemId"));
        li.slideUp(200, () => this.render(false));
      });
  
      // Add or Remove Attribute
      html.find(".attributes").on("click", ".attribute-control", this._onClickAttributeControl.bind(this));
    }
  
    /* -------------------------------------------- */
  
    /** @override */
    setPosition(options={}) {
      const position = super.setPosition(options);
      const sheetBody = this.element.find(".sheet-body");
      const bodyHeight = position.height - 192;
      sheetBody.css("height", bodyHeight);
      return position;
    }
  
    /* -------------------------------------------- */
  
    /**
     * Listen for click events on an attribute control to modify the composition of attributes in the sheet
     * @param {MouseEvent} event    The originating left click event
     * @private
     */
    async _onClickAttributeControl(event) {
      event.preventDefault();
      const a = event.currentTarget;
      const action = a.dataset.action;
      const attrs = this.object.data.data.attributes;
      const form = this.form;
  
      // Add new attribute
      if ( action === "create" ) {
        const objKeys = Object.keys(attrs);
        let nk = Object.keys(attrs).length + 1;
        let newValue = `attr${nk}`;
        let newKey = document.createElement("div");
        while ( objKeys.includes(newValue) ) {
          ++nk;
          newValue = `attr${nk}`;
        };
        newKey.innerHTML = `<input type="text" name="data.attributes.attr${nk}.key" value="${newValue}"/>`;
        newKey = newKey.children[0];
        form.appendChild(newKey);
        await this._onSubmit(event);
      }
  
      // Remove existing attribute
      else if ( action === "delete" ) {
        const li = a.closest(".attribute");
        li.parentElement.removeChild(li);
        await this._onSubmit(event);
      }
    }
  
    /* -------------------------------------------- */
  
    /** @override */
    _updateObject(event, formData) {
  
      // Handle the free-form attributes list
      const formAttrs = expandObject(formData).data.attributes || {};
      const attributes = Object.values(formAttrs).reduce((obj, v) => {
        let k = v["key"].trim();
        if ( /[\s\.]/.test(k) )  return ui.notifications.error("Attribute keys may not contain spaces or periods");
        delete v["key"];
        obj[k] = v;
        return obj;
      }, {});
  
      // Remove attributes which are no longer used
      for ( let k of Object.keys(this.object.data.data.attributes) ) {
        if ( !attributes.hasOwnProperty(k) ) attributes[`-=${k}`] = null;
      }
  
      // Re-combine formData
      formData = Object.entries(formData).filter(e => !e[0].startsWith("data.attributes")).reduce((obj, e) => {
        obj[e[0]] = e[1];
        return obj;
      }, {_id: this.object._id, "data.attributes": attributes});
  
      // Update the Actor
      return this.object.update(formData);
    }
  }
  