Click here to Skip to main content
15,860,861 members
Articles / Desktop Programming / WPF

GoalBook - A Hybrid Smart Client

Rate me:
Please Sign up or sign in to vote.
4.86/5 (24 votes)
25 Sep 2009CPOL10 min read 78.6K   834   69  
A WPF hybrid smart client that synchronises your goals with the Toodledo online To-do service.
//===============================================================================
// Goal Book.
// Copyright © 2009 Mark Brownsword. 
//===============================================================================

#region Using Statements
using System;
using System.Linq;
using System.Xml.Linq;
using GoalBook.Infrastructure.ObjectModel;
#endregion

namespace GoalBook.Synchronisation.ToodleDo
{
    internal class FolderSynchronisor : Synchronisor<FolderList>
    {
        #region Constants and Enums

        //Note constants
        private const string FOLDER = "folder";
        private const string FOLDER_ID = "id";
        private const string FOLDER_PRIVATE = "private";
        private const string FOLDER_ARCHIVED = "archived";
        private const string FOLDER_ORDER = "order";
             
        
        //URL constants
        private const string GET_FOLDERS_URL = @"http://api.toodledo.com/api.php?method=getFolders;key={0}";

        /*
        http://api.toodledo.com/api.php?method=addFolder;key=YourKey;title=MyFold;private=1
        http://api.toodledo.com/api.php?method=editFolder;key=YourKey;id=12345;title=MyFolder
        http://api.toodledo.com/api.php?method=deleteFolder;key=YourKey;id=12345;
         */

        #endregion

        #region Inner Classes and Structures
        #endregion

        #region Delegates and Events
        #endregion

        #region Instance and Shared Fields
        #endregion

        #region Constructors
        /// <summary>
        /// Constructor.
        /// </summary>        
        internal FolderSynchronisor(ToodledoConnector connector)
            : base(connector)
        {
        }
        #endregion

        #region Properties
        #endregion

        #region Private and Protected Methods

        /// <summary>
        /// Get Folder from list.
        /// </summary>
        /// <param name="noteList">FolderList</param>
        /// <param name="id">Identifier for the folder</param>
        /// <returns>Folder</returns>
        private Folder GetFolder(FolderList folderList, int id)
        {
            var targetList = from g in folderList where g.ExternalIdentifier == id select g;
            foreach (Folder folder in targetList)
            {
                return folder; //One only can exist.
            }
            return null;
        }

        /// <summary>
        /// Sync Folders Client. Upload local changes to Toodledo.
        /// </summary>
        /// <param name="noteList"></param>
        private void SyncFoldersClient(FolderList noteList)
        {            
            throw new NotImplementedException();
        }

        /// <summary>
        /// Sync Folders Server. Retrieves the folders from Toodledo.
        /// </summary>
        /// <param name="noteList">NoteList</param>        
        private void SyncFoldersServer(FolderList folderList)
        {
            //Get ToodleDo notes.
            string folderURL = string.Format(GET_FOLDERS_URL, Connector.GetSessionKey());
            XDocument serverList = Connector.MakeServerCall(folderURL);

            //Delete.
            var clientList = from g in folderList where g.ExternalIdentifier > 0 orderby g.Order select g;
            foreach (Folder folder in clientList.ToArray())
            {
                bool found = false;
                var targetList = from s in serverList.Descendants(FOLDER)
                                 where int.Parse(s.Attribute(FOLDER_ID).Value) == folder.ExternalIdentifier
                                 select s;
                foreach (XElement element in targetList)
                {
                    //Only one goal can exist with the specified id, so move on.
                    found = true; break;
                }

                //If not found then it has been deleted on the server. Remove the goal.
                //NOTE: Goal is moved to the Deleted list.
                if (!found) { folderList.Remove(folder); }
            }

            //Add, Edit.
            var orderedServerList = from s in serverList.Descendants(FOLDER)
                                    orderby s.Attribute(FOLDER_ORDER).Value
                                    select s;
            foreach (XElement element in orderedServerList)
            {
                Folder target = GetFolder(folderList, int.Parse(element.Attribute(FOLDER_ID).Value));
                if (target == null)
                {
                    //Add
                    bool isPrivate = element.Attribute(FOLDER_PRIVATE).Value == NUMERIC_TRUE;
                    bool archived = element.Attribute(FOLDER_PRIVATE).Value == NUMERIC_TRUE;
                    int order = int.Parse(element.Attribute(FOLDER_ORDER).Value);
                    string title = element.Value;

                    Folder addFolder = new Folder(Guid.NewGuid(), isPrivate, archived, order, title);
                    addFolder.ExternalIdentifier = int.Parse(element.Attribute(FOLDER_ID).Value);
                    addFolder.SyncRequired = false;

                    folderList.Add(addFolder);
                    folderList.EndNew(folderList.IndexOf(addFolder));
                }
                else
                {
                    //Edit
                    Folder editFolder = target.Clone();

                    editFolder.IsPrivate = element.Attribute(FOLDER_PRIVATE).Value == NUMERIC_TRUE;
                    editFolder.Archived = element.Attribute(FOLDER_PRIVATE).Value == NUMERIC_TRUE;
                    editFolder.Order = int.Parse(element.Attribute(FOLDER_ORDER).Value);                    
                    editFolder.Title = element.Value;                                       

                    folderList[folderList.IndexOf(target)].MapFields(editFolder);
                    folderList[folderList.IndexOf(target)].SyncRequired = false;
                }
            }
        }        
        #endregion

        #region Public and internal Methods
        #endregion

        #region Event Handlers
        #endregion

        #region Base Class Overrides

        /// <summary>
        /// Sync the FolderList.
        /// </summary>
        /// <param name="list">NoteList</param>
        /// <returns>SyncTokenInfo</returns>
        internal override void Sync(FolderList folderList)
        {            
            DateTime savedLastServerFolderEdit = folderList.LastServerFolderEdit;

            if (folderList.SyncRequired)
            {                     
                //SyncFoldersClient(folderList);
            }    

            if (Connector.LastFolderEdit > savedLastServerFolderEdit)
            {                
                SyncFoldersServer(folderList);
            }                                
        }
               
        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Australia Australia
I've been working as a software developer since 2000 and hold a Bachelor of Business degree from The Open Polytechnic of New Zealand. Computers are for people and I aim to build applications for people that they would want to use.

Comments and Discussions