// Copyright 2013 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.

#ifndef CC_RESOURCES_WORKER_POOL_H_
#define CC_RESOURCES_WORKER_POOL_H_

#include <deque>
#include <string>
#include <vector>

#include "base/cancelable_callback.h"
#include "base/containers/scoped_ptr_hash_map.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "cc/base/cc_export.h"

namespace cc {
namespace internal {

class CC_EXPORT WorkerPoolTask
    : public base::RefCountedThreadSafe<WorkerPoolTask> {
 public:
  virtual void RunOnWorkerThread(unsigned thread_index) = 0;
  virtual void CompleteOnOriginThread() = 0;

  void DidSchedule();
  void WillRun();
  void DidRun();
  void WillComplete();
  void DidComplete();

  bool HasFinishedRunning() const;
  bool HasCompleted() const;

 protected:
  friend class base::RefCountedThreadSafe<WorkerPoolTask>;

  WorkerPoolTask();
  virtual ~WorkerPoolTask();

 private:
  bool did_schedule_;
  bool did_run_;
  bool did_complete_;
};

class CC_EXPORT GraphNode {
 public:
  typedef std::vector<GraphNode*> Vector;

  GraphNode(internal::WorkerPoolTask* task, unsigned priority);
  ~GraphNode();

  WorkerPoolTask* task() { return task_; }

  void add_dependent(GraphNode* dependent) {
    DCHECK(dependent);
    dependents_.push_back(dependent);
  }
  const Vector& dependents() const { return dependents_; }

  unsigned priority() const { return priority_; }

  unsigned num_dependencies() const { return num_dependencies_; }
  void add_dependency() { ++num_dependencies_; }
  void remove_dependency() {
    DCHECK(num_dependencies_);
    --num_dependencies_;
  }

 private:
  WorkerPoolTask* task_;
  Vector dependents_;
  unsigned priority_;
  unsigned num_dependencies_;

  DISALLOW_COPY_AND_ASSIGN(GraphNode);
};

}  // namespace internal
}  // namespace cc

#if defined(COMPILER_GCC)
namespace BASE_HASH_NAMESPACE {
template <> struct hash<cc::internal::WorkerPoolTask*> {
  size_t operator()(cc::internal::WorkerPoolTask* ptr) const {
    return hash<size_t>()(reinterpret_cast<size_t>(ptr));
  }
};
}  // namespace BASE_HASH_NAMESPACE
#endif  // COMPILER

namespace cc {

// A worker thread pool that runs tasks provided by task graph and
// guarantees completion of all pending tasks at shutdown.
class CC_EXPORT WorkerPool {
 public:
  virtual ~WorkerPool();

  // Tells the worker pool to shutdown and returns once all pending tasks have
  // completed.
  virtual void Shutdown();

  // Force a check for completed tasks.
  virtual void CheckForCompletedTasks();

 protected:
  // A task graph contains a unique set of tasks with edges between
  // dependencies pointing in the direction of the dependents. Each task
  // need to be assigned a unique priority and a run count that matches
  // the number of dependencies.
  typedef base::ScopedPtrHashMap<internal::WorkerPoolTask*, internal::GraphNode>
      GraphNodeMap;
  typedef GraphNodeMap TaskGraph;

  WorkerPool(size_t num_threads, const std::string& thread_name_prefix);

  // Schedule running of tasks in |graph|. Any previously scheduled tasks
  // that are not already running will be canceled. Canceled tasks don't run
  // but completion of them is still processed.
  void SetTaskGraph(TaskGraph* graph);

 private:
  class Inner;
  friend class Inner;

  typedef std::vector<scoped_refptr<internal::WorkerPoolTask> > TaskVector;

  void ProcessCompletedTasks(const TaskVector& completed_tasks);

  bool in_dispatch_completion_callbacks_;

  // Hide the gory details of the worker pool in |inner_|.
  const scoped_ptr<Inner> inner_;
};

}  // namespace cc

#endif  // CC_RESOURCES_WORKER_POOL_H_