/**
  * Check the properties extension point object.
  *
  * @param <P> The properties type.
  * @param clazz The class type.
  * @param id The extension id.
  * @param extension The extension attribute.
  * @return The properties instance from extension point or default one.
  */
 private static <P> Collection<P> checkPropertiesExtensionPoint(
     Class<P> clazz, String id, String extension) {
   final IConfigurationElement[] nodes =
       Platform.getExtensionRegistry().getConfigurationElementsFor(id);
   final Collection<P> extensions = new ArrayList<>();
   for (final IConfigurationElement node : nodes) {
     final String properties = node.getAttribute(extension);
     if (properties != null) {
       try {
         final P provider = UtilEclipse.createClass(properties, clazz);
         extensions.add(provider);
       } catch (final ReflectiveOperationException exception) {
         Verbose.exception(PropertiesPart.class, "checkPropertiesExtensionPoint", exception);
       }
     }
   }
   return extensions;
 }
/**
 * Dialog for tile collision edition.
 *
 * @author Pierre-Alexandre ([email protected])
 */
public class TileCollisionEditor extends AbstractEditor {
  /** Tile collision icon. */
  private static final Image ICON = UtilEclipse.getIcon("dialog", "edit.png");

  /** Default collision name. */
  private static final String DEFAULT_NAME = "default";

  /** Collision range. */
  private final CollisionRangeComposite range;
  /** Collision function. */
  private final CollisionFunctionComposite function;
  /** Formula name. */
  private Text textName;
  /** Edited formula. */
  private CollisionFormula formula;

  /**
   * Create the tile collision edition dialog.
   *
   * @param parent The parent reference.
   */
  public TileCollisionEditor(Shell parent) {
    super(parent, Messages.Dialog_TileCollision_Title, ICON);
    range = new CollisionRangeComposite();
    function = new CollisionFunctionComposite();
    setMinimumSize(320, 240);
  }

  /**
   * Load an existing formula and fill fields.
   *
   * @param formula The formula to load.
   */
  public void load(CollisionFormula formula) {
    textName.setText(formula.getName());

    range.load(formula.getRange());
    function.load(formula.getFunction());
  }

  /**
   * Get the edited collision formula.
   *
   * @return The edited collision formula instance.
   */
  public CollisionFormula getFormula() {
    return formula;
  }

  /*
   * AbstractEditor
   */

  @Override
  protected void createContent(Composite content) {
    final Composite composite = new Composite(content, SWT.NONE);
    composite.setLayout(new GridLayout(1, true));
    composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));

    textName = UtilSwt.createText(Messages.Dialog_TileCollision_Name, composite);
    textName.setText(DEFAULT_NAME);

    range.create(composite);
    function.create(composite);
  }

  @Override
  protected void onExit() {
    formula =
        new CollisionFormula(
            textName.getText(),
            range.get(),
            function.get(),
            new CollisionConstraint(null, null, null, null));
  }
}
/**
 * Animation editor dialog.
 *
 * @author Pierre-Alexandre ([email protected])
 */
public class AnimationEditor extends AbstractEditor {
  /** Dialog icon. */
  public static final Image ICON = UtilEclipse.getIcon("animation-editor", "dialog.png");

  /** Configurer reference. */
  private final Configurer configurer;
  /** Animations list. */
  private final AnimationList animationList;

  /**
   * Create an animation editor and associate its configurer.
   *
   * @param parent The parent reference.
   * @param configurer The entity configurer reference.
   */
  public AnimationEditor(Composite parent, Configurer configurer) {
    super(parent, Messages.AnimationEditor_Title, ICON);
    this.configurer = configurer;
    animationList = new AnimationList(configurer);
  }

  /**
   * Create the animation frame selector.
   *
   * @param parent The composite parent.
   * @return The created frame selector.
   */
  private AnimationFrameSelector createAnimationFrameSelector(TabFolder parent) {
    final Composite sheet = new Composite(parent, SWT.NONE);
    sheet.setLayout(new GridLayout(1, false));
    sheet.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

    final TabItem sheetTab = new TabItem(parent, SWT.NONE);
    sheetTab.setText(Messages.AnimationEditor_Sheet);
    sheetTab.setControl(sheet);

    final Composite renderer = new Composite(sheet, SWT.BORDER | SWT.DOUBLE_BUFFERED);
    final AnimationFrameSelector animationFrameSelector =
        new AnimationFrameSelector(renderer, configurer);
    renderer.addPaintListener(animationFrameSelector);
    renderer.addMouseListener(animationFrameSelector);
    renderer.addMouseMoveListener(animationFrameSelector);

    return animationFrameSelector;
  }

  /**
   * Create the animator area, where the animation is played and controlled.
   *
   * @param parent The composite parent.
   * @return The created composite.
   */
  private AnimationRenderer createAnimationRenderer(TabFolder parent) {
    final Composite content = new Composite(parent, SWT.NONE);
    content.setLayout(new GridLayout(1, false));
    content.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

    final Composite renderer = new Composite(content, SWT.BORDER | SWT.DOUBLE_BUFFERED);
    final AnimationRenderer animationRenderer = new AnimationRenderer(renderer, configurer);
    renderer.addPaintListener(animationRenderer);

    final TabItem animatorTab = new TabItem(parent, SWT.NONE);
    animatorTab.setText(Messages.AnimationEditor_Animator);
    animatorTab.setControl(content);

    return animationRenderer;
  }

  /*
   * AbstractEditor
   */

  @Override
  protected void createContent(Composite parent) {
    final Composite content = new Composite(parent, SWT.NONE);
    content.setLayout(new GridLayout(2, false));
    content.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

    final Group animGroup = new Group(content, SWT.NONE);
    animGroup.setLayout(new GridLayout(1, false));
    animGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
    animGroup.setText(Messages.AnimationEditor_Animation);

    final TabFolder animationTabs = new TabFolder(animGroup, SWT.TOP);
    final AnimationFrameSelector animationFrameSelector =
        createAnimationFrameSelector(animationTabs);
    final AnimationRenderer animationRenderer = createAnimationRenderer(animationTabs);

    final AnimationProperties animationProperties =
        new AnimationProperties(animationList, animationRenderer);
    animationList.addListener(animationProperties);
    final AnimationPlayer animationPlayer = new AnimationPlayer(animationList, animationRenderer);
    animationPlayer.createAnimationPlayer(animationRenderer.getParent().getParent());

    animationFrameSelector.setAnimationList(animationList);
    animationFrameSelector.setAnimationProperties(animationProperties);
    animationProperties.setAnimationFrameSelector(animationFrameSelector);
    animationRenderer.setAnimationPlayer(animationPlayer);

    final Composite properties = new Composite(content, SWT.NONE);
    properties.setLayout(new GridLayout(1, false));
    properties.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

    animationList.create(properties);
    animationProperties.create(properties);
    animationList.loadAnimations();
  }

  @Override
  protected void onExit() {
    final XmlNode root = configurer.getRoot();
    root.removeChildren(ConfigAnimations.ANIMATION);
    for (final TreeItem item : animationList.getTree().getItems()) {
      final Animation animation = (Animation) item.getData();
      final XmlNode nodeAnim = ConfigAnimations.createNode(animation);
      root.add(nodeAnim);
    }
    configurer.save();
  }
}