/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Eclipse Public License, Version 1.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.eclipse.org/org/documents/epl-v10.php
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.ide.common.layout.grid;

import static com.android.ide.common.layout.grid.GridModel.UNDEFINED;

import com.android.ide.common.api.INode;
import com.android.ide.common.api.SegmentType;

/**
 * A match for a drag within a GridLayout, corresponding to an alignment with another
 * edge, or a margin, or centering, or a gap distance from another edge and so on.
 */
class GridMatch implements Comparable<GridMatch> {
    /** The distance to the matched edge - used to pick best matches */
    public final int distance;

    /** Type of edge that was matched (this refers to the edge on the dragged node,
     * not on the matched node/row/cell etc) */
    public final SegmentType type;

    /** Row or column for the match */
    public int cellIndex;

    /** If true, create a new row/column */
    public boolean createCell;

    /** The actual x or y position of the matched segment */
    public int matchedLine;

    /** Amount of margin between the matched edges */
    public int margin;

    /**
     * Constructs a match.
     *
     * @param type the edge of the dragged element that was matched
     * @param distance the absolute distance from the ideal match - used to find the best
     *            match
     * @param matchedLine the actual X or Y location of the ideal match
     * @param cellIndex the index of the row or column we matched with
     * @param createCell if true, create a new cell by splitting the existing cell at the
     *            matchedLine position
     * @param margin a margin distance to add to the actual location from the matched line
     */
    GridMatch(SegmentType type, int distance, int matchedLine, int cellIndex,
            boolean createCell, int margin) {
        super();
        this.type = type;
        this.distance = distance;
        this.matchedLine = matchedLine;
        this.cellIndex = cellIndex;
        this.createCell = createCell;
        this.margin = margin;
    }

    // Implements Comparable<GridMatch>
    public int compareTo(GridMatch o) {
        // Pick closest matches first
        if (distance != o.distance) {
            return distance - o.distance;
        }

        // Prefer some types of matches over other matches
        return getPriority() - o.getPriority();
    }

    /**
     * Describes the match for the user
     *
     * @param layout the GridLayout containing the match
     * @return a short description for the user of the match
     */
    public String getDisplayName(INode layout) {
        switch (type) {
            case BASELINE:
                return String.format("Align baseline in row %1$d", cellIndex);
            case CENTER_HORIZONTAL:
                return "Center horizontally";
            case LEFT:
                if (!createCell) {
                    return String.format("Insert into column %1$d", cellIndex);
                }
                if (margin != UNDEFINED) {
                    if (cellIndex == 0 && margin != 0) {
                        return "Add one margin distance from the left";
                    }
                    return String.format("Add next to column %1$d", cellIndex);
                }
                return String.format("Align left at x=%1$d", matchedLine - layout.getBounds().x);
            case RIGHT:
                if (!createCell) {
                    return String.format("Insert right-aligned into column %1$d", cellIndex);
                }
                return String.format("Align right at x=%1$d", matchedLine - layout.getBounds().x);
            case TOP:
                if (!createCell) {
                    return String.format("Insert into row %1$d", cellIndex);
                }
                if (margin != UNDEFINED) {
                    if (cellIndex == 0 && margin != 0) {
                        return "Add one margin distance from the top";
                    }
                    return String.format("Add below row %1$d", cellIndex);
                }
                return String.format("Align top at y=%1d", matchedLine - layout.getBounds().y);
            case BOTTOM:
                if (!createCell) {
                    return String.format("Insert into bottom of row %1$d", cellIndex);
                }
                return String.format("Align bottom at y=%1d", matchedLine - layout.getBounds().y);
            case CENTER_VERTICAL:
            case UNKNOWN:
            default:
                return null;
        }
    }

    /**
     * Computes the sorting priority of this match, giving baseline matches higher
     * precedence than centering which in turn is ordered before external edge matches
     */
    private int getPriority() {
        switch (type) {
            case BASELINE:
                return 0;
            case CENTER_HORIZONTAL:
            case CENTER_VERTICAL:
                return 1;
            case BOTTOM:
            case LEFT:
            case RIGHT:
            case TOP:
                return 2;
        }

        return 3;
    }
}