// License: GPL. For details, see LICENSE file.
package mergeoverlap.hack;

import java.awt.Component;
import java.beans.PropertyChangeEvent;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.openstreetmap.josm.command.ChangePropertyCommand;
import org.openstreetmap.josm.command.Command;
import org.openstreetmap.josm.data.osm.OsmPrimitive;
import org.openstreetmap.josm.data.osm.Relation;
import org.openstreetmap.josm.data.osm.TagCollection;
import org.openstreetmap.josm.data.osm.Way;
import org.openstreetmap.josm.gui.MainApplication;
import org.openstreetmap.josm.gui.conflict.tags.CombinePrimitiveResolverDialog;
import org.openstreetmap.josm.gui.conflict.tags.TagConflictResolverModel;
import org.openstreetmap.josm.gui.util.GuiHelper;

/**
 * This dialog helps to resolve conflicts occurring when ways are combined or
 * nodes are merged.
 *
 * There is a singleton instance of this dialog which can be retrieved using
 * {@link #getInstance()}.
 *
 * The dialog uses two models: one  for resolving tag conflicts, the other
 * for resolving conflicts in relation memberships. For both models there are accessors,
 * i.e {@link #getTagConflictResolverModel()} and {@link #getRelationMemberConflictResolverModel()}.
 *
 * Models have to be <strong>populated</strong> before the dialog is launched. Example:
 * <pre>
 *    CombinePrimitiveResolverDialog dialog = CombinePrimitiveResolverDialog.getInstance();
 *    dialog.getTagConflictResolverModel().populate(aTagCollection);
 *    dialog.getRelationMemberConflictResolverModel().populate(aRelationLinkCollection);
 *    dialog.prepareDefaultDecisions();
 * </pre>
 *
 * You should also set the target primitive which other primitives (ways or nodes) are
 * merged to, see {@link #setTargetPrimitive(OsmPrimitive)}.
 *
 * After the dialog is closed use {@link #isCanceled()} to check whether the user canceled
 * the dialog. If it wasn't canceled you may build a collection of {@link Command} objects
 * which reflect the conflict resolution decisions the user made in the dialog:
 * see {@link #buildResolutionCommands()}
 */
public class MyCombinePrimitiveResolverDialog extends CombinePrimitiveResolverDialog {

    /** the unique instance of the dialog */
    private static MyCombinePrimitiveResolverDialog instance;

    /**
     * Constructs a new {@code MyCombinePrimitiveResolverDialog}.
     * @param parent The parent component in which this dialog will be displayed.
     */
    public MyCombinePrimitiveResolverDialog(Component parent) {
        super(parent, new TagConflictResolverModel(), new MyRelationMemberConflictResolverModel());
    }

    /**
     * Replies the unique instance of the dialog
     *
     * @return the unique instance of the dialog
     */
    public static MyCombinePrimitiveResolverDialog getInstance() {
        if (instance == null) {
            GuiHelper.runInEDTAndWait(() -> instance = new MyCombinePrimitiveResolverDialog(MainApplication.getMainFrame()));
        }
        return instance;
    }

    @Override
    protected ApplyAction buildApplyAction() {
        return new ApplyAction() {
            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                super.propertyChange(evt);
                if (evt.getPropertyName().equals(MyRelationMemberConflictResolverModel.NUM_CONFLICTS_PROP)) {
                    updateEnabledState();
                }
            }
        };
    }

    /**
     * Replies the relation membership conflict resolver model.
     * @return The relation membership conflict resolver model.
     */
    @Override
    public MyRelationMemberConflictResolverModel getRelationMemberConflictResolverModel() {
        return (MyRelationMemberConflictResolverModel) pnlRelationMemberConflictResolver.getModel();
    }

    /**
     * Replies the list of {@link Command commands} needed to apply resolution choices.
     * @return The list of {@link Command commands} needed to apply resolution choices.
     */
    public List<Command> buildWayResolutionCommands() {
        List<Command> cmds = new LinkedList<>();

        TagCollection allResolutions = getTagConflictResolverModel().getAllResolutions();
        if (!allResolutions.isEmpty()) {
            cmds.addAll(buildTagChangeCommand(targetPrimitive, allResolutions));
        }
        if (targetPrimitive.get("created_by") != null) {
            cmds.add(new ChangePropertyCommand(targetPrimitive, "created_by", null));
        }

        Command cmd = pnlRelationMemberConflictResolver.buildTagApplyCommands(getRelationMemberConflictResolverModel()
                .getModifiedRelations(targetPrimitive));
        if (cmd != null) {
            cmds.add(cmd);
        }
        return cmds;
    }

    public void buildRelationCorrespondance(Map<Relation, Relation> newRelations, Map<Way, Way> oldWays) {
        getRelationMemberConflictResolverModel().buildRelationCorrespondance(targetPrimitive, newRelations, oldWays);
    }
}
