/*
 * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 * WSO2 Inc. licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.wso2.carbon.siddhi.editor.core.util.designview.designgenerator.generators;

import io.siddhi.query.api.SiddhiElement;
import org.wso2.carbon.siddhi.editor.core.util.designview.beans.configs.ElementCodeSegment;
import org.wso2.carbon.siddhi.editor.core.util.designview.beans.configs.siddhielements.SiddhiElementConfig;

import java.util.HashSet;
import java.util.Set;

/**
 * Contains methods to preserve code segments of Siddhi elements through their Config Generators,
 * in order to help preserving comments.
 */
public abstract class CodeSegmentsPreserver {

    private Set<ElementCodeSegment> preservedCodeSegments = new HashSet<>();

    public Set<ElementCodeSegment> getPreservedCodeSegments() {

        return preservedCodeSegments;
    }

    /**
     * Preserves code segment of the given SiddhiElement object.
     *
     * @param siddhiElement SiddhiElement object which represents a parsed Siddhi element.
     */
    public void preserveCodeSegment(SiddhiElement siddhiElement) {

        if (isCodeSegmentValid(siddhiElement)) {
            preservedCodeSegments.add(
                    new ElementCodeSegment(
                            siddhiElement.getQueryContextStartIndex(), siddhiElement.getQueryContextEndIndex()));
        }
    }

    /**
     * Preserves code segment of the given SiddhiElement,
     * and binds the query start and end indexes to the given SiddhiElementConfig.
     *
     * @param bindFromElement     SiddhiElement object from which,
     *                            code segment indexes are acquired and preserved
     * @param bindToElementConfig SiddhiElementConfig object to which, the acquired indexes should be bound
     */
    protected void preserveAndBindCodeSegment(SiddhiElement bindFromElement, SiddhiElementConfig bindToElementConfig) {

        preserveCodeSegment(bindFromElement);
        bindCodeSegmentIndexes(bindFromElement, bindToElementConfig);
    }

    /**
     * Binds query context start and end indexes of the given SiddhiElement object,
     * to the given SiddhiElementConfig object.
     *
     * @param bindFromElement     SiddhiElement object from which, code segment indexes are acquired
     * @param bindToElementConfig SiddhiElementConfig object to which, the acquired code segment indexes are bound
     */
    protected void bindCodeSegmentIndexes(SiddhiElement bindFromElement,
                                          SiddhiElementConfig bindToElementConfig) {

        if (isCodeSegmentValid(bindFromElement)) {
            bindToElementConfig.setQueryContextStartIndex(bindFromElement.getQueryContextStartIndex());
            bindToElementConfig.setQueryContextEndIndex(bindFromElement.getQueryContextEndIndex());
        }
    }

    /**
     * Preserves the code segments that are preserved in each of the given CodeSegmentsPreservers.
     *
     * @param codeSegmentsPreservers One or more CodeSegmentsPreserver objects,
     *                               whose preserved code segments are accessed for preserving
     */
    protected void preserveCodeSegmentsOf(CodeSegmentsPreserver... codeSegmentsPreservers) {

        for (CodeSegmentsPreserver codeSegmentsPreserver : codeSegmentsPreservers) {
            preservedCodeSegments.addAll(codeSegmentsPreserver.getPreservedCodeSegments());
        }
    }

    /**
     * Returns whether the given SiddhiElement object's code segment is valid or not.
     *
     * @param siddhiElement SiddhiElement object
     * @return true if the code segment is valid, otherwise false
     */
    private boolean isCodeSegmentValid(SiddhiElement siddhiElement) {

        return siddhiElement != null &&
                siddhiElement.getQueryContextStartIndex() != null &&
                siddhiElement.getQueryContextEndIndex() != null;
    }
}
