/*******************************************************************************
 * Copyright (C) 2022, 1C-Soft LLC and others.
 *
 * This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License 2.0
 * which is available at https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     1C-Soft LLC - initial API and implementation
 *******************************************************************************/
package com.e1c.v8codestyle.bsl.qfix;

import java.util.Iterator;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.text.edits.DeleteEdit;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.xtext.TerminalRule;
import org.eclipse.xtext.nodemodel.ILeafNode;
import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
import org.eclipse.xtext.resource.XtextResource;

import com._1c.g5.v8.dt.bsl.services.BslGrammarAccess;
import com._1c.g5.v8.dt.core.platform.IV8Project;
import com._1c.g5.v8.dt.core.platform.IV8ProjectManager;
import com.e1c.g5.v8.dt.bsl.check.qfix.IXtextBslModuleFixModel;
import com.e1c.g5.v8.dt.bsl.check.qfix.SingleVariantXtextBslModuleFix;
import com.e1c.g5.v8.dt.check.ICheckParameters;
import com.e1c.g5.v8.dt.check.qfix.components.QuickFix;
import com.e1c.g5.v8.dt.check.settings.ICheckRepository;
import com.e1c.v8codestyle.internal.bsl.BslPlugin;
import com.google.inject.Inject;

/**
 * Removes extra empty lines
 *
 * @author Artem Iliukhin
 */
@QuickFix(checkId = "module-consecutive-blank-lines", supplierId = BslPlugin.PLUGIN_ID)
public class ConsecutiveEmptyLinesFix
    extends SingleVariantXtextBslModuleFix
{
    private static final String PATTERN = "(?<=\\n)"; //$NON-NLS-1$

    private static final String NUMBER_OF_EMPTY_LINES = "numberOfEmptyLines"; //$NON-NLS-1$

    private final BslGrammarAccess grammarAccess;

    private final ICheckRepository checkRepository;

    private final IV8ProjectManager v8ProjectManager;

    /**
     * Instantiates a new consecutive empty lines fix.
     *
     * @param grammarAccess the grammar access
     * @param checkRepository the check repository
     * @param v8ProjectManager the v 8 project manager
     */
    @Inject
    public ConsecutiveEmptyLinesFix(BslGrammarAccess grammarAccess, ICheckRepository checkRepository,
        IV8ProjectManager v8ProjectManager)
    {
        super();
        this.grammarAccess = grammarAccess;
        this.checkRepository = checkRepository;
        this.v8ProjectManager = v8ProjectManager;
    }

    @Override
    protected void configureFix(FixConfigurer configurer)
    {
        configurer.interactive(true)
            .description(Messages.ConsecutiveEmptyLinesFix_Description)
            .details(Messages.ConsecutiveEmptyLinesFix_Details);
    }

    @Override
    protected TextEdit fixIssue(XtextResource state, IXtextBslModuleFixModel model) throws BadLocationException
    {
        EObject element = model.getElement();
        INode node = NodeModelUtils.findActualNodeFor(element);
        Iterator<ILeafNode> iterator = node.getLeafNodes().iterator();

        IV8Project project = v8ProjectManager.getProject(element);
        ICheckParameters parameters = checkRepository.getCheckParameters(getCheckId(), project.getProject());
        int numberOfEmtyLines = parameters.getInt(NUMBER_OF_EMPTY_LINES);

        MultiTextEdit result = new MultiTextEdit();
        while (iterator.hasNext())
        {
            ILeafNode leafNode = iterator.next();
            EObject grammarElement = leafNode.getGrammarElement();
            int startLine = leafNode.getStartLine();
            int endLine = leafNode.getEndLine();

            if (grammarElement instanceof TerminalRule && grammarAccess.getWSRule().equals(grammarElement)
                && (endLine - startLine - 1) > numberOfEmtyLines)
            {
                String[] lines = leafNode.getText().split(PATTERN);
                int headLength = getAllowedHeadLength(numberOfEmtyLines, lines);

                int tailLength = leafNode.getLength() - getAllowedTailLength(headLength, lines);
                result.addChild(new DeleteEdit(leafNode.getOffset() + headLength, tailLength == 0 ? 1 : tailLength));
            }
        }

        if (result.getChildrenSize() > 0)
        {
            return result;
        }

        return null;
    }

    private int getAllowedHeadLength(int number, String[] lines)
    {
        int sum = 0;
        for (int i = 0; i <= number; i++)
        {
            sum += lines[i].length();
        }
        return sum;
    }

    private int getAllowedTailLength(int sum, String[] lines)
    {
        return sum + lines[lines.length - 1].length();
    }
}
