// License: GPL. For details, see LICENSE file.
package relcontext.actions;

import static org.openstreetmap.josm.tools.I18n.tr;

import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.Action;

import org.openstreetmap.josm.command.Command;
import org.openstreetmap.josm.data.UndoRedoHandler;
import org.openstreetmap.josm.data.osm.Relation;
import org.openstreetmap.josm.data.osm.RelationMember;
import org.openstreetmap.josm.tools.ImageProvider;

import relcontext.ChosenRelation;
import relcontext.ChosenRelationListener;
import relcontext.relationfix.AssociatedStreetFixer;
import relcontext.relationfix.BoundaryFixer;
import relcontext.relationfix.MultipolygonFixer;
import relcontext.relationfix.NothingFixer;
import relcontext.relationfix.PublicTransportFixer;
import relcontext.relationfix.RelationFixer;

public class SortAndFixAction extends AbstractAction implements ChosenRelationListener {
    private static final long serialVersionUID = 1L;
    private final ChosenRelation rel;
    private final List<RelationFixer> fixers;

    public SortAndFixAction(ChosenRelation rel) {
        super();
        //        putValue(Action.NAME, "AZ");
        putValue(Action.SMALL_ICON, ImageProvider.get("data", "warning"));
        putValue(Action.SHORT_DESCRIPTION, tr("Fix roles of the chosen relation members"));
        this.rel = rel;
        rel.addChosenRelationListener(this);
        setEnabled(false);

        // construct all available fixers
        fixers = new ArrayList<>();
        //should be before multipolygon as takes special case of multipolygon relation - boundary
        fixers.add(new BoundaryFixer()); // boundary, multipolygon, boundary=administrative
        fixers.add(new MultipolygonFixer()); // multipolygon
        fixers.add(new AssociatedStreetFixer()); //associatedStreet
        fixers.add(new PublicTransportFixer()); //public_transport

        for (RelationFixer fix : fixers) {
            fix.setFixAction(this);
        }
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        Command c = fixRelation(rel.get());
        if (c != null) {
            UndoRedoHandler.getInstance().add(c);
        }
    }

    @Override
    public void chosenRelationChanged(Relation oldRelation, Relation newRelation) {
        setEnabled(newRelation != null && needsFixing(newRelation));
    }

    public boolean needsFixing(Relation rel) {
        return !isIncomplete(rel) && !getFixer(rel).isRelationGood(rel);
    }

    private RelationFixer getFixer(Relation rel) {
        for (RelationFixer fixer : fixers) {
            if (fixer.isFixerApplicable(rel))
                return fixer;
        }
        return new NothingFixer();
    }

    public Command fixRelation(Relation rel) {
        return getFixer(rel).fixRelation(rel);
    }

    protected static boolean isIncomplete(Relation r) {
        if (r == null || r.isIncomplete() || r.isDeleted())
            return true;
        for (RelationMember m : r.getMembers()) {
            if (m.getMember().isIncomplete())
                return true;
        }
        return false;
    }
}
