import {ParamType as ParamType2} from "../../poly/ParamType";
import {ParamEvent as ParamEvent2} from "../../poly/ParamEvent";
import {CoreGraphNode as CoreGraphNode2} from "../../../core/graph/CoreGraphNode";
import {CoreType} from "../../../core/Type";
import {ArrayUtils as ArrayUtils2} from "../../../core/ArrayUtils";
import {ObjectUtils as ObjectUtils2} from "../../../core/ObjectUtils";
const CALLBACK_OPTION = "callback";
const CALLBACK_STRING_OPTION = "callbackString";
const COMPUTE_ON_DIRTY = "computeOnDirty";
const COOK_OPTION = "cook";
const FILE_BROWSE_OPTION = "fileBrowse";
const FILE_TYPE_OPTION = "type";
const EXPRESSION = "expression";
const FOR_ENTITIES = "forEntities";
const LABEL = "label";
const LEVEL = "level";
const MENU = "menu";
const ENTRIES = "entries";
const MULTILINE_OPTION = "multiline";
const LANGUAGE_OPTION = "language";
const NODE_SELECTION = "nodeSelection";
const NODE_SELECTION_CONTEXT = "context";
const NODE_SELECTION_TYPES = "types";
const PARAM_SELECTION = "paramSelection";
const DEPENDENT_ON_FOUND_NODE = "dependentOnFoundNode";
const RANGE_OPTION = "range";
const RANGE_LOCKED_OPTION = "rangeLocked";
const STEP_OPTION = "step";
const SPARE_OPTION = "spare";
const TEXTURE_OPTION = "texture";
const ENV_OPTION = "env";
const HIDDEN_OPTION = "hidden";
const FIELD_OPTION = "field";
const VISIBLE_IF_OPTION = "visibleIf";
const COLOR_CONVERSION = "conversion";
export var StringParamLanguage;
(function(StringParamLanguage2) {
  StringParamLanguage2["TYPESCRIPT"] = "typescript";
})(StringParamLanguage || (StringParamLanguage = {}));
export var FileType;
(function(FileType2) {
  FileType2["TEXTURE"] = "texture";
  FileType2["GEOMETRY"] = "geometry";
})(FileType || (FileType = {}));
export class OptionsController {
  constructor(_param) {
    this._param = _param;
    this._programatic_visible_state = true;
    this._callbackAllowed = false;
    this._update_visibility_and_remove_dirty_bound = this.update_visibility_and_remove_dirty.bind(this);
    this._ui_data_dependency_set = false;
  }
  dispose() {
    this._options[CALLBACK_OPTION] = void 0;
    this._options[CALLBACK_STRING_OPTION] = void 0;
    this._visibility_graph_node?.dispose();
  }
  set(options) {
    this._default_options = options;
    this._options = ObjectUtils2.cloneDeep(this._default_options);
    this.post_set_options();
  }
  copy(options_controller) {
    this._default_options = ObjectUtils2.cloneDeep(options_controller.default());
    this._options = ObjectUtils2.cloneDeep(options_controller.current());
    this.post_set_options();
  }
  set_option(name, value) {
    this._options[name] = value;
    if (this._param.components) {
      for (let component of this._param.components) {
        component.options.set_option(name, value);
      }
    }
  }
  post_set_options() {
    this._handle_computeOnDirty();
  }
  param() {
    return this._param;
  }
  node() {
    return this._param.node;
  }
  default() {
    return this._default_options;
  }
  current() {
    return this._options;
  }
  has_options_overridden() {
    return !ObjectUtils2.isEqual(this._options, this._default_options);
  }
  overridden_options() {
    const overriden = {};
    const option_names = Object.keys(this._options);
    for (let option_name of option_names) {
      if (!ObjectUtils2.isEqual(this._options[option_name], this._default_options[option_name])) {
        const cloned_option = ObjectUtils2.cloneDeep(this._options[option_name]);
        Object.assign(overriden, {[option_name]: cloned_option});
      }
    }
    return overriden;
  }
  overridden_option_names() {
    return Object.keys(this.overridden_options());
  }
  computeOnDirty() {
    return this._options[COMPUTE_ON_DIRTY] || false;
  }
  _handle_computeOnDirty() {
    if (this.computeOnDirty()) {
      if (!this._computeOnDirty_callback_added) {
        this.param().addPostDirtyHook("computeOnDirty", this._compute_param.bind(this));
        this._computeOnDirty_callback_added = true;
      }
    }
  }
  async _compute_param() {
    await this.param().compute();
  }
  has_callback() {
    return this._options[CALLBACK_OPTION] != null || this._options[CALLBACK_STRING_OPTION] != null;
  }
  allowCallback() {
    this._callbackAllowed = true;
  }
  execute_callback() {
    if (!this._callbackAllowed) {
      return;
    }
    if (!this.node()) {
      return;
    }
    if (!this.node().scene().loadingController.loaded()) {
      return;
    }
    const callback = this.get_callback();
    if (callback != null) {
      const parent_param = this.param().parent_param;
      if (parent_param) {
        parent_param.options.execute_callback();
      } else {
        callback(this.node(), this.param());
      }
    }
  }
  get_callback() {
    if (this.has_callback()) {
      return this._options[CALLBACK_OPTION] = this._options[CALLBACK_OPTION] || this.create_callback_from_string();
    }
  }
  create_callback_from_string() {
    const callbackString = this._options[CALLBACK_STRING_OPTION];
    if (callbackString) {
      const callback_function = new Function("node", "scene", "window", "location", callbackString);
      return () => {
        callback_function(this.node(), this.node().scene(), null, null);
      };
    }
  }
  color_conversion() {
    return this._options[COLOR_CONVERSION];
  }
  makes_node_dirty_when_dirty() {
    let cook_options;
    if (this.param().parent_param != null) {
      return false;
    }
    let value = true;
    if ((cook_options = this._options[COOK_OPTION]) != null) {
      value = cook_options;
    }
    return value;
  }
  file_browse_option() {
    return this._options[FILE_BROWSE_OPTION];
  }
  file_browse_allowed() {
    return this.file_browse_option() != null;
  }
  file_browse_type() {
    const option = this.file_browse_option();
    if (option) {
      return option[FILE_TYPE_OPTION];
    } else {
      return null;
    }
  }
  is_expression_for_entities() {
    const expr_option = this._options[EXPRESSION];
    if (expr_option) {
      return expr_option[FOR_ENTITIES] || false;
    }
    return false;
  }
  level() {
    return this._options[LEVEL] || 0;
  }
  has_menu() {
    return this.menu_options() != null;
  }
  menu_options() {
    return this._options[MENU];
  }
  menu_entries() {
    const options = this.menu_options();
    if (options) {
      return options[ENTRIES];
    } else {
      return [];
    }
  }
  has_menu_radio() {
    return this.has_menu();
  }
  is_multiline() {
    return this._options[MULTILINE_OPTION] === true;
  }
  language() {
    return this._options[LANGUAGE_OPTION];
  }
  is_code() {
    return this.language() != null;
  }
  node_selection_options() {
    return this._options[NODE_SELECTION];
  }
  node_selection_context() {
    const options = this.node_selection_options();
    if (options) {
      return options[NODE_SELECTION_CONTEXT];
    }
  }
  node_selection_types() {
    const options = this.node_selection_options();
    if (options) {
      return options[NODE_SELECTION_TYPES];
    }
  }
  dependent_on_found_node() {
    if (DEPENDENT_ON_FOUND_NODE in this._options) {
      return this._options[DEPENDENT_ON_FOUND_NODE];
    } else {
      return true;
    }
  }
  is_selecting_param() {
    return this.param_selection_options() != null;
  }
  param_selection_options() {
    return this._options[PARAM_SELECTION];
  }
  param_selection_type() {
    const options = this.param_selection_options();
    if (options) {
      const type_or_boolean = options;
      if (!CoreType.isBoolean(type_or_boolean)) {
        return type_or_boolean;
      }
    }
  }
  range() {
    return this._options[RANGE_OPTION] || [0, 1];
  }
  step() {
    return this._options[STEP_OPTION];
  }
  range_locked() {
    return this._options[RANGE_LOCKED_OPTION] || [false, false];
  }
  ensure_in_range(value) {
    const range = this.range();
    if (value >= range[0] && value <= range[1]) {
      return value;
    } else {
      if (value < range[0]) {
        return this.range_locked()[0] === true ? range[0] : value;
      } else {
        return this.range_locked()[1] === true ? range[1] : value;
      }
    }
  }
  is_spare() {
    return this._options[SPARE_OPTION] || false;
  }
  texture_options() {
    return this._options[TEXTURE_OPTION];
  }
  texture_as_env() {
    const texture_options = this.texture_options();
    if (texture_options != null) {
      return texture_options[ENV_OPTION] === true;
    }
    return false;
  }
  is_hidden() {
    return this._options[HIDDEN_OPTION] === true || this._programatic_visible_state === false;
  }
  is_visible() {
    return !this.is_hidden();
  }
  set_visible_state(state) {
    this._options[HIDDEN_OPTION] = !state;
    this.param().emit(ParamEvent2.VISIBLE_UPDATED);
  }
  label() {
    return this._options[LABEL];
  }
  is_label_hidden() {
    const type = this.param().type();
    return type === ParamType2.BUTTON || type === ParamType2.SEPARATOR || type === ParamType2.BOOLEAN && this.is_field_hidden();
  }
  is_field_hidden() {
    return this._options[FIELD_OPTION] === false;
  }
  ui_data_depends_on_other_params() {
    return VISIBLE_IF_OPTION in this._options;
  }
  visibility_predecessors() {
    const visibility_options = this._options[VISIBLE_IF_OPTION];
    if (!visibility_options) {
      return [];
    }
    let predecessor_names = [];
    if (CoreType.isArray(visibility_options)) {
      predecessor_names = ArrayUtils2.uniq(visibility_options.map((options) => Object.keys(options)).flat());
    } else {
      predecessor_names = Object.keys(visibility_options);
    }
    const node = this.param().node;
    return ArrayUtils2.compact(predecessor_names.map((name) => {
      const param = node.params.get(name);
      if (param) {
        return param;
      } else {
        console.error(`param ${name} not found as visibility condition for ${this.param().name()} in node ${this.param().node.type()}`);
      }
    }));
  }
  set_ui_data_dependency() {
    if (this._ui_data_dependency_set) {
      return;
    }
    this._ui_data_dependency_set = true;
    const predecessors = this.visibility_predecessors();
    if (predecessors.length > 0) {
      this._visibility_graph_node = new CoreGraphNode2(this.param().scene(), "param_visibility");
      for (let predecessor of predecessors) {
        this._visibility_graph_node.addGraphInput(predecessor);
      }
      this._visibility_graph_node.addPostDirtyHook("_update_visibility_and_remove_dirty", this._update_visibility_and_remove_dirty_bound);
    }
  }
  update_visibility_and_remove_dirty() {
    this.update_visibility();
    this.param().removeDirtyState();
  }
  async update_visibility() {
    const options = this._options[VISIBLE_IF_OPTION];
    if (options) {
      const params = this.visibility_predecessors();
      const promises = params.map((p) => {
        if (p.isDirty()) {
          return p.compute();
        }
      });
      this._programatic_visible_state = false;
      await Promise.all(promises);
      if (CoreType.isArray(options)) {
        for (let options_set of options) {
          const satisfied_values = params.filter((param) => param.value == options_set[param.name()]);
          if (satisfied_values.length == params.length) {
            this._programatic_visible_state = true;
          }
        }
      } else {
        const satisfied_values = params.filter((param) => param.value == options[param.name()]);
        this._programatic_visible_state = satisfied_values.length == params.length;
      }
      this.param().emit(ParamEvent2.VISIBLE_UPDATED);
    }
  }
}
