Click here to Skip to main content
15,897,518 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 79.5K   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.Collections.Generic;
using System.IO;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Security.Permissions;
using System.Xml.Linq;
using GoalBook.Infrastructure.Interfaces;
using GoalBook.Infrastructure.ObjectModel;
using GoalBook.Shell.Properties;
using GoalBook.Infrastructure;
#endregion

namespace GoalBook.Shell.Services
{
    /// <summary>
    /// Isolated Storage Service.
    /// </summary>
    [IsolatedStorageFilePermission(SecurityAction.Demand)]
    public sealed class IsolatedStorageService : IPersistenceService
    {                
        #region Constants and Enums
        #endregion

        #region Inner Classes and Structures
        #endregion

        #region Delegates and Events

        /// <summary>
        /// SaveOccured event.
        /// </summary>
        public event EventHandler SaveOccured;
        private void OnSaveOccured()
        {
            EventHandler saveOccured = SaveOccured;
            if (saveOccured != null)
            {
                EventArgs args = new EventArgs();
                saveOccured(this, args);
            }
        }  
     
        #endregion

        #region Instance and Shared Fields

        private static GoalList _goalList;
        private static NoteList _noteList;
        private static TaskList _taskList;
        private static FolderList _folderList;        
        private static string _goalFile;
        private static string _noteFile;
        private static string _taskFile;
        private static string _folderFile;        
        private Dictionary<int, string> _levelList;
        private Dictionary<Guid, string> _contributesList;
        private Dictionary<Guid, string> _filteredContributesList;
        private Dictionary<Guid, string> _folderReferenceList;        
        #endregion

        #region Constructors 

        /// <summary>
        /// Constructor.
        /// </summary>
        public IsolatedStorageService()
        {
            _goalFile = "Goals.xml";
            _noteFile = "Notes.xml";
            _taskFile = "Tasks.xml";
            _folderFile = "Folders.xml";
        }

        #endregion

        #region Properties

        /// <summary>
        /// Reference to Goals.
        /// </summary>
        public GoalList Goals 
        {
            get 
            {
                if (_goalList == null) InitialiseGoalList();
                return _goalList;
            }            
        }

        /// <summary>
        /// Reference to Notes.
        /// </summary>
        public NoteList Notes
        {
            get
            {
                if (_noteList == null) InitialiseNoteList();
                return _noteList;
            }            
        }

        /// <summary>
        /// Reference to Tasks.
        /// </summary>
        public TaskList Tasks
        {
            get
            {
                if (_taskList == null) InitialiseTaskList();
                return _taskList;
            }
        }

        /// <summary>
        /// Reference to Folders.
        /// </summary>
        public FolderList Folders
        {
            get
            {
                if (_folderList == null) InitialiseFolderList();
                return _folderList;
            }
        }                
        #endregion

        #region Private and Protected Methods

        /// <summary>
        /// Initialise GoalList.
        /// </summary>        
        private void InitialiseGoalList()
        {
            _goalList = new GoalList();
            _goalList.CreateFromXDocument(RetrieveFromIsolatedStorage(_goalFile));                                    
        }

        /// <summary>
        /// Initialise NoteList.
        /// </summary>        
        private void InitialiseNoteList()
        {
            _noteList = new NoteList();
            _noteList.CreateFromXDocument(RetrieveFromIsolatedStorage(_noteFile));                    
        }

        /// <summary>
        /// Initialise TaskList.
        /// </summary>
        private void InitialiseTaskList()
        {
            _taskList = new TaskList();
            _taskList.CreateFromXDocument(RetrieveFromIsolatedStorage(_taskFile));
        }

        /// <summary>
        /// Initialise FolderList.
        /// </summary>
        private void InitialiseFolderList()
        {
            _folderList = new FolderList();
            _folderList.CreateFromXDocument(RetrieveFromIsolatedStorage(_folderFile));            
        }

        /// <summary>
        /// Retrieve specified file from IsolatedStorage.
        /// </summary>
        /// <returns>XDocument</returns>
        private XDocument RetrieveFromIsolatedStorage(string file)
        {
            IsolatedStorageFile store = GetUserStore();
            XDocument result = null;

            if (store.GetFileNames(file).Length > 0)
            {
                // Read the stream from Isolated Storage.
                using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(file, FileMode.Open, store))
                {
                    using (StreamReader reader = new StreamReader(stream))
                    {
                        result = XDocument.Load(reader);
                    }
                }
            }

