/// <summary>
    /// Reads persited mru id's from isolated storage.
    /// </summary>
    static void Initialize()
    {
      if (_initialized)
        return;

      _initialized = true;

      if (!IsolatedStorageFile.IsEnabled)
        return;

      ArcGISOnlineEnvironment.ArcGISOnline.Content.ItemDeleted += new EventHandler<ContentItemEventArgs>(ArcGISOnline_ItemDeleted);

      //read mru map id's from isolated storage settings
      IsolatedStorageSettings settings = IsolatedStorageSettings.ApplicationSettings;
      for (int i = 0; i < _maxAmount; ++i)
      {
        if (settings.Contains(_mru + i))
        {
          //create a empty ContentItem and initialize with id only
          //once the ContentItems are requested from a client we download them based on the id
          ContentItem item = new ContentItem();
          item.Id = (string)settings[_mru + i];
          _contentItems.Add(item);
        }
        else
          break;
      }
    }
    /// <summary>
    /// Adds a map to the list of mru maps.
    /// </summary>
    public static void Add(ContentItem item)
    {
      Initialize();

      ContentItem existingItem = Find(item.Id);
      if (existingItem != null)
      {
        //move item to top
        _contentItems.Remove(existingItem);
      }

      if (_contentItems.Count == _maxAmount) //don't list more than a certain amount of maps
        _contentItems.RemoveAt(_maxAmount - 1); //remove oldest

      _contentItems.Insert(0, item);

      Save();
    }
    /// <summary>
    /// Gets the folder of a content item if the item is in a folder.
    /// </summary>
    void GetFolder(ContentItem item, EventHandler<RequestEventArgs> callback)
    {
      if (_agol.User.Current == null)
      {
        if (callback != null)
			callback(null, new RequestEventArgs() { Error = new Exception(ESRI.ArcGIS.Mapping.Controls.ArcGISOnline.Resources.Strings.ExceptionGetFolderFailedUserSignedIn) });
        return;
      }

      //if the folder has already been determined call back immediately
      //
      if (item.Folder != null)
      {
        callback(null, new RequestEventArgs());
        return;
      }

      //get the user's content and find the item
      //
      GetUserContent(null, (object sender, UserContentEventArgs e) =>
        {
          if (e.Error != null)
          {
            callback(null, new RequestEventArgs() { Error = e.Error });
            return;
          }

          UserContent userContent = e.Content;
          if (userContent == null)
          {
            callback(null, new RequestEventArgs() { Error = new Exception(string.Format(ESRI.ArcGIS.Mapping.Controls.ArcGISOnline.Resources.Strings.ItemNotFound, item.Id)) });
            return;
          }

          //first check if the item is in the content root level
          //
          if (userContent.ContentItems != null)
          {
            foreach (ContentItem contentItem in userContent.ContentItems)
              if (contentItem.Id == item.Id)
              {
                //create a folder that represents the root folder by assigning an empty id
                item.Folder = new ContentFolder() { Id = "" };

                callback(null, new RequestEventArgs());
                return;
              }
          }

          //search folders for the content item
          if (userContent.Folders == null || userContent.Folders.Length == 0)
            callback(null, new RequestEventArgs() { Error = new Exception(string.Format(ESRI.ArcGIS.Mapping.Controls.ArcGISOnline.Resources.Strings.ItemNotFound, item.Id)) });
          else
          {
            bool folderFound = false;
            int foldersToSearch = 0;
            int foldersSearched = 0;
            foreach (ContentFolder folder in userContent.Folders)
            {
              foldersToSearch++;
              ContentFolder folderToSearch = folder; //cache for reference in lambda expression
              GetUserContent(folderToSearch.Id, (object sender2, UserContentEventArgs e2) =>
                {
                  foldersSearched++;

                  if (e2.Content != null && e2.Content.ContentItems != null)
                    foreach (ContentItem contentItem in e2.Content.ContentItems)
                      if (contentItem.Id == item.Id)
                      {
                        folderFound = true; //make sure callback is not invoked on subsequent responses

                        item.Folder = folderToSearch;

                        callback(null, new RequestEventArgs());
                        return;
                      }

                  if (foldersSearched == foldersToSearch && !folderFound)
                  {
                    callback(null, new RequestEventArgs() { Error = new Exception(string.Format(ESRI.ArcGIS.Mapping.Controls.ArcGISOnline.Resources.Strings.ItemNotFound,  item.Id)) });
                    return;
                  }
                });
            }
          }
        });
    }
    /// <summary>
    /// Deletes the content item specified by its Id.
    /// </summary>
    public void Delete(ContentItem item, EventHandler<ContentItemEventArgs> callback)
    {
      if (_agol.User.Current == null)
      {
        if (callback != null)
			callback(null, new ContentItemEventArgs() { Error = new Exception(ESRI.ArcGIS.Mapping.Controls.ArcGISOnline.Resources.Strings.ExceptionDeleteFailedUserSignIn), Id = item.Id });
        return;
      }

      //find out if the item is located in a folder
      //
      GetFolder(item, (object sender, RequestEventArgs e) =>
        {
          if (e.Error != null)
          {
            if (callback != null)
              callback(null, new ContentItemEventArgs() { Error = e.Error });
            return;
          }

          string folderUrl = ContentFolder.IsSubfolder(item.Folder) ? "/" + item.Folder.Id : "";
          string url = _agol.Url + "/content/users/" + _agol.User.Current.Username + folderUrl + "/items/" + item.Id + "/delete?f=json&token=" + _agol.User.Token;

          WebUtil.UploadStringAsync(url, null, "", (object sender2, UploadStringCompletedEventArgs e2) =>
            {
              if (e2.Error != null)
              {
                if (callback != null)
                  callback(null, new ContentItemEventArgs() { Error = e2.Error, Id = item.Id });
                return;
              }

              Success result = WebUtil.ReadObject<Success>(new MemoryStream(Encoding.UTF8.GetBytes(e2.Result)));

			  ContentItemEventArgs eventArgs = new ContentItemEventArgs() { Error = (result == null || !result.Succeeded) ? new Exception(ESRI.ArcGIS.Mapping.Controls.ArcGISOnline.Resources.Strings.ExceptionDeleteFailed) : null, Id = item.Id };
              if (callback != null)
                callback(null, eventArgs);

              //raise event
              if (ItemDeleted != null)
                ItemDeleted(null, eventArgs);
            });
        });
    }
    /// <summary>
    /// Gets the sharing information for the specified ContentItem which includes the groups 
    /// the item is shared with and overall access permission (public/non public). 
    /// </summary>
    public void GetSharingInfo(ContentItem item, EventHandler<SharingInfoEventArgs> callback)
    {
      if (_agol.User.Current == null)
      {
        if (callback != null)
          callback(null, new SharingInfoEventArgs());
        return;
      }

      //find out if the item is located in a folder
      //
      GetFolder(item, (object sender, RequestEventArgs e) =>
        {
          if (e.Error != null)
          {
            if (callback != null)
              callback(null, new SharingInfoEventArgs() { Error = e.Error });
            return;
          }

          string folderUrl = ContentFolder.IsSubfolder(item.Folder) ? "/" + item.Folder.Id : "";
          string url = _agol.Url + "content/users/" + _agol.User.Current.Username + folderUrl + "/items/" + item.Id + "?f=json&token=" + _agol.User.Token;

          // add a bogus parameter to avoid the caching that happens with the WebClient
          //
          url += "&tickCount=" + Environment.TickCount.ToString();

          WebUtil.OpenReadAsync(url, null, (sender2, e2) =>
            {
              if (e2.Error != null)
              {
                if (callback != null)
                  callback(null, new SharingInfoEventArgs() { Error = e2.Error });
                return;
              }

              UserItem userItem = WebUtil.ReadObject<UserItem>(e2.Result);

              if (callback != null)
                callback(null, new SharingInfoEventArgs() { SharingInfo = (item == null) ? null : userItem.Sharing, Item = (item == null) ? null : userItem.ContentItem });
            });
        });
    }
    /// <summary>
    /// Unshares the specified item from the specified groups. 
    /// </summary>
    /// <param name="item"></param>
    /// <param name="groupIds">A collection of group Ids which the specified item is unshared from.</param>
    /// <param name="callback"></param>
    public void UnshareItem(ContentItem item, string[] groupIds, EventHandler<RequestEventArgs> callback)
    {
      //find out if the item is located in a folder
      //
      GetFolder(item, (object sender, RequestEventArgs e) =>
        {
          if (e.Error != null)
          {
            if (callback != null)
              callback(null, e);
            return;
          }

          List<HttpContentItem> items = new List<HttpContentItem>();
          items.Add(new HttpContentItem() { Name = "f", Value = "json" });

          string groups = "";
          if (groupIds != null)
            foreach (string groupId in groupIds)
              groups += groupId + ", ";
          items.Add(new HttpContentItem() { Name = "groups", Value = groups });

          string folderUrl = ContentFolder.IsSubfolder(item.Folder) ? "/" + item.Folder.Id : "";
          string url = _agol.Url + "content/users/" + _agol.User.Current.Username + folderUrl + "/items/" + item.Id + "/unshare?token=" + _agol.User.Token;
          WebUtil.MultiPartPostAsync(url, items, ApplicationUtility.Dispatcher, (sender2, e2) =>
            {
              UnshareItemResult result = WebUtil.ReadObject<UnshareItemResult>(e2.Result);

              if (callback != null)
              {
                if (result != null)
                  callback(null, new RequestEventArgs());
                else
                  callback(null, new RequestEventArgs() { Error = new Exception(string.Format(ESRI.ArcGIS.Mapping.Controls.ArcGISOnline.Resources.Strings.ExceptionFailedToShareItem, item.Id)) });
              }
            });
        });
    }