content: /*
   * Copyright 2010, 2011, 2012 mapsforge.org
   * Copyright 2013 Hannes Janetzek
   *
   * This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
   *
   * This program is free software: you can redistribute it and/or modify it under the
   * terms of the GNU Lesser General Public License as published by the Free Software
   * Foundation, either version 3 of the License, or (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful, but WITHOUT ANY
   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
   * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public License along with
   * this program. If not, see <http://www.gnu.org/licenses/>.
   */
  package org.oscim.utils;
  
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  /**
   * An abstract base class for threads which support pausing and resuming.
   */
  public abstract class PausableThread extends Thread {
      private static final Logger log = LoggerFactory.getLogger(PausableThread.class);
      private static final boolean dbg = false;
  
      private boolean mPausing = true;
      private boolean mRunning = true;
      private boolean mShouldPause = false;
      private boolean mShouldStop = false;
  
      /**
       * Causes the current thread to wait until this thread is pausing.
       */
      public final void awaitPausing() {
          synchronized (this) {
  
              while (!isPausing()) {
  
                  if (dbg)
                      log.debug("Await Pause {}", getThreadName());
  
                  try {
                      wait(100);
                  } catch (InterruptedException e) {
                      /* restore the interrupted status */
                      this.interrupt();
                  }
              }
          }
      }
  
      public synchronized void finish() {
          if (!mRunning)
              return;
  
          log.debug("Finish {}", getThreadName());
  
          mShouldStop = true;
          this.interrupt();
      }
  
      /**
       * @return true if this thread is currently pausing, false otherwise.
       */
      public final synchronized boolean isPausing() {
          return mPausing;
      }
  
      /**
       * The thread should stop its work temporarily.
       */
      public final synchronized void pause() {
          if (!mShouldPause) {
              mShouldPause = true;
              this.interrupt();
          }
      }
  
      /**
       * The paused thread should continue with its work.
       */
      public final synchronized void proceed() {
          if (mShouldPause) {
              mShouldPause = false;
              notify();
          }
      }
  
      public final synchronized boolean isCanceled() {
          return mShouldPause;
      }
  
      @Override
      public final void run() {
          mRunning = true;
          setName(getThreadName());
          setPriority(getThreadPriority());
  
          O:
          while (!mShouldStop) {
  
              synchronized (this) {
                  if (mShouldStop)
                      break;
  
                  while ((mShouldPause || !hasWork())) {
                      try {
                          if (mShouldPause) {
                              mPausing = true;
  
                              if (dbg)
                                  log.debug("Pausing: {}",
                                          getThreadName());
                          }
  
                          wait();
  
                      } catch (InterruptedException e) {
                          if (dbg)
                              log.debug("Interrupted {} {}:{}",
                                      getThreadName(),
                                      mShouldPause,
                                      mShouldStop);
  
                          if (mShouldStop)
                              break O;
                      }
                  }
  
                  if (mPausing) {
                      mPausing = false;
                      afterPause();
                  }
              }
  
              try {
                  doWork();
              } catch (InterruptedException e) {
                  if (dbg)
                      log.debug("Interrupted {} {}:{}",
                              getThreadName(),
                              mShouldPause,
                              mShouldStop);
  
              }
          }
  
          log.debug("Done {}", getThreadName());
  
          mPausing = true;
          mRunning = false;
  
          afterRun();
      }
  
      /**
       * Called once when this thread continues to work after a pause. The default
       * implementation is empty.
       */
      protected void afterPause() {
          // do nothing
      }
  
      /**
       * Called once at the end of the {@link #run()} method. The default
       * implementation is empty.
       */
      protected void afterRun() {
          // do nothing
      }
  
      /**
       * Called when this thread is not paused and should do its work.
       *
       * @throws InterruptedException if the thread has been interrupted.
       */
      protected abstract void doWork() throws InterruptedException;
  
      /**
       * @return the name of this thread.
       */
      protected abstract String getThreadName();
  
      /**
       * @return the priority of this thread. The default value is
       * {@link Thread#NORM_PRIORITY}.
       */
      protected int getThreadPriority() {
          return Thread.NORM_PRIORITY;
      }
  
      /**
       * @return true if this thread has some work to do, false otherwise.
       */
      protected abstract boolean hasWork();
  }
  