            return result;
        }

        /// <summary>
        /// Get a reference to the users Isolated Store.
        /// Saved location is under C:\Users\Mark\AppData\Local\IsolatedStorage.
        /// </summary>
        /// <returns>IsolatedStorageFile</returns>
        private IsolatedStorageFile GetUserStore()
        {
            return IsolatedStorageFile.GetStore(IsolatedStorageScope.User | IsolatedStorageScope.Assembly, null, null);
        }

        /// <summary>
        /// Save To IsolatedStorage.
        /// (e.g. C:\Users\[UserName]\AppData\Local\IsolatedStorage).
        /// </summary>
        /// <param name="document">XDocument to save</param>
        /// <param name="file">Name of file</param>
        private void SaveToIsolatedStorage(XDocument document, string file)
        {
            // Open the stream from IsolatedStorage.
            IsolatedStorageFileStream stream = new IsolatedStorageFileStream(
                file, FileMode.Create, GetUserStore());
            using (stream)
            {
                using (StreamWriter writer = new StreamWriter(stream))
                {
                    document.Save(writer);
                }
            }
        }

        #endregion

        #region Public Methods
        /// <summary>
        /// Clear all data.
        /// </summary>
        public void Clear()
        {
            if (_goalList != null)
            {
                _goalList.Clear();
                _goalList.MarkListOld();
                _goalList.DeletedPendingSync.Clear();
                _goalList.LastServerGoalEdit = DateTime.MinValue;
            }

            if (_folderList != null)
            {
                _folderList.Clear();
                _folderList.MarkListOld();
                _folderList.DeletedPendingSync.Clear();
                _folderList.LastServerFolderEdit = DateTime.MinValue;
            }

            if (_noteList != null)
            {
                _noteList.Clear();
                _noteList.MarkListOld();
                _noteList.DeletedPendingSync.Clear();
                _noteList.LastServerNoteEdit = DateTime.MinValue;
            }

            if (_taskList != null)
            {
                _taskList.Clear();
                _taskList.MarkListOld();
                _taskList.DeletedPendingSync.Clear();
                _taskList.LastServerTaskEdit = DateTime.MinValue;
            }
        }

        /// <summary>
        /// Save Data to Isolated Storage (e.g. C:\Users\[UserName]\AppData\Local\IsolatedStorage).
        /// </summary>
        public void Save()
        {            
            if (_goalList.IsSavable)
            {
                //Save Goals in clean state.
                IXDocSerializable cloneList = _goalList.Clone();
                cloneList.MarkListOld();
                SaveToIsolatedStorage(cloneList.GetXDocument(), _goalFile);
                _goalList.MarkListOld();
            }

            if (_folderList.IsSavable)
            {
                //Save the Folders in clean state.
                IXDocSerializable cloneList = _folderList.Clone();
                cloneList.MarkListOld();
                SaveToIsolatedStorage(cloneList.GetXDocument(), _folderFile);
                _folderList.MarkListOld();
            }

            if (_noteList.IsSavable)
            {
                //Save Notes in clean state.
                IXDocSerializable cloneList = _noteList.Clone();
                cloneList.MarkListOld();
                SaveToIsolatedStorage(cloneList.GetXDocument(), _noteFile);
                _noteList.MarkListOld();
            }

            if (_taskList.IsSavable)
            {
                //Save Tasks in clean state.
                IXDocSerializable cloneList = _taskList.Clone();
                cloneList.MarkListOld();
                SaveToIsolatedStorage(cloneList.GetXDocument(), _taskFile);
                _taskList.MarkListOld();
            }

            OnSaveOccured();
        }
               
        /// <summary>
        /// Fetch LevelList.
        /// </summary>
        /// <returns>Dictionary of levels</returns>
        public Dictionary<int, string> FetchLevelList()
        {
            if (_levelList == null)
            {
                _levelList = new Dictionary<int, string>();
                _levelList.Add(0, Resources.LevelLifetimeText);
                _levelList.Add(1, Resources.LevelLongtermText);
                _levelList.Add(2, Resources.LevelShorttermText);                
            }

            return _levelList;
        }

