(function() {
    window.initDQ = function() {
        $(document)
            .off('change input paste', '.dq-edit-container input, .dq-edit-container textarea, .dq-edit-container select')
            .on('change input paste', '.dq-edit-container input, .dq-edit-container textarea, .dq-edit-container select', function() {
                let key = $(this).closest('.dq-line').attr('dq-key'),
                    dataElem = $(this).closest('.dq-edit-container').find('>.dq-data-map').first(),
                    current = JSON.parse(dataElem.text());
                current[key] = $(this).val();
                let serialized = JSON.stringify(current);
                dataElem.text(serialized);
                $(this).closest('form').find('input[name="data"]').val(serialized);
                let fullData = {
                    lines: JSON.parse($(this).closest('.dq-edit-container').find('>.dq-definition').first().text()),
                    dataMap: current
                };
                $(this).closest('form').find('input[name="data"]').val(JSON.stringify(fullData));

                runDQConditions($(this).closest('.dq-edit-container'));
            });
        $(document)
            .off('input.auto-grow', '.dq-edit-container textarea')
            .on('input.auto-grow', '.dq-edit-container textarea', function() {
                this.style.minHeight = "calc(1.5em + .5rem + 2px)";
                this.style.height = "calc(1.5em + .5rem + 2px)";
                this.style.height = (this.scrollHeight)+"px";
            });
    };

    function resolveAtomicCondition(_condition, _dataMap) {
        if(!_condition.hasOwnProperty('key') || !_condition.hasOwnProperty('value')) {
            _condition.resolution = false;
            return;
        }
        let key = _condition.key, op = _condition.hasOwnProperty('op') ? _condition.op : 'eq';
        let lhs = _dataMap[key], rhs = _condition.value;
        switch(op) {
            case 'eq':
                _condition.resolution = (lhs == rhs); // NOTE: using == instead of === on purpose
                break;
            case 'lt':
                _condition.resolution = (+lhs < +rhs);
                break;
            case 'lte':
                _condition.resolution = (+lhs <= +rhs);
                break;
            case 'gt':
                _condition.resolution = (+lhs > +rhs);
                break;
            case 'gte':
                _condition.resolution = (+lhs >= +rhs);
                break;
            default:
                _condition.resolution = false;
        }
    }

    function resolveAllAtomicConditions(_conditions, _dataMap) {
        if(Array.isArray(_conditions)) {
            for (let i = 0; i < _conditions.length; i++) {
                resolveAllAtomicConditions(_conditions[i], _dataMap);
            }
        }
        else if(typeof _conditions === 'object') {
            resolveAtomicCondition(_conditions, _dataMap);
        }
    }

    function reduceConditionsIntoResolutions(_conditions) {
        for (let i = 0; i < _conditions.length; i++) {
            // if simple object, resolve
            if(!Array.isArray(_conditions[i]) && typeof _conditions[i] === 'object') {
                _conditions.splice(i, 1, _conditions[i].resolution);
            }
            else if(Array.isArray(_conditions[i])) {
                reduceConditionsIntoResolutions(_conditions[i]);
            }
        }
    }

    function combineResolutionListsIntoSingleResolutions(_conditions) {
        console.log('ALIX 1', _conditions);
        for (let i = 0; i < _conditions.length; i++) {
            if(Array.isArray(_conditions[i])) {
                _conditions[i] = combineResolutionListsIntoSingleResolutions(_conditions[i]);
            }
        }
        console.log('ALIX 2', _conditions);

        // at this point, the array will have only booleans and "AND", "OR" combinators
        let resolution = _conditions[0];
        for (let i = 1; i < _conditions.length; i+=2) {
            if(_conditions[i] === 'AND') {
                resolution = resolution && _conditions[i + 1];
            }
            else if(_conditions[i] === 'OR') {
                resolution = resolution || _conditions[i + 1];
            }
        }

        return resolution;
    }

    window.runDQConditions = function(_parent) {

        _parent.find('.dq-line.has-pre-condition').each(function() {
            let conditions = JSON.parse($(this).find('>.dq-pre-condition').first().text()),
                dataMap = JSON.parse($(this).closest('.dq-edit-container').find('>.dq-data-map').first().text());

            resolveAllAtomicConditions(conditions, dataMap);

            // if object, single condition with key, op and value
            if(!Array.isArray(conditions) && typeof conditions === 'object') {
                if(conditions.resolution) {
                    $(this).removeClass('d-none');
                }
                else {
                    $(this).addClass('d-none');
                }
            }
            // else if array - means list of conditions with 'and' or 'or' separators - array size MUST be an odd number
            else if(Array.isArray(conditions)) {

                // goal is to reduce each item in the array into a single boolean - recursively
                reduceConditionsIntoResolutions(conditions);

                conditions = combineResolutionListsIntoSingleResolutions(conditions);

                if(conditions) {
                    $(this).removeClass('d-none');
                }
                else {
                    $(this).addClass('d-none');
                }

            }

        });

    }
    addMCInitializer('dq-edit', initDQ, '.dq-edit-container');
}).call(window);