+typedef std::map<std::string, CatalogRef> CatalogDict;
+typedef std::vector<Delegate*> DelegateVec;
+typedef std::map<std::string, std::string> MemThumbnailCache;
+typedef std::deque<std::string> StringDeque;
+
+class Root::ThumbnailDownloader : public HTTP::Request
+{
+public:
+ ThumbnailDownloader(Root::RootPrivate* aOwner, const std::string& aUrl) :
+ HTTP::Request(aUrl),
+ m_owner(aOwner)
+ {
+ }
+
+protected:
+ virtual void gotBodyData(const char* s, int n)
+ {
+ m_buffer += std::string(s, n);
+ }
+
+ virtual void onDone();
+
+private:
+ Root::RootPrivate* m_owner;
+ std::string m_buffer;
+};
+
+class Root::RootPrivate
+{
+public:
+ RootPrivate() :
+ http(NULL),
+ maxAgeSeconds(60 * 60 * 24)
+ {
+ }
+
+ void fireStartInstall(InstallRef install)
+ {
+ DelegateVec::const_iterator it;
+ for (it = delegates.begin(); it != delegates.end(); ++it) {
+ (*it)->startInstall(install);
+ }
+ }
+
+ void fireInstallProgress(InstallRef install,
+ unsigned int aBytes, unsigned int aTotal)
+ {
+ DelegateVec::const_iterator it;
+ for (it = delegates.begin(); it != delegates.end(); ++it) {
+ (*it)->installProgress(install, aBytes, aTotal);
+ }
+ }
+
+ void fireFinishInstall(InstallRef install, Delegate::StatusCode status)
+ {
+ DelegateVec::const_iterator it;
+ for (it = delegates.begin(); it != delegates.end(); ++it) {
+ (*it)->finishInstall(install, status);
+ }
+ }
+
+ void fireRefreshStatus(CatalogRef catalog, Delegate::StatusCode status)
+ {
+ DelegateVec::const_iterator it;
+ for (it = delegates.begin(); it != delegates.end(); ++it) {
+ (*it)->catalogRefreshed(catalog, status);
+ }
+ }
+
+ void firePackagesChanged()
+ {
+ DelegateVec::const_iterator it;
+ for (it = delegates.begin(); it != delegates.end(); ++it) {
+ (*it)->availablePackagesChanged();
+ }
+ }
+
+ void thumbnailDownloadComplete(HTTP::Request_ptr request,
+ Delegate::StatusCode status, const std::string& bytes)
+ {
+ std::string u(request->url());
+ if (status == Delegate::STATUS_SUCCESS) {
+ thumbnailCache[u] = bytes;
+ fireDataForThumbnail(u, bytes);
+ }
+
+ downloadNextPendingThumbnail();
+ }
+
+ void fireDataForThumbnail(const std::string& aUrl, const std::string& bytes)
+ {
+ DelegateVec::const_iterator it;
+ const uint8_t* data = reinterpret_cast<const uint8_t*>(bytes.data());
+ for (it = delegates.begin(); it != delegates.end(); ++it) {
+ (*it)->dataForThumbnail(aUrl, bytes.size(), data);
+ }
+ }
+
+ void downloadNextPendingThumbnail()
+ {
+ thumbnailDownloadRequest.clear();
+ if (pendingThumbnails.empty()) {
+ return;
+ }
+
+ std::string u = pendingThumbnails.front();
+ pendingThumbnails.pop_front();
+ thumbnailDownloadRequest = new Root::ThumbnailDownloader(this, u);
+
+ if (http) {
+ http->makeRequest(thumbnailDownloadRequest);
+ } else {
+ httpPendingRequests.push_back(thumbnailDownloadRequest);
+ }
+ }
+
+ DelegateVec delegates;
+
+ SGPath path;
+ std::string locale;
+ HTTP::Client* http;
+ CatalogDict catalogs;
+ CatalogList disabledCatalogs;
+ unsigned int maxAgeSeconds;
+ std::string version;
+
+ std::set<CatalogRef> refreshing;
+ typedef std::deque<InstallRef> UpdateDeque;
+ UpdateDeque updateDeque;
+ std::deque<HTTP::Request_ptr> httpPendingRequests;
+
+ HTTP::Request_ptr thumbnailDownloadRequest;
+ StringDeque pendingThumbnails;
+ MemThumbnailCache thumbnailCache;
+
+ typedef std::map<PackageRef, InstallRef> InstallCache;
+ InstallCache m_installs;
+};
+
+
+void Root::ThumbnailDownloader::onDone()
+{
+ if (responseCode() != 200) {
+ SG_LOG(SG_GENERAL, SG_ALERT, "thumbnail download failure:" << url());
+ m_owner->thumbnailDownloadComplete(this, Delegate::FAIL_DOWNLOAD, std::string());
+ return;
+ }
+
+ m_owner->thumbnailDownloadComplete(this, Delegate::STATUS_SUCCESS, m_buffer);
+ //time(&m_owner->m_retrievedTime);
+ //m_owner->writeTimestamp();
+ //m_owner->refreshComplete(Delegate::STATUS_REFRESHED);
+}
+
+SGPath Root::path() const
+{
+ return d->path;
+}
+
+void Root::setMaxAgeSeconds(unsigned int seconds)