/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 *
 * The contents of this file are subject to the Mozilla Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/MPL/
 * 
 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
 * 
 * The Original Code is the Mozilla browser.
 * 
 * The Initial Developer of the Original Code is Netscape
 * Communications, Inc.  Portions created by Netscape are
 * Copyright (C) 1999, Mozilla.  All Rights Reserved.
 * 
 * Original Author:
 *   Scott Collins <scc@mozilla.org>
 * 
 * Contributor(s):
 *   Pierre Phaneuf <pp@ludusdesign.com>
 */

#include "nsISupports.idl"


/**
 * An instance of |nsIWeakReference| is a proxy object that cooperates with
 * its referent to give clients a non-owning, non-dangling reference.  Clients
 * own the proxy, and should generally manage it with an |nsCOMPtr| (see the
 * type |nsWeakPtr| for a |typedef| name that stands out) as they would any
 * other XPCOM object.  The |QueryReferent| member function provides a
 * (hopefully short-lived) owning reference on demand, through which clients
 * can get useful access to the referent, while it still exists.
 *
 * @see nsISupportsWeakReference
 * @see nsWeakReference
 * @see nsWeakPtr
 */
[scriptable, uuid(9188bc85-f92e-11d2-81ef-0060083a0bcf)]
interface nsIWeakReference : nsISupports
  {
    /**
     * |QueryReferent| queries the referent, if it exists, and like |QueryInterface|, produces
     * an owning reference to the desired interface.  It is designed to look and act exactly
     * like (a proxied) |QueryInterface|.  Don't hold on to the produced interface permanently;
     * that would defeat the purpose of using a non-owning |nsIWeakReference| in the first place.
     */
    void QueryReferent( in nsIIDRef uuid, [iid_is(uuid), retval] out nsQIResult result );
  };


/**
 * |nsISupportsWeakReference| is a factory interface which produces appropriate
 * instances of |nsIWeakReference|.  Weak references in this scheme can only be
 * produced for objects that implement this interface.
 *
 * @see nsIWeakReference
 * @see nsSupportsWeakReference
 */
[scriptable, uuid(9188bc86-f92e-11d2-81ef-0060083a0bcf)]
interface nsISupportsWeakReference : nsISupports
  {
    /**
     * |GetWeakReference| produces an appropriate instance of |nsIWeakReference|.
     * As with all good XPCOM `getters', you own the resulting interface and should
     * manage it with an |nsCOMPtr|.
     *
     * @see nsIWeakReference
     * @see nsWeakPtr
     * @see nsCOMPtr
     */
    nsIWeakReference GetWeakReference();
  };


%{C++

#ifndef nsCOMPtr_h__
#include "nsCOMPtr.h"
#endif

typedef nsCOMPtr<nsIWeakReference> nsWeakPtr;


/**
 * |NS_GetWeakReference| is a convenience function that bundles up all the work needed
 * to get a weak reference to an arbitrary object, i.e., the |QueryInterface|, test, and
 * call through to |GetWeakReference|.  It produces an |nsIWeakReference*| as its
 * function result specifically to cooperate with |nsCOMPtr| (or |nsWeakPtr|) like so:
 * |nsWeakPtr myWeakPtr = getter_AddRefs( NS_GetWeakReference(aPtr) );|.
 */
extern NS_COM
nsIWeakReference*
NS_GetWeakReference( nsISupports* , nsresult* aResult=0 );


/**
 *
 */
template <class T>
inline
nsresult
CallQueryReferent( nsIWeakReference* aSource, T** aDestination )
  {
    NS_PRECONDITION(aSource, "null parameter");
    NS_PRECONDITION(aDestination, "null parameter");

    return aSource->QueryReferent(NS_GET_IID(T), (void**)aDestination);
  }


class NS_EXPORT nsQueryReferent : public nsCOMPtr_helper
  {
    public:
      nsQueryReferent( nsIWeakReference* aWeakPtr, nsresult* error )
          : mWeakPtr(aWeakPtr),
            mErrorPtr(error)
        {
          // nothing else to do here
        }

      virtual nsresult operator()( const nsIID& aIID, void** ) const;

    private:
      nsIWeakReference*  mWeakPtr;
      nsresult*          mErrorPtr;
  };

inline
const nsQueryReferent
do_QueryReferent( nsIWeakReference* aRawPtr, nsresult* error = 0 )
  {
    return nsQueryReferent(aRawPtr, error);
  }


%}
