/*******************************************************************************
 * Copyright (c) 2013, 2015 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     René Brandstetter - Bug 411821 - [QuickAccess] Contribute SearchField
 *                                      through a fragment or other means
 ******************************************************************************/

package org.eclipse.e4.ui.model.internal;

/**
 * A holder class for the full information to position an element in a list.
 *
 * @author René Brandstetter
 */
public final class PositionInfo {
  /** The position type to use. */
  private final Position position;

  /**
   * The additional positioning information which can be used to position an
   * element relative to another element.
   */
  private final String positionReference;

  /**
   * The {@link PositionInfo} which represent an insert at the beginning of
   * the list.
   */
  public static final PositionInfo FIRST = new PositionInfo(Position.FIRST, null);

  /**
   * The {@link PositionInfo} which represent an insert at the end of the
   * list.
   */
  public static final PositionInfo LAST = new PositionInfo(Position.LAST, null);

  /**
   * Creates an instance of the PositionInfo.
   *
   * @param position
   *          the kind of the positioning
   * @param positionReference
   *          additional information which is need to position an element
   *          (e.g.: index, ID of another element)
   * @throws NullPointerException
   *           if the <code>position</code> is <code>null</code>
   */
  public PositionInfo(Position position, String positionReference) {
    if (position == null) {
      throw new NullPointerException("No position given!");
    }

    this.position = position;
    this.positionReference = positionReference;
  }

  /**
   * Returns the kind/type of positioning which should be used.
   *
   * @return the position
   */
  public Position getPosition() {
    return position;
  }

  /**
   * Returns additional information which is needed to place an element.
   *
   * @return the positionReference, or <code>null</code> if no additional information is given
   */
  public String getPositionReference() {
    return positionReference;
  }

  /**
   * Returns the additional information which is needed to place an element as
   * an int.
   *
   * @return the positionReference as an int
   * @throws NumberFormatException
   *           if the {@link #positionReference} can't be parsed to an int
   * @throws NullPointerException
   *           if the {@link #positionReference} is <code>null</code>
   */
  public int getPositionReferenceAsInteger() {
    return Integer.parseInt(positionReference);
  }

  /**
   * Creates a {@link PositionInfo} object out of the given positioning
   * string.
   *
   * <p>
   * <b>Examples for a positioning string:</b>
   * <ul>
   * <li><code>last</code> - place an element to the end of a list</li>
   * <li><code>first</code> - place an element to the beginning of a list</li>
   * <li><code>index:3</code> - place an element at the provided index 3 in a
   * list</li>
   * <li><code>before:org.eclipse.test.id</code> - place an element in a list
   * in front of the element with the ID "org.eclipse.test.id"</li>
   * <li><code>after:org.eclipse.test.id</code> - place an element in a list
   * after the element with the ID "org.eclipse.test.id"</li>
   * </ul>
   * </p>
   *
   * @param positionInfo
   *          the positioning string
   * @return a {@link PositionInfo} which holds all the data mentioned in the
   *         positioning string, or <code>null</code> if the positioning
   *         string doesn't hold a positioning information
   */
  public static PositionInfo parse(String positionInfo) {
    Position position = Position.find(positionInfo);
    if (position != null) {
      switch (position) {
        case FIRST:
          return PositionInfo.FIRST;

        case LAST:
          return PositionInfo.LAST;

        default:
          return new PositionInfo(position, positionInfo.substring(position.prefix.length()));
      }
    }

    return null;
  }

  @Override
  public String toString() {
    StringBuilder back = new StringBuilder(position.prefix);
    if (positionReference != null) {
      back.append(positionReference);
    }
    return back.toString();
  }
}