// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.sdk.util;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Helper class that destructs unfinished objects. It is needed when Java GC is not enough.
 * It requires to be explicitly discharged if all went OK and destruction should be cancelled.
 * Using this class may be more convenient that try/finally in Java.
 * <p>User may subclass this class to override exception logging in handleFinallyProblem
 * methods.
 */
public class DestructingGuard {
  private static final Logger LOGGER = Logger.getLogger(DestructingGuard.class.getName());

  /**
   * Confirms that constructing has finished OKAY and no destruction is needed from now.
   */
  public void discharge() {
    discharged = true;
  }

  /**
   * This method is supposed to be called from finally clause. It performs destructing
   * unless {@link #discharge()} has been called.
   */
  public void doFinally() {
    if (discharged) {
      return;
    }
    for (int i = destructables.size() - 1; i >= 0; i--) {
      try {
        destructables.get(i).destruct();
      } catch (RuntimeException e) {
        handleFinallyProblem(e);
      } catch (Error e) {
        handleFinallyProblem(e);
      }
    }
    discharged = true;
  }

  /**
   * Adds another value that should be destructed. Added values are destructed in reversed order.
   */
  public void addValue(Destructable destructable) {
    this.destructables.add(destructable);
  }

  protected void handleFinallyProblem(RuntimeException e) {
    LOGGER.log(Level.SEVERE, "Exception in finally handler", e);
  }

  protected void handleFinallyProblem(Error e) {
    LOGGER.log(Level.SEVERE, "Exception in finally handler", e);
  }

  private List<Destructable> destructables = new ArrayList<Destructable>(1);
  private boolean discharged = false;
}
