package CH.ifa.draw.gui;

import java.awt.Component;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import javax.swing.AbstractButton;


/**
 * A customizable layout for the toolbar.
 * <p>
 * Depends on the buttons having a unique name.
 * @deprecated This class is not to be used externally and will later be hidden.
 */
@Deprecated
public class StorableButtonContainerLayout {

    /**
     * Layout for ButtonContainers, contains a list of the names of the different buttons that are part
     * of the ButtonContainer layout.
     */
    protected final List<List<String>> _layout;
    /**
     * Palettes that are required for this layout to exist.
     */
    protected final Set<String> _requiredPalettes;
    /**
     * Name for the ButtonContainer layout, should be unique for each layout.
     */
    protected final String _layoutName;


    private static final org.apache.log4j.Logger LOGGER =
        org.apache.log4j.Logger.getLogger(StorableButtonContainerLayout.class);


    private StorableButtonContainerLayout(
        List<List<String>> layout, Set<String> requiredPalettes, String layoutName)
    {
        this._layout = layout;
        this._requiredPalettes = requiredPalettes;
        this._layoutName = layoutName;
    }

    @Override
    public String toString() {
        return _layoutName;
    }

    @Override
    public boolean equals(Object o) {
        if (!(o instanceof StorableButtonContainerLayout)) {
            return false;
        }
        return (this._layoutName.equals(((StorableButtonContainerLayout) o)._layoutName));
    }

    /**
     * Check if this layout can be used with the available palettes.
     *
     * @param availablePalettes palettes that are checked, if they contain all the requiredPalettes
     * @return result, true if palettes can be used (and false if not)
     */
    public boolean isAvailable(Set<String> availablePalettes) {
        return availablePalettes.containsAll(_requiredPalettes);
    }

    /**
     * Creates a new StorableButtonContainerLayout.
     * @param components array of buttons that will be part of the layout
     * @param groupLookup map of Buttons and the group name of their required palette
     * @param layoutName name for the layout, should be unique for each layout
     * @return StorableButtonContainerLayout that is created
     */
    public static StorableButtonContainerLayout createLayout(
        Component[] components, Map<String, String> groupLookup, String layoutName)
    {

        List<List<String>> layout = new ArrayList<>();
        Component[] buttons;
        Set<String> requiredPalettes = new HashSet<>();

        for (Component component : components) {
            if (component instanceof ToolButtonContainer) {

                List<String> container = new ArrayList<>();
                buttons = ((ToolButtonContainer) component).getButtons();

                for (Component button : buttons) {
                    String name = button.getName();
                    if (name != null && !name.isEmpty()) {

                        container.add(name);
                        String group = groupLookup.get(name);
                        if (group != null) {
                            requiredPalettes.add(group);
                        }
                    }

                }
                layout.add(container);

            }

        }

        return new StorableButtonContainerLayout(layout, requiredPalettes, layoutName);
    }

    /**
     * Lists all buttons that are part of a layout.
     * @param layout the layout of which the buttons are listed
     * @param buttonLookup list of all buttons with name and type of button
     * @return result, is a list of buttons that are part of the layout
     */
    public static List<Set<AbstractButton>> readLayout(
        StorableButtonContainerLayout layout, Map<String, AbstractButton> buttonLookup)
    {

        List<Set<AbstractButton>> result = new ArrayList<>();

        for (List<String> set : layout._layout) {

            Set<AbstractButton> buttonSet = new LinkedHashSet<>();

            for (String name : set) {
                buttonSet.add(buttonLookup.get(name));
            }
            result.add(buttonSet);
        }
        return result;
    }

    /**
     * Creates a list of {@link StorableButtonContainerLayout} from a properties file.
     *
     * @param properties {@link Properties} file from which the list of StorableButtonContainerLayout is created
     * @return result, list of {@link StorableButtonContainerLayout} that is created
     */
    public static List<StorableButtonContainerLayout> createLayoutsFromProperties(
        Properties properties)
    {

        String name;
        String[] splitString;
        Set<String> requiredPalettes;
        ButtonLayoutParser parser;
        List<List<String>> layout;
        List<StorableButtonContainerLayout> result = new ArrayList<>();

        for (Map.Entry<Object, Object> entry : properties.entrySet()) {

            try {
                name = (String) entry.getKey();
                String data = (String) entry.getValue();

                splitString = data.split("%");

                // An empty layout might have been saved, so we have to check here.
                if (splitString.length > 1) {
                    // Find required palettes
                    data = splitString[1];
                    parser = new ButtonLayoutParser(new StringReader(data));
                    requiredPalettes = parser.parseRequiredPalettes();

                    // Find containers
                    data = splitString[0];
                    parser = new ButtonLayoutParser(new StringReader(data));
                    layout = parser.parseButtons();

                    result.add(new StorableButtonContainerLayout(layout, requiredPalettes, name));
                } else {
                    result.add(
                        new StorableButtonContainerLayout(
                            new ArrayList<>(), new HashSet<>(), name));
                }
            } catch (ParseException e) {
                LOGGER.error("Parsing of data failed" + e + "\n");
            } catch (TokenMgrError error) {
                LOGGER.error("Parsing of token failed" + error + "\n");
            }
        }

        return result;
    }

    /**
     * Write the provided layout into the {@link Properties} file.
     *
     * @param properties is the {@link Properties} file that the layout is written into
     * @param layout is written in to the {@link Properties} file.
     */
    public static void writeToProperties(
        Properties properties, StorableButtonContainerLayout layout)
    {

        StringBuilder builder = new StringBuilder();

        for (List<String> container : layout._layout) {
            for (String button : container) {
                builder.append(button);
                builder.append(",");
            }
            builder.append(";");
        }
        builder.append("%");
        for (String group : layout._requiredPalettes) {
            builder.append(group);
            builder.append(",");
        }

        properties.put(layout._layoutName, builder.toString());
    }
}
