/*
 * Copyright 2020 Laszlo Balazs-Csiki and Contributors
 *
 * This file is part of Pixelitor. Pixelitor is free software: you
 * can redistribute it and/or modify it under the terms of the GNU
 * General Public License, version 3 as published by the Free
 * Software Foundation.
 *
 * Pixelitor is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Pixelitor. If not, see <http://www.gnu.org/licenses/>.
 */

package pixelitor.tools.shapes;

import pixelitor.filters.gui.BooleanParam;
import pixelitor.filters.gui.EnumParam;
import pixelitor.filters.gui.RangeParam;
import pixelitor.filters.gui.StrokeParam;
import pixelitor.gui.utils.GridBagHelper;

import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.geom.QuadCurve2D;

import static java.awt.BorderLayout.CENTER;
import static java.awt.RenderingHints.KEY_ANTIALIASING;
import static java.awt.RenderingHints.VALUE_ANTIALIAS_ON;
import static javax.swing.BorderFactory.createTitledBorder;
import static pixelitor.tools.shapes.ShapeType.KIWI;
import static pixelitor.tools.shapes.StrokeType.BASIC;
import static pixelitor.tools.shapes.StrokeType.SHAPE;
import static pixelitor.tools.shapes.StrokeType.ZIGZAG;

/**
 * Stroke configuration used by the shapes tool and by
 * shape filters
 */
public class StrokeSettingsPanel extends JPanel {

    public StrokeSettingsPanel(StrokeParam sp) {
        RangeParam strokeWidthParam = sp.getStrokeWidthParam();

        setLayout(new GridBagLayout());

        JComponent strokeWidthGUI = strokeWidthParam.createGUI();
        GridBagConstraints gbc = new GridBagConstraints(
                0, 0, 1, 1,
                1.0, 0,
                GridBagConstraints.CENTER,
                GridBagConstraints.HORIZONTAL,
                new Insets(0, 0, 0, 0),
                3, 3);
        add(strokeWidthGUI, gbc);

        JPanel capJoinPanel = createCapJoinPanel(sp);
        gbc.gridy = 1;
        add(capJoinPanel, gbc);

        JPanel strokeTypePanel = createStrokeTypePanel(sp);
        gbc.gridy = 2;
        add(strokeTypePanel, gbc);

        JPanel strokePreviewPanel = createStrokePreviewPanel(sp);
        gbc.gridy = 3;
        gbc.weighty = 1.0;
        gbc.fill = GridBagConstraints.BOTH;
        add(strokePreviewPanel, gbc);
    }

    private static JPanel createCapJoinPanel(StrokeParam sp) {
        EnumParam<BasicStrokeCap> capParam = sp.getStrokeCapParam();
        EnumParam<BasicStrokeJoin> joinParam = sp.getStrokeJoinParam();

        var p = new JPanel();
        p.setBorder(createTitledBorder("Line Endpoints"));
        p.setLayout(new GridBagLayout());

        var gbh = new GridBagHelper(p);

        JComponent capSelector = capParam.createGUI();

        // Dirty trick: manually set the preferred width so that
        // the layout aligns with the layout in the other panel.
        // Doubling the width is about OK.
        Dimension dim = capSelector.getPreferredSize();
        dim.setSize(dim.getWidth() * 2, dim.getHeight());
        capSelector.setPreferredSize(dim);

        JComponent joinSelector = joinParam.createGUI();

        capParam.setToolTip("The shape of the line endpoints");
        joinParam.setToolTip("The way lines connect at the corners");

        gbh.addLabelAndControl(BasicStrokeCap.NAME + ":", capSelector);
        gbh.addLabelAndControl(BasicStrokeJoin.NAME + ":", joinSelector);

        return p;
    }

    private static JPanel createStrokeTypePanel(StrokeParam sp) {
        EnumParam<StrokeType> strokeTypeParam = sp.getStrokeTypeParam();
        BooleanParam dashedParam = sp.getDashedParam();
        EnumParam<ShapeType> shapeTypeParam = sp.getShapeTypeParam();

        var p = new JPanel();
        p.setBorder(createTitledBorder("Stroke Type"));

        p.setLayout(new GridBagLayout());

        shapeTypeParam.selectAndSetAsDefault(KIWI);

        strokeTypeParam.setupEnableOtherIf(shapeTypeParam,
                strokeType -> strokeType == SHAPE);

        strokeTypeParam.setupDisableOtherIf(dashedParam,
                strokeType -> strokeType != BASIC
                        && strokeType != ZIGZAG
                        && strokeType != SHAPE);

        var gbh = new GridBagHelper(p);
        JComponent strokeTypeGUI = strokeTypeParam.createGUI();
        strokeTypeGUI.setName("strokeType");
        gbh.addLabelAndControl(StrokeType.NAME + ":", strokeTypeGUI);

        JComponent shapeTypeGUI = shapeTypeParam.createGUI();
        shapeTypeGUI.setName("shapeType");
        gbh.addLabelAndControl(ShapeType.NAME + ":", shapeTypeGUI);

        JComponent dashedGUI = dashedParam.createGUI();
        dashedGUI.setName("dashed");
        gbh.addLabelAndControl("Dashed:", dashedGUI);

        return p;
    }

    private static JPanel createStrokePreviewPanel(StrokeParam sp) {
        JComponent preview = new JComponent() {
            final Dimension size = new Dimension(120, 120);

            @Override
            protected void paintComponent(Graphics g) {
                Graphics2D g2 = (Graphics2D) g;
                g2.setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_ON);
                g2.setColor(Color.WHITE);
                int width = getWidth();
                int height = getHeight();
                g2.fillRect(0, 0, width, height);
//                Line2D shape = new Line2D.Double(width * 0.1, height * 0.5, width * 0.9, height * 0.5);
                QuadCurve2D.Double shape = new QuadCurve2D.Double(
                        width * 0.1, height * 0.4,
                        width * 0.5, height * 0.8,
                        width * 0.9, height * 0.4
                );
                g2.setColor(Color.BLACK);
                g2.setStroke(sp.createStroke());
                g2.draw(shape);
            }

            @Override
            public Dimension getMinimumSize() {
                return size;
            }

            @Override
            public Dimension getPreferredSize() {
                return size;
            }
        };
        sp.setPreviewer(preview);

        var p = new JPanel(new BorderLayout());
        p.add(preview, CENTER);
        p.setBorder(createTitledBorder("Stroke Preview"));

        return p;
    }
}