/* vim: ts=2 sw=2 expandtab
 * BEGIN FLOCK GPL
 *
 * Copyright Flock Inc. 2005-2009
 * http://flock.com
 *
 * This file may be used under the terms of the
 * GNU General Public License Version 2 or later (the "GPL"),
 * http://www.gnu.org/licenses/gpl.html
 *
 * 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.
 *
 * END FLOCK GPL
 */
 
#ifndef flockStreamUtils___h___
#define flockStreamUtils___h___

#include "nsIRDFService.h"
#include "nsIRDFContainerUtils.h"
#include "nsIObserverService.h"
#include "nsIObserver.h"
#include "nsITimer.h"

#include "flockIStreamUtils.h"
#include "flockIRDFSourceUtils.h"
#include "flockIRDFObserver.h"

#include "nsCOMPtr.h"
#include "nsCOMArray.h"

#include "nsClassHashtable.h"

class flockStreamCountsPropagator : public flockIStreamCountsPropagator,
                                    public flockIRDFObserver,
                                    public nsIObserver,
                                    public nsITimerCallback
{
public:
  NS_DECL_ISUPPORTS
  NS_DECL_FLOCKISTREAMCOUNTSPROPAGATOR
  NS_DECL_FLOCKIRDFOBSERVER
  NS_DECL_NSIOBSERVER
  NS_DECL_NSITIMERCALLBACK

  flockStreamCountsPropagator();

  static flockStreamCountsPropagator *GetSingleton();

private:
  ~flockStreamCountsPropagator();

  NS_IMETHOD Initialize();

  nsresult GetIntFromLiteral(nsIRDFNode *aNode, PRInt32 *retval);
  nsresult GetBooleanFromLiteral(nsIRDFNode *aNode, PRBool *retval);

  nsresult GetCountValue(nsIRDFDataSource *aDataSource,
                         nsIRDFResource *aResource,
                         int aPropIndex, PRInt32 *retval);
  nsresult GetBooleanValue(nsIRDFDataSource *aDataSource,
                           nsIRDFResource *aResource,
                           int aPropIndex, PRBool *retval);

  nsresult SetCountValue(nsIRDFDataSource *aDataSource,
                         nsIRDFResource *aResource,
                        int aPropIndex, PRInt32 count);
  nsresult SetBooleanValue(nsIRDFDataSource *aDataSource,
                           nsIRDFResource *aResource,
                           int aPropIndex, PRBool value);

  nsresult SetHasUnseenItems(nsIRDFDataSource *aDataSource,
                             nsIRDFResource *aSource,
                             PRInt32 unseenCount);

  nsresult ProcessAssertParent(nsIRDFDataSource *aDataSource,
                               nsIRDFResource *aSource,
                               nsIRDFNode *aTarget, PRBool aTruthValue);

  nsresult GetParents(nsIRDFDataSource *aDataSource,
                      nsIRDFResource *aSource,
                      nsCOMArray<nsIRDFResource> &aArray);

  nsresult ProcessUnseen(nsIRDFDataSource *aDataSource, PRUint16 aType,
                         nsIRDFResource *aSource,
                         nsIRDFNode *aTarget, nsIRDFNode *aOldTarget);
  nsresult ProcessUnseenItems(nsIRDFDataSource *aDataSource, PRUint16 aType,
                              nsIRDFResource *aSource,
                              nsIRDFNode *aTarget, nsIRDFNode *aOldTarget);
  nsresult ProcessCount(nsIRDFDataSource *aDataSource, PRUint16 aType,
                        nsIRDFResource *aSource,
                        nsIRDFNode *aTarget, nsIRDFNode *aOldTarget);

  nsCOMPtr<nsIRDFService> mRDFService;
  nsCOMPtr<flockIRDFSourceUtils> mFLS;
  nsCOMPtr<nsIRDFContainerUtils> mRDFCU;

  nsCOMPtr<nsIRDFDataSource> mFavesDS;

  nsCOMPtr<nsIObserverService> mObserverService;

  nsCOMPtr<nsITimer> mUpdateTimer;

  nsCOMArray<nsIRDFResource> mProperties;

private:
  struct StreamCounts {
    StreamCounts() : unseen(0), total(0) { };

    PRInt32 unseen;
    PRInt32 total;
  };

  nsClassHashtable<nsISupportsHashKey, StreamCounts> mStreamCounts;

  StreamCounts *GetStreamCounts(nsIRDFResource *aResource);
 
  struct CountDelta {
    nsCOMPtr<nsIRDFResource> resource;
    StreamCounts counts;
  };

  void UpdateCounts(CountDelta *delta);

  static PLDHashOperator PR_CALLBACK CollectCounts(nsISupports *aKey,
                                                   StreamCounts *aCounts,
                                                   void *aUserData);
};

class flockStreamUtils : public flockIStreamUtils
{
public:
  NS_DECL_ISUPPORTS
  NS_DECL_FLOCKISTREAMUTILS

  flockStreamUtils();

private:
  ~flockStreamUtils();
};

#endif // flockStreamUtils___h___