        /// <summary>
        /// Fetch ContributesList. Get all goals with level lower that specified value.
        /// </summary> 
        /// <returns>Dictionary</returns>
        public Dictionary<Guid, string> FetchContributesList(Guid currentGoal, int level)
        {
            if (_filteredContributesList == null)
            {
                _filteredContributesList = new Dictionary<Guid, string>();
            }

            _filteredContributesList.Clear();            
            foreach (Goal goal in _goalList)
            {
                if (goal.LevelID < level && goal.GoalID != currentGoal)
                {
                    if (_filteredContributesList.Count == 0) { _filteredContributesList.Add(Guid.Empty, null); }
                    _filteredContributesList.Add(goal.GoalID, goal.Title);                    
                }
            }

            return _filteredContributesList;
        }

        /// <summary>
        /// Fetch Contributes List.
        /// </summary>
        /// <returns>Dictionary</returns>
        public Dictionary<Guid, string> FetchContributesList()
        {
            if (_contributesList == null)
            {
                _contributesList = new Dictionary<Guid, string>();
                
                foreach (Goal goal in _goalList)
                {
                    _contributesList.Add(goal.GoalID, goal.Title);
                }
            }
            
            return _contributesList;
        }

        /// <summary>
        /// Fetch FolderList.
        /// </summary>
        /// <returns>Dictionary of folders</returns>
        public Dictionary<Guid, string> FetchFolderList()
        {
            if (_folderReferenceList == null)
            {
                _folderReferenceList = new Dictionary<Guid, string>();                          
            }

            _folderReferenceList.Clear();
            _folderReferenceList.Add(Guid.Empty, Resources.DefaultFolder);

            foreach (Folder folder in _folderList)
            {
                _folderReferenceList.Add(folder.FolderID, folder.Title);
            }

            return _folderReferenceList;
        }

        /// <summary>
        /// Update ContributesList. Add/Remove items as required.
        /// </summary>        
        public void UpdateContributesList(Guid goalID)
        {
            if (_contributesList.ContainsKey(goalID))
            {
                //Remove from contributesList
                _contributesList.Remove(goalID);
            }
            else
            {          
                foreach (Goal goal in _goalList)
                {
                    if (goal.GoalID == goalID)
                    {
                        //Add to contributesList
                        _contributesList.Add(goal.GoalID, goal.Title); break;
                    }
                }                                
            }
        }

        /// <summary>
        /// Update Folder List. 
        /// </summary>
        public void UpdateFolderList()
        {
            if (_folderReferenceList == null)
            {
                return;
            }

            // Check for deleted folders
            bool foundFolder = false;
            var checkDeleteList = from g in _folderReferenceList select g;
            foreach (KeyValuePair<Guid, string> folderItem in checkDeleteList.ToArray())
            {
                if (folderItem.Key == Guid.Empty)
                {
                    continue;
                }

                foreach (Folder folder in _folderList)
                {
                    if (folder.FolderID == folderItem.Key)
                    {
                        foundFolder = true;
                        break;
                    }
                }

                if (foundFolder)
                {
                    foundFolder = false;
                    continue;
                }
                else
                {
                    _folderReferenceList.Remove(folderItem.Key);

                    // Replace Note folderid with No Folder (Guid.Empty).
                    foreach (Note note in _noteList)
                    {
                        if (note.FolderID == folderItem.Key)
                        {
                            note.FolderID = Guid.Empty;
                        }
                    }

                    // Replace Task folderid with No Folder (Guid.Empty). 
                    foreach (Task task in _taskList)
                    {
                        if (task.TaskID == folderItem.Key)
                        {
                            task.TaskID = Guid.Empty;
                        }
                    }
                }
            }
                       
            // Check for Added folders.
            foreach (Folder folder in _folderList)
            {
                if (_folderReferenceList.ContainsKey(folder.FolderID))
                {
                    // Item exists, so just update Title.
                    _folderReferenceList[folder.FolderID] = folder.Title;
                }
                else
                {
                    // Add new item.
                    _folderReferenceList.Add(folder.FolderID, folder.Title);
                }
            }
        }

        /// <summary>
        /// Reference to SyncRequired. A flag indicating if synchronisation is required.
        /// </summary>        
        public bool SyncRequired
        {
            get
            {
                return Goals.SyncRequired || Notes.SyncRequired || Tasks.SyncRequired || Folders.SyncRequired;
            }
        }

        /// <summary>
        /// Get SaveRequired.
        /// </summary>
        public bool SaveRequired
        {
            get
            {
                return Goals.IsSavable || Notes.IsSavable || Tasks.IsSavable || Folders.IsSavable;
            }
        }

        #endregion

        #region Event Handlers
        #endregion

        #region Base Class Overrides
        #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