"use strict";
var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
    if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
    return cooked;
};
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
var __rest = (this && this.__rest) || function (s, e) {
    var t = {};
    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
        t[p] = s[p];
    if (s != null && typeof Object.getOwnPropertySymbols === "function")
        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0)
            t[p[i]] = s[p[i]];
    return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
var castArray = require("lodash/castArray");
var cloneDeep = require("lodash/cloneDeep");
var findIndex = require("lodash/findIndex");
var includes = require("lodash/includes");
var isEmpty = require("lodash/isEmpty");
var isEqual = require("lodash/isEqual");
var map = require("lodash/map");
var reject = require("lodash/reject");
var React = require("react");
var FaFilter = require("react-icons/lib/fa/filter");
var styled_components_1 = require("styled-components");
var utils = require("../../utils");
var Button_1 = require("../Button");
var DataTypes_1 = require("../DataTypes");
var DeleteButton_1 = require("../DeleteButton");
var Grid_1 = require("../Grid");
var Modal_1 = require("../Modal");
var Search_1 = require("../Search");
var Select_1 = require("../Select");
var Txt_1 = require("../Txt");
var SchemaSieve = require("./SchemaSieve");
var Summary_1 = require("./Summary");
var ViewsMenu_1 = require("./ViewsMenu");
var FilterInput = function (props) {
    var model = DataTypes_1.getDataModel(props.schema);
    if (!model) {
        return null;
    }
    var Edit = model.Edit;
    return (React.createElement(Edit, { schema: props.schema, value: props.value, operator: props.operator, onUpdate: props.onUpdate, slim: true }));
};
var RelativeBox = styled_components_1.default(Grid_1.Box)(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n\tposition: relative;\n"], ["\n\tposition: relative;\n"])));
var ExtraRuleDeleteBtn = styled_components_1.default(DeleteButton_1.default)(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n\tposition: absolute;\n\tbottom: 7px;\n\tright: -35px;\n"], ["\n\tposition: absolute;\n\tbottom: 7px;\n\tright: -35px;\n"])));
var SearchWrapper = styled_components_1.default.div(templateObject_3 || (templateObject_3 = __makeTemplateObject(["\n\tflex-basis: 500px;\n"], ["\n\tflex-basis: 500px;\n"])));
var FilterWrapper = styled_components_1.default(Grid_1.Box)(templateObject_4 || (templateObject_4 = __makeTemplateObject(["\n\tposition: relative;\n"], ["\n\tposition: relative;\n"])));
var Filters = (function (_super) {
    __extends(Filters, _super);
    function Filters(props) {
        var _this = _super.call(this, props) || this;
        var _a = _this.props, _b = _a.filters, filters = _b === void 0 ? [] : _b, schema = _a.schema, _c = _a.views, views = _c === void 0 ? [] : _c;
        var flatSchema = SchemaSieve.flattenSchema(schema);
        var flatViews = _this.flattenViews(views);
        var flatFilters = filters.map(function (filter) {
            return SchemaSieve.flattenSchema(filter);
        });
        _this.state = {
            showModal: false,
            searchString: '',
            editingFilter: null,
            filters: flatFilters,
            views: flatViews,
            schema: flatSchema,
            edit: [],
        };
        _this.state.edit.push(_this.getCleanEditModel());
        return _this;
    }
    Filters.prototype.componentWillReceiveProps = function (nextProps) {
        var newState = {};
        if (!isEqual(nextProps.schema, this.props.schema)) {
            newState.schema = SchemaSieve.flattenSchema(nextProps.schema);
        }
        if (!isEqual(nextProps.filters, this.props.filters)) {
            var filters = nextProps.filters || [];
            newState.filters = filters.map(function (filter) {
                return SchemaSieve.flattenSchema(filter);
            });
        }
        if (!isEqual(nextProps.views, this.props.views)) {
            var views = nextProps.views || [];
            newState.views = this.flattenViews(views);
        }
        if (!isEmpty(newState)) {
            this.setState(newState);
        }
    };
    Filters.prototype.flattenViews = function (views) {
        return views.map(function (_a) {
            var filters = _a.filters, view = __rest(_a, ["filters"]);
            return (__assign({}, view, { filters: filters.map(function (filter) { return SchemaSieve.flattenSchema(filter); }) }));
        });
    };
    Filters.prototype.emitViewsUpdate = function () {
        if (!this.props.onViewsUpdate) {
            return;
        }
        this.props.onViewsUpdate(this.state.views.map(function (_a) {
            var filters = _a.filters, view = __rest(_a, ["filters"]);
            return (__assign({}, view, { filters: filters.map(function (filter) { return SchemaSieve.unflattenSchema(filter); }) }));
        }));
    };
    Filters.prototype.getCleanEditModel = function (field) {
        var schema = this.state.schema;
        if (!field) {
            field = Object.keys(schema.properties).shift();
        }
        var fieldOperators = this.getOperators(field);
        if (!fieldOperators.length) {
            return {
                field: field,
                operator: '',
                value: '',
            };
        }
        var operator = fieldOperators.shift().slug;
        var value = '';
        var subschema = schema.properties[field];
        if (typeof subschema !== 'boolean') {
            if (subschema.enum) {
                value = subschema.enum[0] || '';
            }
            if (subschema.type === 'boolean') {
                value = true;
            }
        }
        return {
            field: field,
            operator: operator,
            value: value,
        };
    };
    Filters.prototype.getOperators = function (field) {
        var schema = this.state.schema;
        return SchemaSieve.getOperators(schema, field);
    };
    Filters.prototype.setEditField = function (field, index) {
        var currentEdit = this.state.edit.slice();
        currentEdit.splice(index, 1, this.getCleanEditModel(field));
        this.setState({
            edit: currentEdit,
        });
    };
    Filters.prototype.setEditOperator = function (operator, index) {
        var currentEdit = this.state.edit.slice();
        var item = currentEdit[index];
        currentEdit.splice(index, 1, __assign({}, item, { operator: operator }));
        this.setState({
            edit: currentEdit,
        });
    };
    Filters.prototype.setEditValue = function (value, index) {
        var currentEdit = this.state.edit.slice();
        var item = currentEdit[index];
        currentEdit.splice(index, 1, __assign({}, item, { value: value }));
        this.setState({
            edit: currentEdit,
        });
    };
    Filters.prototype.emitFilterUpdate = function () {
        if (!this.props.onFiltersUpdate) {
            return;
        }
        this.props.onFiltersUpdate(this.state.filters.map(function (filter) { return SchemaSieve.unflattenSchema(filter); }));
    };
    Filters.prototype.addFilter = function () {
        var _this = this;
        var $id = this.state.editingFilter;
        var schema = this.state.schema;
        var filter = SchemaSieve.createFilter(schema, this.state.edit);
        var currentFilters = this.state.filters;
        var filters;
        if (!!$id) {
            var matchIndex = findIndex(currentFilters, { $id: $id });
            currentFilters.splice(matchIndex, 1, filter);
            filters = currentFilters.slice();
        }
        else {
            filters = currentFilters.concat(filter);
        }
        this.setState({
            filters: filters,
            edit: [this.getCleanEditModel()],
            showModal: false,
            editingFilter: null,
        }, function () { return _this.emitFilterUpdate(); });
    };
    Filters.prototype.editFilter = function (filter) {
        var schema = this.state.schema;
        var signatures = SchemaSieve.decodeFilter(schema, filter);
        this.setState({
            edit: signatures,
            editingFilter: filter.$id,
            showModal: true,
        });
    };
    Filters.prototype.removeFilter = function (_a) {
        var _this = this;
        var $id = _a.$id, title = _a.title;
        this.setState(function (prevState) {
            var newState = __assign({}, prevState, { filters: reject(prevState.filters, { $id: $id }) });
            if (title === SchemaSieve.FULL_TEXT_SLUG) {
                newState.searchString = '';
            }
            return newState;
        }, function () { return _this.emitFilterUpdate(); });
    };
    Filters.prototype.setFilters = function (filters) {
        var _this = this;
        this.setState({ filters: filters }, function () { return _this.emitFilterUpdate(); });
    };
    Filters.prototype.addCompound = function () {
        var _this = this;
        this.setState(function (prevState) { return ({
            edit: prevState.edit.concat(_this.getCleanEditModel()),
        }); });
    };
    Filters.prototype.removeCompound = function (index) {
        var edit = this.state.edit.slice();
        edit.splice(index, 1);
        this.setState({
            edit: edit,
        });
    };
    Filters.prototype.saveView = function (name, scope) {
        var _this = this;
        var view = {
            id: utils.randomString(),
            name: name,
            scope: scope,
            filters: cloneDeep(this.state.filters),
        };
        this.setState(function (prevState) { return ({
            views: prevState.views.concat(view),
        }); }, function () {
            return _this.props.onViewsUpdate && _this.props.onViewsUpdate(_this.state.views);
        });
    };
    Filters.prototype.deleteView = function (_a) {
        var _this = this;
        var id = _a.id;
        this.setState(function (prevState) { return ({
            views: reject(prevState.views, { id: id }),
        }); }, function () {
            return _this.props.onViewsUpdate && _this.props.onViewsUpdate(_this.state.views);
        });
    };
    Filters.prototype.setSimpleSearch = function (term) {
        var _this = this;
        this.setState(function (prevState) {
            var newFilters = term
                ? SchemaSieve.upsertFullTextSearch(_this.state.schema, prevState.filters, term)
                : SchemaSieve.removeFullTextSearch(prevState.filters);
            return {
                searchString: term,
                filters: newFilters,
            };
        }, function () { return _this.emitFilterUpdate(); });
    };
    Filters.prototype.shouldRenderComponent = function (mode) {
        if (!this.props.renderMode) {
            return true;
        }
        var allowedModes = castArray(this.props.renderMode);
        if (includes(allowedModes, 'all')) {
            return true;
        }
        return includes(allowedModes, mode);
    };
    Filters.prototype.render = function () {
        var _this = this;
        var filters = this.state.filters;
        return (React.createElement(FilterWrapper, { mb: 3 },
            React.createElement(Grid_1.Flex, { justify: "space-between" },
                this.shouldRenderComponent('add') && (React.createElement(Button_1.default, __assign({ mr: 30, disabled: this.props.disabled, primary: true, onClick: function () {
                        return _this.setState({ showModal: true, editingFilter: null });
                    } }, this.props.addFilterButtonProps),
                    React.createElement(FaFilter, { style: { marginRight: 10 } }),
                    "Add filter")),
                this.shouldRenderComponent('search') && (React.createElement(SearchWrapper, null,
                    React.createElement(Search_1.default, { dark: this.props.dark, disabled: this.props.disabled, value: this.state.searchString, onChange: function (e) { return _this.setSimpleSearch(e.target.value); } }))),
                this.shouldRenderComponent('views') && (React.createElement(ViewsMenu_1.default, { buttonProps: this.props.viewsMenuButtonProps, disabled: this.props.disabled, views: this.state.views || [], schema: this.props.schema, hasMultipleScopes: this.props.viewScopes && this.props.viewScopes.length > 1, setFilters: function (filters) { return _this.setFilters(filters); }, deleteView: function (view) { return _this.deleteView(view); }, renderMode: this.props.renderMode }))),
            this.state.showModal && (React.createElement("div", null,
                React.createElement(Modal_1.default, { title: "Filter by", cancel: function () { return _this.setState({ showModal: false }); }, done: function () { return _this.addFilter(); }, action: "Save" },
                    map(this.state.edit, function (_a, index) {
                        var field = _a.field, operator = _a.operator, value = _a.value;
                        var operators = _this.getOperators(field);
                        return (React.createElement(RelativeBox, { key: index },
                            index > 0 && React.createElement(Txt_1.default, { my: 2 }, "OR"),
                            React.createElement(Grid_1.Flex, null,
                                React.createElement(Select_1.default, { value: field, onChange: function (v) {
                                        return _this.setEditField(v.target.value, index);
                                    } }, map(_this.state.schema.properties, function (s, field) { return (React.createElement("option", { key: field, value: field }, s.title || field)); })),
                                operators.length === 1 && (React.createElement(Txt_1.default, { mx: 1, p: "7px 20px 0" }, operators[0].label)),
                                operators.length > 1 && (React.createElement(Select_1.default, { ml: 1, value: operator, onChange: function (v) {
                                        return _this.setEditOperator(v.target.value, index);
                                    } }, map(operators, function (_a) {
                                    var slug = _a.slug, label = _a.label;
                                    return (React.createElement("option", { key: slug, value: slug }, label));
                                }))),
                                React.createElement(FilterInput, { operator: operator, value: value, schema: _this.state.schema.properties[field], onUpdate: function (v) { return _this.setEditValue(v, index); } })),
                            index > 0 && (React.createElement(ExtraRuleDeleteBtn, { onClick: function () { return _this.removeCompound(index); } }))));
                    }),
                    React.createElement(Button_1.default, { mb: 2, mt: 4, primary: true, underline: true, onClick: function () { return _this.addCompound(); } }, "Add alternative")))),
            this.shouldRenderComponent('summary') &&
                !!filters.length &&
                !this.props.disabled && (React.createElement(Summary_1.default, { scopes: this.props.viewScopes, edit: function (filter) { return _this.editFilter(filter); }, delete: function (filter) { return _this.removeFilter(filter); }, saveView: function (name, scope) { return _this.saveView(name, scope); }, filters: filters, views: this.state.views || [], schema: this.state.schema, dark: !!this.props.dark }))));
    };
    return Filters;
}(React.Component));
exports.default = Filters;
var templateObject_1, templateObject_2, templateObject_3, templateObject_4;
