// Copyright (c) 2011 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 CHROME_BROWSER_NET_CHROME_NET_LOG_H_
#define CHROME_BROWSER_NET_CHROME_NET_LOG_H_
#pragma once

#include <vector>

#include "base/atomicops.h"
#include "base/memory/scoped_ptr.h"
#include "base/observer_list.h"
#include "base/synchronization/lock.h"
#include "base/time.h"
#include "net/base/net_log.h"

class LoadTimingObserver;
class NetLogLogger;
class PassiveLogCollector;

// ChromeNetLog is an implementation of NetLog that dispatches network log
// messages to a list of observers.
//
// All methods are thread safe, with the exception that no ChromeNetLog or
// ChromeNetLog::ThreadSafeObserver functions may be called by an observer's
// OnAddEntry() method.  Doing so will result in a deadlock.
//
// By default, ChromeNetLog will attach the observer PassiveLogCollector which
// will keep track of recent request information (which used when displaying
// the about:net-internals page).
//
class ChromeNetLog : public net::NetLog {
 public:
  // This structure encapsulates all of the parameters of an event,
  // including an "order" field that identifies when it was captured relative
  // to other events.
  struct Entry {
    Entry(uint32 order,
          net::NetLog::EventType type,
          const base::TimeTicks& time,
          net::NetLog::Source source,
          net::NetLog::EventPhase phase,
          net::NetLog::EventParameters* params);
    ~Entry();

    uint32 order;
    net::NetLog::EventType type;
    base::TimeTicks time;
    net::NetLog::Source source;
    net::NetLog::EventPhase phase;
    scoped_refptr<net::NetLog::EventParameters> params;
  };

  typedef std::vector<Entry> EntryList;

  // Interface for observing the events logged by the network stack.
  class ThreadSafeObserver {
   public:
    // Constructs an observer that wants to see network events, with
    // the specified minimum event granularity.  A ThreadSafeObserver can only
    // observe a single ChromeNetLog at a time.
    //
    // Typical observers should specify LOG_BASIC.
    //
    // Observers that need to see the full granularity of events can
    // specify LOG_ALL. However doing so will have performance consequences,
    // and may cause PassiveLogCollector to use more memory than anticipated.
    //
    // Observers will be called on the same thread an entry is added on,
    // and are responsible for ensuring their own thread safety.
    explicit ThreadSafeObserver(LogLevel log_level);

    virtual ~ThreadSafeObserver();

    // This method will be called on the thread that the event occurs on.  It
    // is the responsibility of the observer to handle it in a thread safe
    // manner.
    //
    // It is illegal for an Observer to call any ChromeNetLog or
    // ChromeNetLog::ThreadSafeObserver functions in response to a call to
    // OnAddEntry.
    virtual void OnAddEntry(EventType type,
                            const base::TimeTicks& time,
                            const Source& source,
                            EventPhase phase,
                            EventParameters* params) = 0;
    LogLevel log_level() const;

   protected:
    void AssertNetLogLockAcquired() const;

    // Can only be called when actively observing a ChromeNetLog.
    void SetLogLevel(LogLevel log_level);

    // ChromeNetLog currently being observed, if any.  Set by ChromeNetLog's
    // AddObserver and RemoveObserver methods.
    ChromeNetLog* net_log_;

   private:
    friend class ChromeNetLog;
    LogLevel log_level_;
    DISALLOW_COPY_AND_ASSIGN(ThreadSafeObserver);
  };

  ChromeNetLog();
  ~ChromeNetLog();

  // NetLog implementation:
  virtual void AddEntry(EventType type,
                        const base::TimeTicks& time,
                        const Source& source,
                        EventPhase phase,
                        EventParameters* params);
  virtual uint32 NextID();
  virtual LogLevel GetLogLevel() const;

  void AddObserver(ThreadSafeObserver* observer);
  void RemoveObserver(ThreadSafeObserver* observer);

  // Adds |observer| and writes all passively captured events to
  // |passive_entries|. Guarantees that no events in |passive_entries| will be
  // sent to |observer| and all future events that have yet been sent to the
  // PassiveLogCollector will be sent to |observer|.
  void AddObserverAndGetAllPassivelyCapturedEvents(ThreadSafeObserver* observer,
                                                   EntryList* passive_entries);

  void GetAllPassivelyCapturedEvents(EntryList* passive_entries);

  void ClearAllPassivelyCapturedEvents();

  LoadTimingObserver* load_timing_observer() {
    return load_timing_observer_.get();
  }

 private:
  void AddObserverWhileLockHeld(ThreadSafeObserver* observer);

  // Called whenever an observer is added or removed, or changes its log level.
  // Must have acquired |lock_| prior to calling.
  void UpdateLogLevel_();

  // |lock_| protects access to |observers_| and, indirectly, to
  // |passive_collector_|.  Should not be acquired by observers.
  base::Lock lock_;

  // Last assigned source ID.  Incremented to get the next one.
  base::subtle::Atomic32 last_id_;

  base::subtle::Atomic32 log_level_;

  // Not thread safe.  Must only be used when |lock_| is acquired.
  scoped_ptr<PassiveLogCollector> passive_collector_;

  scoped_ptr<LoadTimingObserver> load_timing_observer_;
  scoped_ptr<NetLogLogger> net_log_logger_;

  // |lock_| must be acquired whenever reading or writing to this.
  ObserverList<ThreadSafeObserver, true> observers_;

  DISALLOW_COPY_AND_ASSIGN(ChromeNetLog);
};

#endif  // CHROME_BROWSER_NET_CHROME_NET_LOG_H_