"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var React = require("react");
var igd_core_1 = require("@intelligentgraphics/igd.core");
var igd_productdata_1 = require("@intelligentgraphics/igd.productdata");
var ig_utilities_1 = require("@intelligentgraphics/ig.utilities");
var SessionContext_1 = require("../SessionContext");
var Units = require("../Units");
var Articles_1 = require("./Articles");
var Groupers_1 = require("./Groupers");
var Util_1 = require("./Util");
var Context_1 = require("./Context");
var PropertyEditorSubPropertyBehaviour;
(function (PropertyEditorSubPropertyBehaviour) {
    /**
     * Keep sub properties on their parent properties
     */
    PropertyEditorSubPropertyBehaviour["Depth"] = "depth";
    /**
     * Extract available properties and add them the to normal list of properties
     */
    PropertyEditorSubPropertyBehaviour["ShowInline"] = "showInline";
})(PropertyEditorSubPropertyBehaviour = exports.PropertyEditorSubPropertyBehaviour || (exports.PropertyEditorSubPropertyBehaviour = {}));
var PropertyEditorMode;
(function (PropertyEditorMode) {
    /**
     * Display articles of the session
     */
    PropertyEditorMode["AllArticles"] = "AllArticles";
    /**
     * Display articles of the session application state selection
     */
    PropertyEditorMode["Selection"] = "Selection";
    /**
     * Display articles provided via prop
     */
    PropertyEditorMode["ProvidedArticles"] = "ProvidedArticles";
    /**
     * Display provided articles or the session application state selection, if no articles are provided
     */
    PropertyEditorMode["Auto"] = "Auto";
})(PropertyEditorMode = exports.PropertyEditorMode || (exports.PropertyEditorMode = {}));
var PropertyEditor = /** @class */ (function (_super) {
    tslib_1.__extends(PropertyEditor, _super);
    function PropertyEditor() {
        var _this = _super !== null && _super.apply(this, arguments) || this;
        _this.state = {
            groups: [],
            groupReferences: {},
            properties: {},
        };
        _this.createContextValue = ig_utilities_1.memoizeOne(function (context, properties) { return (tslib_1.__assign(tslib_1.__assign({}, context), { properties: properties })); });
        _this.createViewProps = ig_utilities_1.memoizeOne(function (state) { return ({
            groups: state.groups,
            properties: Object.getOwnPropertyNames(state.properties),
            getPropertyByIdentifier: function (identifier) { return state.properties[identifier]; },
        }); });
        _this.articleData = {};
        _this.transferTargets = [];
        _this.childContext = {
            properties: {},
            setPropertyValue: _this.setPropertyValue.bind(_this),
            applyToAll: _this.applyToTransferTargets.bind(_this),
            getComIdsByProperty: _this.getComIdsByProperty.bind(_this),
        };
        _this.onItemCreated = function (article) {
            if (_this.props.mode === PropertyEditorMode.AllArticles) {
                return _this.queueUpdate(_this.getComIds());
            }
        };
        _this.onItemRemoved = function (article) {
            if (_this.props.mode === PropertyEditorMode.AllArticles) {
                return _this.queueUpdate(_this.getComIds());
            }
        };
        _this.onItemConfigured = function (article) {
            if (!_this.articleData[article.comId]) {
                return;
            }
            _this.queueUpdate(_this.getComIds());
        };
        _this.onApplicationStateValueChanged = function (payload) {
            if (payload.key !== "selection") {
                return;
            }
            _this.queueUpdate(_this.getComIds());
        };
        _this.queueUpdate = function (comIds) {
            if (comIds === void 0) { comIds = []; }
            if (_this.updateBatchTimer !== undefined) {
                window.clearTimeout(_this.updateBatchTimer);
                _this.updateBatchTimer = undefined;
            }
            _this.updateBatchTimer = window.setTimeout(function () {
                return _this.setupForArticles(comIds);
            });
        };
        _this.setupId = 0;
        return _this;
    }
    PropertyEditor.prototype.render = function () {
        var context = this.createContextValue(this.childContext, this.state.properties);
        var viewProps = this.createViewProps(this.state);
        return (React.createElement(Context_1.PropertyEditorContext.Provider, { value: context }, this.props.children(viewProps)));
    };
    PropertyEditor.prototype.componentDidMount = function () {
        this.setupForArticles(this.getComIds());
        this.subscription = this.props.session.subscribe({
            ItemConfigured: this.onItemConfigured,
            ItemCreated: this.onItemCreated,
            ItemRemoved: this.onItemRemoved,
            ApplicationStateValueChanged: this.onApplicationStateValueChanged,
        });
    };
    PropertyEditor.prototype.componentWillUnmount = function () {
        if (this.subscription) {
            this.subscription.destroy();
        }
    };
    PropertyEditor.prototype.componentDidUpdate = function (prevProps) {
        if (this.props.articles !== prevProps.articles ||
            this.props.transferTargets !== prevProps.transferTargets ||
            this.props.units !== prevProps.units ||
            this.props.subPropertyBehaviour !==
                prevProps.subPropertyBehaviour ||
            this.props.mode !== prevProps.mode) {
            this.queueUpdate(this.getComIds());
        }
    };
    PropertyEditor.prototype.setupForArticles = function (comIds) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var id, transferTargets, articleData, articleGroups, sourceGroups, propertyList, result;
            var _this = this;
            return tslib_1.__generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        this.setupId++;
                        id = this.setupId;
                        transferTargets = this.props.transferTargets;
                        // replace article com ids with set com ids if the articles are not configurable
                        comIds = igd_productdata_1.RuleUtil.execute(this.props.session, comIds, "configurable");
                        if (transferTargets !== undefined) {
                            // do the same for transfer targets, when available
                            transferTargets = igd_productdata_1.RuleUtil.execute(this.props.session, transferTargets, "configurable");
                        }
                        articleData = Articles_1.collectArticleData(this.props.session, comIds.concat(transferTargets || []));
                        articleGroups = Articles_1.groupArticlesBySourceId(comIds.map(function (comId) { return articleData[comId]; }));
                        sourceGroups = Object.values(articleGroups);
                        return [4 /*yield*/, this.props.createPropertyGroups(sourceGroups)];
                    case 1:
                        propertyList = _a.sent();
                        if (id !== this.setupId) {
                            // if the setupId has changed while propertyGroups were created, skip remaining setup
                            return [2 /*return*/];
                        }
                        this.transferTargets = transferTargets;
                        this.articleData = articleData;
                        result = Util_1.createComponentState({
                            propertyList: propertyList,
                            units: this.props.units,
                            transferTargets: transferTargets.map(function (comId) { return _this.articleData[comId]; }),
                            subPropertyBehaviour: this.props.subPropertyBehaviour,
                        });
                        this.setState(result);
                        return [2 /*return*/];
                }
            });
        });
    };
    PropertyEditor.prototype.setPropertyValue = function (name, newValue) {
        var _a = Util_1.parsePropertyIdentifier(name), groupId = _a.groupId, propertyKey = _a.propertyKey;
        var references = this.state.groupReferences[groupId];
        if (references === undefined) {
            throw new Error("Could not find a group for id \"" + groupId + "\"");
        }
        var normalizedReferences = Array.isArray(references)
            ? references
            : [references];
        var targetProperty = this.state.properties[name];
        if (name === undefined) {
            throw new Error("Could not find a property for name \"" + name + "\"");
        }
        if (!ig_utilities_1.isNullOrUndefined(targetProperty.ValueUnit) &&
            (targetProperty.ValueType === igd_core_1.IGXE.EPropertyType.Int ||
                targetProperty.ValueType === igd_core_1.IGXE.EPropertyType.Float)) {
            newValue = Units.convert(Number(newValue), targetProperty.ValueUnit, igd_core_1.IGXE.EPropertyValueUnit.LENGTH_M);
        }
        return this.props.setPropertyValue(this.props.session, normalizedReferences, propertyKey, newValue);
    };
    PropertyEditor.prototype.applyToTransferTargets = function (name) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var propertyKey, property, newValueDefinition, newValue, applyTargets;
            var _this = this;
            return tslib_1.__generator(this, function (_a) {
                propertyKey = Util_1.parsePropertyIdentifier(name).propertyKey;
                property = this.state.properties[name];
                if (property === undefined) {
                    throw new Error("Can not find a property for \"" + name + "\"");
                }
                newValueDefinition = igd_core_1.IGXE.getFinalPropertyValue(property);
                if (newValueDefinition === undefined) {
                    throw new Error("Property \"" + name + "\" can not be applied to all, because no value has been configured");
                }
                newValue = newValueDefinition.Value;
                if (!ig_utilities_1.isNullOrUndefined(property.ValueUnit) &&
                    (property.ValueType === igd_core_1.IGXE.EPropertyType.Int ||
                        property.ValueType === igd_core_1.IGXE.EPropertyType.Float)) {
                    newValue = Units.convert(Number(newValue), property.ValueUnit, igd_core_1.IGXE.EPropertyValueUnit.LENGTH_M);
                }
                applyTargets = igd_productdata_1.PropertyUtil.findApplyTargets(this.transferTargets.map(function (target) { return _this.articleData[target]; }), propertyKey, newValue);
                return [2 /*return*/, this.props.setPropertyValue(this.props.session, applyTargets.map(function (article) { return article.comId; }), propertyKey, newValue)];
            });
        });
    };
    PropertyEditor.prototype.getComIdsByProperty = function (name) {
        var groupId = Util_1.parsePropertyIdentifier(name).groupId;
        var references = this.state.groupReferences[groupId];
        return Array.isArray(references) ? references : [references];
    };
    PropertyEditor.prototype.getComIds = function () {
        switch (this.props.mode) {
            case PropertyEditorMode.AllArticles:
                return this.props.session.getAllComIds();
            case PropertyEditorMode.Selection:
                return this.props.session.getApplicationStateValue("selection");
            case PropertyEditorMode.ProvidedArticles:
                if (this.props.articles === undefined) {
                    throw new Error("The property editor's mode has been set to ProvidedArticles, but no articles have been provided!");
                }
                return this.props.articles;
        }
        if (this.props.articles !== undefined) {
            return this.props.articles;
        }
        return this.props.session.getApplicationStateValue("selection");
    };
    PropertyEditor.defaultProps = {
        createPropertyGroups: Groupers_1.byComId,
        transferTargets: [],
        setPropertyValue: function (session, articles, propKey, propValue) {
            return session.changeProperty(articles, propKey, propValue);
        },
        subPropertyBehaviour: PropertyEditorSubPropertyBehaviour.ShowInline,
        mode: PropertyEditorMode.Auto,
    };
    return PropertyEditor;
}(React.Component));
exports.default = SessionContext_1.withSessionContext(PropertyEditor);
