Statistics
| Branch: | Revision:

root / trunk / Pithos.Client.WPF / Shell / ShellViewModel.cs @ b517d0d3

History | View | Annotate | Download (40.9 kB)

1 d7288179 pkanavos
#region
2 d7288179 pkanavos
/* -----------------------------------------------------------------------
3 d7288179 pkanavos
 * <copyright file="ShellViewModel.cs" company="GRNet">
4 d7288179 pkanavos
 * 
5 d7288179 pkanavos
 * Copyright 2011-2012 GRNET S.A. All rights reserved.
6 d7288179 pkanavos
 *
7 d7288179 pkanavos
 * Redistribution and use in source and binary forms, with or
8 d7288179 pkanavos
 * without modification, are permitted provided that the following
9 d7288179 pkanavos
 * conditions are met:
10 d7288179 pkanavos
 *
11 d7288179 pkanavos
 *   1. Redistributions of source code must retain the above
12 d7288179 pkanavos
 *      copyright notice, this list of conditions and the following
13 d7288179 pkanavos
 *      disclaimer.
14 d7288179 pkanavos
 *
15 d7288179 pkanavos
 *   2. Redistributions in binary form must reproduce the above
16 d7288179 pkanavos
 *      copyright notice, this list of conditions and the following
17 d7288179 pkanavos
 *      disclaimer in the documentation and/or other materials
18 d7288179 pkanavos
 *      provided with the distribution.
19 d7288179 pkanavos
 *
20 d7288179 pkanavos
 *
21 d7288179 pkanavos
 * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
22 d7288179 pkanavos
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 d7288179 pkanavos
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 d7288179 pkanavos
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
25 d7288179 pkanavos
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 d7288179 pkanavos
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 d7288179 pkanavos
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28 d7288179 pkanavos
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 d7288179 pkanavos
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 d7288179 pkanavos
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 d7288179 pkanavos
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 d7288179 pkanavos
 * POSSIBILITY OF SUCH DAMAGE.
33 d7288179 pkanavos
 *
34 d7288179 pkanavos
 * The views and conclusions contained in the software and
35 d7288179 pkanavos
 * documentation are those of the authors and should not be
36 d7288179 pkanavos
 * interpreted as representing official policies, either expressed
37 d7288179 pkanavos
 * or implied, of GRNET S.A.
38 d7288179 pkanavos
 * </copyright>
39 d7288179 pkanavos
 * -----------------------------------------------------------------------
40 d7288179 pkanavos
 */
41 d7288179 pkanavos
#endregion
42 d7288179 pkanavos
using System.Collections.Concurrent;
43 d7288179 pkanavos
using System.Diagnostics;
44 d7288179 pkanavos
using System.Diagnostics.Contracts;
45 d7288179 pkanavos
using System.IO;
46 d7288179 pkanavos
using System.Net;
47 dd5f5163 pkanavos
using System.Net.Http;
48 d7288179 pkanavos
using System.Reflection;
49 d7288179 pkanavos
using System.Runtime.InteropServices;
50 d7288179 pkanavos
using System.ServiceModel;
51 d7288179 pkanavos
using System.Threading;
52 d7288179 pkanavos
using System.Threading.Tasks;
53 d7288179 pkanavos
using System.Windows;
54 d7288179 pkanavos
using System.Windows.Controls.Primitives;
55 d7288179 pkanavos
using System.Windows.Input;
56 d7288179 pkanavos
using AppLimit.NetSparkle;
57 d7288179 pkanavos
using Caliburn.Micro;
58 d7288179 pkanavos
using Hardcodet.Wpf.TaskbarNotification;
59 d7288179 pkanavos
using Pithos.Client.WPF.Configuration;
60 d7288179 pkanavos
using Pithos.Client.WPF.FileProperties;
61 d7288179 pkanavos
using Pithos.Client.WPF.Preferences;
62 d7288179 pkanavos
using Pithos.Client.WPF.SelectiveSynch;
63 d7288179 pkanavos
using Pithos.Client.WPF.Services;
64 d7288179 pkanavos
using Pithos.Client.WPF.Shell;
65 d7288179 pkanavos
using Pithos.Core;
66 d7288179 pkanavos
using Pithos.Core.Agents;
67 d7288179 pkanavos
using Pithos.Interfaces;
68 d7288179 pkanavos
using System;
69 d7288179 pkanavos
using System.Collections.Generic;
70 d7288179 pkanavos
using System.Linq;
71 d7288179 pkanavos
using Pithos.Network;
72 6b816c1f pkanavos
using Pithos.OFM;
73 d7288179 pkanavos
using StatusService = Pithos.Client.WPF.Services.StatusService;
74 d7288179 pkanavos
75 302c5b7d George Pantazis
76 d7288179 pkanavos
namespace Pithos.Client.WPF {
77 d7288179 pkanavos
	using System.ComponentModel.Composition;
78 d7288179 pkanavos
79 d7288179 pkanavos
	public class ToggleStatusCommand:ICommand
80 d7288179 pkanavos
	{
81 d7288179 pkanavos
	    private readonly ShellViewModel _model;
82 d7288179 pkanavos
	    public ToggleStatusCommand(ShellViewModel model)
83 d7288179 pkanavos
	    {
84 d7288179 pkanavos
	        _model = model;
85 d7288179 pkanavos
	    }
86 d7288179 pkanavos
	    public void Execute(object parameter)
87 d7288179 pkanavos
	    {
88 d7288179 pkanavos
	        _model.CurrentSyncStatus();
89 d7288179 pkanavos
	    }
90 d7288179 pkanavos
91 d7288179 pkanavos
	    public bool CanExecute(object parameter)
92 d7288179 pkanavos
	    {
93 d7288179 pkanavos
	        return true;
94 d7288179 pkanavos
	    }
95 d7288179 pkanavos
96 d7288179 pkanavos
	    public event EventHandler CanExecuteChanged;
97 d7288179 pkanavos
	}
98 d7288179 pkanavos
99 d7288179 pkanavos
100 d7288179 pkanavos
	///<summary>
101 d7288179 pkanavos
	/// The "shell" of the Pithos application displays the taskbar  icon, menu and notifications.
102 d7288179 pkanavos
	/// The shell also hosts the status service called by shell extensions to retrieve file info
103 d7288179 pkanavos
	///</summary>
104 d7288179 pkanavos
	///<remarks>
105 d7288179 pkanavos
	/// It is a strange "shell" as its main visible element is an icon instead of a window
106 d7288179 pkanavos
	/// The shell subscribes to the following events:
107 d7288179 pkanavos
	/// * Notification:  Raised by components that want to notify the user. Usually displayed in a balloon
108 d7288179 pkanavos
	/// * SelectiveSynchChanges: Notifies that the user made changes to the selective synch folders for an account. Raised by the Selective Synch dialog. Located here because the monitors are here
109 d7288179 pkanavos
	/// * ShowFilePropertiesEvent: Raised when a shell command requests the display of the file/container properties dialog
110 d7288179 pkanavos
	///</remarks>		
111 d7288179 pkanavos
	//TODO: CODE SMELL Why does the shell handle the SelectiveSynchChanges?
112 d7288179 pkanavos
    [Export(typeof(IShell)), Export(typeof(ShellViewModel)),Export(typeof(IStatusNotification))]
113 d7288179 pkanavos
	public class ShellViewModel : Screen, IStatusNotification, IShell,
114 d7288179 pkanavos
		IHandle<Notification>, IHandle<SelectiveSynchChanges>, IHandle<ShowFilePropertiesEvent>
115 d7288179 pkanavos
	{
116 d7288179 pkanavos
		
117 d7288179 pkanavos
		private readonly IEventAggregator _events;
118 d7288179 pkanavos
119 dd5f5163 pkanavos
        
120 d7288179 pkanavos
		public PithosSettings Settings { get; private set; }
121 d7288179 pkanavos
122 d7288179 pkanavos
123 d7288179 pkanavos
		private readonly ConcurrentDictionary<Uri, PithosMonitor> _monitors = new ConcurrentDictionary<Uri, PithosMonitor>();
124 d7288179 pkanavos
		///<summary>
125 d7288179 pkanavos
		/// Dictionary of account monitors, keyed by account
126 d7288179 pkanavos
		///</summary>
127 d7288179 pkanavos
		///<remarks>
128 d7288179 pkanavos
		/// One monitor class is created for each account. The Shell needs access to the monitors to execute start/stop/pause commands,
129 d7288179 pkanavos
		/// retrieve account and boject info		
130 d7288179 pkanavos
		///</remarks>
131 d7288179 pkanavos
		// TODO: Does the Shell REALLY need access to the monitors? Could we achieve the same results with a better design?
132 d7288179 pkanavos
		// TODO: The monitors should be internal to Pithos.Core, even though exposing them makes coding of the Object and Container windows easier
133 d7288179 pkanavos
		public ConcurrentDictionary<Uri, PithosMonitor> Monitors
134 d7288179 pkanavos
		{
135 d7288179 pkanavos
			get { return _monitors; }
136 d7288179 pkanavos
		}
137 d7288179 pkanavos
138 d7288179 pkanavos
139 d7288179 pkanavos
		///<summary>
140 d7288179 pkanavos
		/// The status service is used by Shell extensions to retrieve file status information
141 d7288179 pkanavos
		///</summary>
142 d7288179 pkanavos
		//TODO: CODE SMELL! This is the shell! While hosting in the shell makes executing start/stop commands easier, it is still a smell
143 d7288179 pkanavos
		private ServiceHost _statusService;
144 d7288179 pkanavos
145 d7288179 pkanavos
		//Logging in the Pithos client is provided by log4net
146 d7288179 pkanavos
        private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
147 d7288179 pkanavos
148 96e5791c pkanavos
        #pragma warning disable 649
149 d7288179 pkanavos
        [Import]
150 d7288179 pkanavos
	    private PollAgent _pollAgent;
151 d7288179 pkanavos
152 d7288179 pkanavos
        [Import]
153 d7288179 pkanavos
	    private NetworkAgent _networkAgent;
154 d7288179 pkanavos
155 d7288179 pkanavos
	    [Import]
156 d7288179 pkanavos
	    public Selectives Selectives { get; set; }
157 d7288179 pkanavos
158 96e5791c pkanavos
        #pragma warning restore 649
159 d7288179 pkanavos
160 96e5791c pkanavos
        public ToggleStatusCommand ToggleMiniStatusCommand { get; set; }
161 d7288179 pkanavos
162 d7288179 pkanavos
	    private MiniStatusViewModel _miniStatus;
163 d7288179 pkanavos
164 d7288179 pkanavos
	    [Import]
165 d7288179 pkanavos
        public MiniStatusViewModel MiniStatus
166 d7288179 pkanavos
	    {
167 d7288179 pkanavos
	        get { return _miniStatus; }
168 d7288179 pkanavos
	        set
169 d7288179 pkanavos
	        {
170 d7288179 pkanavos
	            _miniStatus = value;
171 d7288179 pkanavos
	            _miniStatus.Shell = this;
172 d7288179 pkanavos
	            _miniStatus.Deactivated += (sender, arg) =>
173 d7288179 pkanavos
	                                           {
174 d7288179 pkanavos
	                                               _statusVisible = false;
175 d7288179 pkanavos
                                                   NotifyOfPropertyChange(()=>MiniStatusCaption);
176 d7288179 pkanavos
	                                           };
177 d7288179 pkanavos
	        }
178 d7288179 pkanavos
	    }
179 d7288179 pkanavos
180 d7288179 pkanavos
	    ///<summary>
181 d7288179 pkanavos
		/// The Shell depends on MEF to provide implementations for windowManager, events, the status checker service and the settings
182 d7288179 pkanavos
		///</summary>
183 d7288179 pkanavos
		///<remarks>
184 d7288179 pkanavos
		/// The PithosSettings class encapsulates the app's settings to abstract their storage mechanism (App settings, a database or registry)
185 d7288179 pkanavos
		///</remarks>
186 d7288179 pkanavos
		[ImportingConstructor]		
187 d7288179 pkanavos
		public ShellViewModel(IWindowManager windowManager, IEventAggregator events, PithosSettings settings/*,PollAgent pollAgent,NetworkAgent networkAgent*/)
188 d7288179 pkanavos
		{
189 d7288179 pkanavos
			try
190 d7288179 pkanavos
			{
191 d7288179 pkanavos
192 d7288179 pkanavos
				_windowManager = windowManager;
193 d7288179 pkanavos
				//CHECK: Caliburn doesn't need explicit command construction
194 d7288179 pkanavos
				//CurrentSyncStatusCommand = new PithosCommand(OpenPithosFolder);
195 d7288179 pkanavos
				//The event subst
196 d7288179 pkanavos
				_events = events;
197 d7288179 pkanavos
				_events.Subscribe(this);
198 d7288179 pkanavos
199 d7288179 pkanavos
/*
200 d7288179 pkanavos
			    _pollAgent = pollAgent;
201 d7288179 pkanavos
			    _networkAgent = networkAgent;
202 d7288179 pkanavos
*/
203 d7288179 pkanavos
				Settings = settings;
204 d7288179 pkanavos
205 d7288179 pkanavos
				Proxy.SetFromSettings(settings);
206 d7288179 pkanavos
207 d7288179 pkanavos
                StatusMessage = Settings.Accounts.Count==0 
208 d7288179 pkanavos
                    ? "No Accounts added\r\nPlease add an account" 
209 d7288179 pkanavos
                    : "Starting";
210 d7288179 pkanavos
211 d7288179 pkanavos
				_accounts.CollectionChanged += (sender, e) =>
212 d7288179 pkanavos
												   {
213 d7288179 pkanavos
													   NotifyOfPropertyChange(() => OpenFolderCaption);
214 d7288179 pkanavos
													   NotifyOfPropertyChange(() => HasAccounts);
215 d7288179 pkanavos
												   };
216 d7288179 pkanavos
217 d7288179 pkanavos
                SetVersionMessage();
218 d7288179 pkanavos
219 d7288179 pkanavos
                ToggleMiniStatusCommand=new ToggleStatusCommand(this);
220 d7288179 pkanavos
			}
221 d7288179 pkanavos
			catch (Exception exc)
222 d7288179 pkanavos
			{
223 d7288179 pkanavos
				Log.Error("Error while starting the ShellViewModel",exc);
224 d7288179 pkanavos
				throw;
225 d7288179 pkanavos
			}
226 d7288179 pkanavos
227 d7288179 pkanavos
		}
228 d7288179 pkanavos
229 d7288179 pkanavos
	    private void SetVersionMessage()
230 d7288179 pkanavos
	    {
231 d7288179 pkanavos
	        Assembly assembly = Assembly.GetExecutingAssembly();
232 d7288179 pkanavos
	        var fileVersion = FileVersionInfo.GetVersionInfo(assembly.Location);
233 d7288179 pkanavos
	        VersionMessage = String.Format("Pithos+ {0}", fileVersion.FileVersion);
234 d7288179 pkanavos
	    }
235 d7288179 pkanavos
236 6b816c1f pkanavos
237 302c5b7d George Pantazis
        public void openOFM()
238 302c5b7d George Pantazis
        {
239 6b816c1f pkanavos
            var fileManager = IoC.Get<FileManagerViewModel>();
240 df12ed4c pkanavos
            fileManager.Accounts = Settings.Accounts;
241 df12ed4c pkanavos
            fileManager.CurrentAccount = fileManager.Accounts.First();// Settings.Accounts.First();
242 6b816c1f pkanavos
            _windowManager.ShowWindow(fileManager);
243 6b816c1f pkanavos
            //var ofm = new OFM.GUI.OFM();
244 6b816c1f pkanavos
            //ofm.Show();
245 302c5b7d George Pantazis
        }
246 302c5b7d George Pantazis
247 d7288179 pkanavos
        public void CurrentSyncStatus()
248 d7288179 pkanavos
        {
249 d7288179 pkanavos
            if (Accounts.Count == 0)
250 d7288179 pkanavos
            {
251 d7288179 pkanavos
                ShowPreferences("AccountTab");
252 d7288179 pkanavos
            }
253 d7288179 pkanavos
            else
254 d7288179 pkanavos
            {
255 d7288179 pkanavos
                if (!_statusVisible)
256 d7288179 pkanavos
                {
257 d7288179 pkanavos
                    _windowManager.ShowWindow(MiniStatus);
258 d7288179 pkanavos
                    _statusVisible = true;
259 d7288179 pkanavos
                }
260 d7288179 pkanavos
                else
261 d7288179 pkanavos
                {
262 d7288179 pkanavos
                    if (MiniStatus.IsActive)
263 d7288179 pkanavos
                        MiniStatus.TryClose();
264 d7288179 pkanavos
                    _statusVisible = false;
265 d7288179 pkanavos
                }
266 d7288179 pkanavos
267 d7288179 pkanavos
                NotifyOfPropertyChange(() => MiniStatusCaption);
268 d7288179 pkanavos
            }
269 d7288179 pkanavos
        }
270 d7288179 pkanavos
271 d7288179 pkanavos
	    protected override void OnActivate()
272 d7288179 pkanavos
		{
273 d7288179 pkanavos
			base.OnActivate();
274 d7288179 pkanavos
275 d7288179 pkanavos
            InitializeSparkle();
276 d7288179 pkanavos
277 d7288179 pkanavos
	        //Must delay opening the upgrade window
278 d7288179 pkanavos
            //to avoid Windows Messages sent by the TaskbarIcon
279 d7288179 pkanavos
            TaskEx.Delay(5000).ContinueWith(_=>
280 d7288179 pkanavos
                Execute.OnUIThread(()=> _sparkle.StartLoop(true,Settings.UpdateForceCheck,Settings.UpdateCheckInterval)));
281 d7288179 pkanavos
282 d7288179 pkanavos
283 d7288179 pkanavos
			StartMonitoring();                    
284 d7288179 pkanavos
		}
285 d7288179 pkanavos
286 d7288179 pkanavos
287 d7288179 pkanavos
	    private void OnCheckFinished(object sender, bool updaterequired)
288 d7288179 pkanavos
	    {
289 d7288179 pkanavos
            
290 d7288179 pkanavos
            Log.InfoFormat("Upgrade check finished. Need Upgrade: {0}", updaterequired);
291 d7288179 pkanavos
            if (_manualUpgradeCheck)
292 d7288179 pkanavos
            {
293 d7288179 pkanavos
                _manualUpgradeCheck = false;
294 d7288179 pkanavos
                if (!updaterequired)
295 d7288179 pkanavos
                    //Sparkle raises events on a background thread
296 d7288179 pkanavos
                    Execute.OnUIThread(()=>
297 d7288179 pkanavos
                        ShowBalloonFor(new Notification{Title="Pithos+ is up to date",Message="You have the latest Pithos+ version. No update is required"}));
298 d7288179 pkanavos
            }
299 d7288179 pkanavos
	    }
300 d7288179 pkanavos
301 d7288179 pkanavos
	    private void OnUpgradeDetected(object sender, UpdateDetectedEventArgs e)
302 d7288179 pkanavos
	    {            
303 d7288179 pkanavos
	        Log.InfoFormat("Update detected {0}",e.LatestVersion);
304 d7288179 pkanavos
	    }
305 d7288179 pkanavos
306 d7288179 pkanavos
        public void CheckForUpgrade()
307 d7288179 pkanavos
        {
308 d7288179 pkanavos
            ShowBalloonFor(new Notification{Title="Checking for upgrades",Message="Contacting the server to retrieve the latest Pithos+ version."});
309 d7288179 pkanavos
            _sparkle.StopLoop();
310 d7288179 pkanavos
            _sparkle.updateDetected -= OnUpgradeDetected;
311 d7288179 pkanavos
            _sparkle.checkLoopFinished -= OnCheckFinished;
312 d7288179 pkanavos
            _sparkle.Dispose();
313 d7288179 pkanavos
314 d7288179 pkanavos
            _manualUpgradeCheck = true;
315 d7288179 pkanavos
            InitializeSparkle();
316 d7288179 pkanavos
            _sparkle.StartLoop(true,true,Settings.UpdateCheckInterval);
317 d7288179 pkanavos
        }
318 d7288179 pkanavos
319 d7288179 pkanavos
        private void InitializeSparkle()
320 d7288179 pkanavos
        {
321 b517d0d3 George Pantazis
            _sparkle = new Sparkle(Settings.UpdateUrl+"?Version="+Assembly.GetExecutingAssembly().GetName().Version);
322 d7288179 pkanavos
            _sparkle.updateDetected += OnUpgradeDetected;
323 d7288179 pkanavos
            _sparkle.checkLoopFinished += OnCheckFinished;
324 d7288179 pkanavos
            _sparkle.ShowDiagnosticWindow = Settings.UpdateDiagnostics;
325 d7288179 pkanavos
        }
326 d7288179 pkanavos
327 2115e2a5 pkanavos
	    private async Task StartMonitoring()
328 d7288179 pkanavos
		{
329 d7288179 pkanavos
			try
330 d7288179 pkanavos
			{
331 d7288179 pkanavos
                if (Settings.IgnoreCertificateErrors)
332 d7288179 pkanavos
                {
333 d7288179 pkanavos
                    ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true;
334 d7288179 pkanavos
                }
335 d7288179 pkanavos
                    
336 d7288179 pkanavos
				var accounts = Settings.Accounts.Select(MonitorAccount);
337 d7288179 pkanavos
                await TaskEx.WhenAll(accounts).ConfigureAwait(false);
338 d7288179 pkanavos
				_statusService = StatusService.Start();
339 d7288179 pkanavos
340 d7288179 pkanavos
			}
341 d7288179 pkanavos
			catch (AggregateException exc)
342 d7288179 pkanavos
			{
343 d7288179 pkanavos
				exc.Handle(e =>
344 d7288179 pkanavos
				{
345 d7288179 pkanavos
					Log.Error("Error while starting monitoring", e);
346 d7288179 pkanavos
					return true;
347 d7288179 pkanavos
				});
348 d7288179 pkanavos
				throw;
349 d7288179 pkanavos
			}
350 d7288179 pkanavos
		}
351 d7288179 pkanavos
352 d7288179 pkanavos
		protected override void OnDeactivate(bool close)
353 d7288179 pkanavos
		{
354 d7288179 pkanavos
			base.OnDeactivate(close);
355 d7288179 pkanavos
			if (close)
356 d7288179 pkanavos
			{
357 d7288179 pkanavos
				StatusService.Stop(_statusService);
358 d7288179 pkanavos
				_statusService = null;
359 d7288179 pkanavos
			}
360 d7288179 pkanavos
		}
361 d7288179 pkanavos
362 2115e2a5 pkanavos
		public async Task MonitorAccount(AccountSettings account)
363 d7288179 pkanavos
		{
364 2115e2a5 pkanavos
		    await TaskEx.Yield();                                                
365 d7288179 pkanavos
				PithosMonitor monitor;
366 d7288179 pkanavos
				var accountName = account.AccountName;
367 d7288179 pkanavos
368 d7288179 pkanavos
			    MigrateFolders(account);
369 d7288179 pkanavos
370 d7288179 pkanavos
			    Selectives.SetIsSelectiveEnabled(account.AccountKey, account.SelectiveSyncEnabled);
371 d7288179 pkanavos
372 d7288179 pkanavos
				if (Monitors.TryGetValue(account.AccountKey, out monitor))
373 d7288179 pkanavos
				{
374 d7288179 pkanavos
					//If the account is active
375 d7288179 pkanavos
                    if (account.IsActive)
376 d7288179 pkanavos
                    {
377 d7288179 pkanavos
                        //The Api Key may have changed throuth the Preferences dialog
378 d7288179 pkanavos
                        monitor.ApiKey = account.ApiKey;
379 d7288179 pkanavos
						Debug.Assert(monitor.StatusNotification == this,"An existing monitor should already have a StatusNotification service object");
380 d7288179 pkanavos
                        monitor.RootPath = account.RootPath;
381 d7288179 pkanavos
                        //Start the monitor. It's OK to start an already started monitor,
382 d7288179 pkanavos
                        //it will just ignore the call                        
383 2115e2a5 pkanavos
                        await StartMonitor(monitor);
384 d7288179 pkanavos
                    }
385 d7288179 pkanavos
                    else
386 d7288179 pkanavos
                    {
387 d7288179 pkanavos
                        //If the account is inactive
388 d7288179 pkanavos
                        //Stop and remove the monitor
389 d7288179 pkanavos
                        RemoveMonitor(account.ServerUrl,accountName);
390 d7288179 pkanavos
                    }
391 d7288179 pkanavos
					return;
392 d7288179 pkanavos
				}
393 d7288179 pkanavos
394 d7288179 pkanavos
				
395 d7288179 pkanavos
				//Create a new monitor/ Can't use MEF here, it would return a single instance for all monitors
396 d7288179 pkanavos
				monitor = new PithosMonitor
397 d7288179 pkanavos
							  {
398 d7288179 pkanavos
								  UserName = accountName,
399 d7288179 pkanavos
								  ApiKey = account.ApiKey,                                  
400 d7288179 pkanavos
								  StatusNotification = this,
401 d7288179 pkanavos
								  RootPath = account.RootPath
402 d7288179 pkanavos
							  };
403 d7288179 pkanavos
				//PithosMonitor uses MEF so we need to resolve it
404 d7288179 pkanavos
				IoC.BuildUp(monitor);
405 d7288179 pkanavos
406 d7288179 pkanavos
				monitor.AuthenticationUrl = account.ServerUrl;
407 d7288179 pkanavos
408 d7288179 pkanavos
				Monitors[account.AccountKey] = monitor;
409 d7288179 pkanavos
410 6e596fcb pkanavos
                if (!Directory.Exists(account.RootPath))
411 6e596fcb pkanavos
                {
412 6e596fcb pkanavos
                    account.IsActive = false;
413 855fc9c9 pkanavos
                    Settings.Save();
414 6e596fcb pkanavos
                    Notify(new Notification
415 6e596fcb pkanavos
                    {
416 6e596fcb pkanavos
                        Level = TraceLevel.Error,
417 6e596fcb pkanavos
                        Title = "Missing account folder",
418 6e596fcb pkanavos
                        Message = String.Format("Can't find the root folder for account {0} at {1}. The account was deactivated.\r" +
419 6e596fcb pkanavos
                        "If the account's files were stored in a removable disk, please connect it and reactivate the account", account.AccountName, account.RootPath)
420 6e596fcb pkanavos
                    });
421 6e596fcb pkanavos
                }
422 6e596fcb pkanavos
423 6e596fcb pkanavos
424 d7288179 pkanavos
				if (account.IsActive)
425 d7288179 pkanavos
				{
426 d7288179 pkanavos
					//Don't start a monitor if it doesn't have an account and ApiKey
427 d7288179 pkanavos
					if (String.IsNullOrWhiteSpace(monitor.UserName) ||
428 d7288179 pkanavos
						String.IsNullOrWhiteSpace(monitor.ApiKey))
429 d7288179 pkanavos
						return;
430 2115e2a5 pkanavos
					await StartMonitor(monitor);
431 d7288179 pkanavos
				}
432 2115e2a5 pkanavos
			
433 d7288179 pkanavos
		}
434 d7288179 pkanavos
435 d7288179 pkanavos
	    private void MigrateFolders(AccountSettings account)
436 d7288179 pkanavos
	    {
437 d7288179 pkanavos
	        var oldOthersFolder=Path.Combine(account.RootPath, FolderConstants.OldOthersFolder);
438 d7288179 pkanavos
	        var newOthersFolder = Path.Combine(account.RootPath, FolderConstants.OthersFolder);
439 d7288179 pkanavos
	        var oldFolder = new DirectoryInfo(oldOthersFolder);
440 d7288179 pkanavos
	        var newFolder = new DirectoryInfo(newOthersFolder);
441 d7288179 pkanavos
442 d7288179 pkanavos
            if (oldFolder.Exists && !newFolder.Exists)
443 d7288179 pkanavos
            {
444 d7288179 pkanavos
                oldFolder.MoveTo(newOthersFolder);
445 d7288179 pkanavos
            }
446 d7288179 pkanavos
	    }
447 d7288179 pkanavos
448 d7288179 pkanavos
449 d7288179 pkanavos
	    protected override void OnViewLoaded(object view)
450 d7288179 pkanavos
		{
451 d7288179 pkanavos
			UpdateStatus();
452 d7288179 pkanavos
			var window = (Window)view;            
453 d7288179 pkanavos
			TaskEx.Delay(1000).ContinueWith(t => Execute.OnUIThread(window.Hide));
454 d7288179 pkanavos
			base.OnViewLoaded(view);
455 d7288179 pkanavos
		}
456 d7288179 pkanavos
457 d7288179 pkanavos
458 d7288179 pkanavos
		#region Status Properties
459 d7288179 pkanavos
460 d7288179 pkanavos
		private string _statusMessage;
461 d7288179 pkanavos
		public string StatusMessage
462 d7288179 pkanavos
		{
463 d7288179 pkanavos
			get { return _statusMessage; }
464 d7288179 pkanavos
			set
465 d7288179 pkanavos
			{
466 d7288179 pkanavos
				_statusMessage = value;
467 d7288179 pkanavos
				NotifyOfPropertyChange(() => StatusMessage);
468 d7288179 pkanavos
                NotifyOfPropertyChange(() => TooltipMessage);
469 d7288179 pkanavos
			}
470 d7288179 pkanavos
		}
471 d7288179 pkanavos
472 f3b6a335 pkanavos
	    public int Progress
473 f3b6a335 pkanavos
	    {
474 f3b6a335 pkanavos
	        get { return _progress; }
475 f3b6a335 pkanavos
	        set
476 f3b6a335 pkanavos
	        {
477 f3b6a335 pkanavos
	            _progress = value;
478 f3b6a335 pkanavos
                NotifyOfPropertyChange(()=>Progress);
479 f3b6a335 pkanavos
	        }
480 f3b6a335 pkanavos
	    }
481 f3b6a335 pkanavos
482 f3b6a335 pkanavos
	    public string VersionMessage { get; set; }
483 d7288179 pkanavos
484 d7288179 pkanavos
	    public string TooltipMessage
485 d7288179 pkanavos
	    {
486 d7288179 pkanavos
	        get
487 d7288179 pkanavos
	        {
488 d7288179 pkanavos
	            return String.Format("{0}\r\n{1}",VersionMessage,StatusMessage);
489 d7288179 pkanavos
	        }
490 d7288179 pkanavos
	    }
491 d7288179 pkanavos
492 d7288179 pkanavos
        public string TooltipMiniStatus
493 d7288179 pkanavos
        {
494 d7288179 pkanavos
            get
495 d7288179 pkanavos
            {
496 d7288179 pkanavos
                return String.Format("{0}\r\n{1}", "Status Window", "Enable / Disable the status window");
497 d7288179 pkanavos
            }
498 d7288179 pkanavos
        }
499 d7288179 pkanavos
500 d7288179 pkanavos
        /*public string ToggleStatusWindowMessage
501 d7288179 pkanavos
        {
502 d7288179 pkanavos
            get
503 d7288179 pkanavos
            {
504 d7288179 pkanavos
                return String.Format("{0}" + Environment.NewLine + "{1} Toggle Mini Status");
505 d7288179 pkanavos
            }
506 d7288179 pkanavos
        }*/
507 d7288179 pkanavos
508 d7288179 pkanavos
	    private readonly ObservableConcurrentCollection<AccountInfo> _accounts = new ObservableConcurrentCollection<AccountInfo>();
509 d7288179 pkanavos
		public ObservableConcurrentCollection<AccountInfo> Accounts
510 d7288179 pkanavos
		{
511 d7288179 pkanavos
			get { return _accounts; }
512 d7288179 pkanavos
		}
513 d7288179 pkanavos
514 d7288179 pkanavos
		public bool HasAccounts
515 d7288179 pkanavos
		{
516 d7288179 pkanavos
			get { return _accounts.Count > 0; }
517 d7288179 pkanavos
		}
518 d7288179 pkanavos
519 d7288179 pkanavos
520 d7288179 pkanavos
		public string OpenFolderCaption
521 d7288179 pkanavos
		{
522 d7288179 pkanavos
			get
523 d7288179 pkanavos
			{
524 d7288179 pkanavos
				return (_accounts.Count == 0)
525 d7288179 pkanavos
						? "No Accounts Defined"
526 d7288179 pkanavos
						: "Open Pithos Folder";
527 d7288179 pkanavos
			}
528 d7288179 pkanavos
		}
529 d7288179 pkanavos
530 d7288179 pkanavos
		private string _pauseSyncCaption="Pause Synching";
531 d7288179 pkanavos
		public string PauseSyncCaption
532 d7288179 pkanavos
		{
533 d7288179 pkanavos
			get { return _pauseSyncCaption; }
534 d7288179 pkanavos
			set
535 d7288179 pkanavos
			{
536 d7288179 pkanavos
				_pauseSyncCaption = value;
537 d7288179 pkanavos
				NotifyOfPropertyChange(() => PauseSyncCaption);
538 d7288179 pkanavos
			}
539 d7288179 pkanavos
		}
540 d7288179 pkanavos
541 d7288179 pkanavos
		private readonly ObservableConcurrentCollection<FileEntry> _recentFiles = new ObservableConcurrentCollection<FileEntry>();
542 d7288179 pkanavos
		public ObservableConcurrentCollection<FileEntry> RecentFiles
543 d7288179 pkanavos
		{
544 d7288179 pkanavos
			get { return _recentFiles; }
545 d7288179 pkanavos
		}
546 d7288179 pkanavos
547 d7288179 pkanavos
548 d7288179 pkanavos
		private string _statusIcon="../Images/Pithos.ico";
549 d7288179 pkanavos
		public string StatusIcon
550 d7288179 pkanavos
		{
551 d7288179 pkanavos
			get { return _statusIcon; }
552 d7288179 pkanavos
			set
553 d7288179 pkanavos
			{
554 d7288179 pkanavos
				//TODO: Ensure all status icons use the Pithos logo
555 d7288179 pkanavos
				_statusIcon = value;
556 d7288179 pkanavos
				NotifyOfPropertyChange(() => StatusIcon);
557 d7288179 pkanavos
			}
558 d7288179 pkanavos
		}
559 d7288179 pkanavos
560 d7288179 pkanavos
		#endregion
561 d7288179 pkanavos
562 d7288179 pkanavos
		#region Commands
563 d7288179 pkanavos
564 d7288179 pkanavos
        public void CancelCurrentOperation()
565 d7288179 pkanavos
        {
566 d7288179 pkanavos
            _pollAgent.CancelCurrentOperation();
567 d7288179 pkanavos
        }
568 d7288179 pkanavos
569 d7288179 pkanavos
        public void ShowPreferences()
570 d7288179 pkanavos
        {
571 d7288179 pkanavos
            ShowPreferences(null);
572 d7288179 pkanavos
        }
573 d7288179 pkanavos
574 d7288179 pkanavos
		public void ShowPreferences(string currentTab)
575 d7288179 pkanavos
		{
576 d7288179 pkanavos
			//Settings.Reload();
577 d7288179 pkanavos
            
578 d7288179 pkanavos
		    var preferences = IoC.Get<PreferencesViewModel>();//??new PreferencesViewModel(_windowManager, _events, this, Settings,currentTab);
579 d7288179 pkanavos
            if (!String.IsNullOrWhiteSpace(currentTab))
580 d7288179 pkanavos
                preferences.SelectedTab = currentTab;
581 d7288179 pkanavos
            if (!preferences.IsActive)
582 d7288179 pkanavos
		        _windowManager.ShowWindow(preferences);
583 d7288179 pkanavos
            var view = (Window)preferences.GetView();
584 d7288179 pkanavos
            view.NullSafe(v=>v.Activate());
585 d7288179 pkanavos
		}
586 d7288179 pkanavos
587 d7288179 pkanavos
		public void AboutPithos()
588 d7288179 pkanavos
		{
589 d7288179 pkanavos
			var about = IoC.Get<AboutViewModel>();
590 d7288179 pkanavos
		    about.LatestVersion=_sparkle.LatestVersion;
591 d7288179 pkanavos
			_windowManager.ShowWindow(about);
592 d7288179 pkanavos
		}
593 d7288179 pkanavos
594 d7288179 pkanavos
		public void SendFeedback()
595 d7288179 pkanavos
		{
596 d7288179 pkanavos
			var feedBack =  IoC.Get<FeedbackViewModel>();
597 d7288179 pkanavos
			_windowManager.ShowWindow(feedBack);
598 d7288179 pkanavos
		}
599 d7288179 pkanavos
600 d7288179 pkanavos
		//public PithosCommand OpenPithosFolderCommand { get; private set; }
601 d7288179 pkanavos
602 d7288179 pkanavos
		public void OpenPithosFolder()
603 d7288179 pkanavos
		{
604 d7288179 pkanavos
			var account = Settings.Accounts.FirstOrDefault(acc => acc.IsActive);
605 d7288179 pkanavos
			if (account == null)
606 d7288179 pkanavos
				return;
607 d7288179 pkanavos
			Process.Start(account.RootPath);
608 d7288179 pkanavos
		}
609 d7288179 pkanavos
610 d7288179 pkanavos
		public void OpenPithosFolder(AccountInfo account)
611 d7288179 pkanavos
		{
612 d7288179 pkanavos
			Process.Start(account.AccountPath);
613 d7288179 pkanavos
		}
614 d7288179 pkanavos
615 d7288179 pkanavos
		
616 d7288179 pkanavos
617 d7288179 pkanavos
		public void GoToSite()
618 d7288179 pkanavos
		{            
619 d7288179 pkanavos
			var site = Properties.Settings.Default.ProductionServer;
620 d7288179 pkanavos
			Process.Start(site);            
621 d7288179 pkanavos
		}
622 d7288179 pkanavos
623 d7288179 pkanavos
624 d7288179 pkanavos
		public void GoToSite(AccountInfo account)
625 d7288179 pkanavos
		{
626 d7288179 pkanavos
		    var uri = account.SiteUri.Replace("http://","https://");            
627 d7288179 pkanavos
		    Process.Start(uri);
628 d7288179 pkanavos
		}
629 d7288179 pkanavos
630 d7288179 pkanavos
	    private bool _statusVisible;
631 d7288179 pkanavos
632 d7288179 pkanavos
	    public string MiniStatusCaption
633 d7288179 pkanavos
	    {
634 d7288179 pkanavos
	        get
635 d7288179 pkanavos
	        {
636 d7288179 pkanavos
	            return  _statusVisible ? "Hide Status Window" : "Show Status Window";
637 d7288179 pkanavos
	        }
638 d7288179 pkanavos
	    }
639 d7288179 pkanavos
640 d7288179 pkanavos
	    public bool HasConflicts
641 d7288179 pkanavos
	    {
642 d7288179 pkanavos
            get { return true; }
643 d7288179 pkanavos
	    }
644 d7288179 pkanavos
        public void ShowConflicts()
645 d7288179 pkanavos
        {
646 d7288179 pkanavos
            _windowManager.ShowWindow(IoC.Get<ConflictsViewModel>());            
647 d7288179 pkanavos
        }
648 d7288179 pkanavos
649 d7288179 pkanavos
	    /// <summary>
650 d7288179 pkanavos
        /// Open an explorer window to the target path's directory
651 d7288179 pkanavos
        /// and select the file
652 d7288179 pkanavos
        /// </summary>
653 d7288179 pkanavos
        /// <param name="entry"></param>
654 d7288179 pkanavos
        public void GoToFile(FileEntry entry)
655 d7288179 pkanavos
        {
656 d7288179 pkanavos
            var fullPath = entry.FullPath;
657 d7288179 pkanavos
            if (!File.Exists(fullPath) && !Directory.Exists(fullPath))
658 d7288179 pkanavos
                return;
659 d7288179 pkanavos
            Process.Start("explorer.exe","/select, " + fullPath);
660 d7288179 pkanavos
        }
661 d7288179 pkanavos
662 d7288179 pkanavos
        public void OpenLogPath()
663 d7288179 pkanavos
        {
664 d7288179 pkanavos
            var pithosDataPath = PithosSettings.PithosDataPath;
665 d7288179 pkanavos
666 d7288179 pkanavos
            Process.Start(pithosDataPath);
667 d7288179 pkanavos
        }
668 d7288179 pkanavos
        
669 d7288179 pkanavos
        public void ShowFileProperties()
670 d7288179 pkanavos
		{
671 d7288179 pkanavos
			var account = Settings.Accounts.First(acc => acc.IsActive);            
672 d7288179 pkanavos
			var dir = new DirectoryInfo(account.RootPath + @"\pithos");
673 d7288179 pkanavos
			var files=dir.GetFiles();
674 d7288179 pkanavos
			var r=new Random();
675 d7288179 pkanavos
			var idx=r.Next(0, files.Length);
676 d7288179 pkanavos
			ShowFileProperties(files[idx].FullName);            
677 d7288179 pkanavos
		}
678 d7288179 pkanavos
679 96e5791c pkanavos
		public void ShowFileProperties(string filePath)
680 d7288179 pkanavos
		{
681 d7288179 pkanavos
			if (String.IsNullOrWhiteSpace(filePath))
682 d7288179 pkanavos
				throw new ArgumentNullException("filePath");
683 d7288179 pkanavos
			if (!File.Exists(filePath) && !Directory.Exists(filePath))
684 d7288179 pkanavos
				throw new ArgumentException(String.Format("Non existent file {0}",filePath),"filePath");
685 d7288179 pkanavos
			Contract.EndContractBlock();
686 d7288179 pkanavos
687 d7288179 pkanavos
			var pair=(from monitor in  Monitors
688 d7288179 pkanavos
							   where filePath.StartsWith(monitor.Value.RootPath, StringComparison.InvariantCultureIgnoreCase)
689 d7288179 pkanavos
								   select monitor).FirstOrDefault();
690 d7288179 pkanavos
			var accountMonitor = pair.Value;
691 d7288179 pkanavos
692 d7288179 pkanavos
			if (accountMonitor == null)
693 d7288179 pkanavos
				return;
694 d7288179 pkanavos
695 397b9100 pkanavos
			var infoTask=accountMonitor.GetObjectInfo(filePath);
696 d7288179 pkanavos
697 d7288179 pkanavos
			
698 d7288179 pkanavos
699 d7288179 pkanavos
			var fileProperties = new FilePropertiesViewModel(this, infoTask,filePath);
700 d7288179 pkanavos
			_windowManager.ShowWindow(fileProperties);
701 d7288179 pkanavos
		} 
702 d7288179 pkanavos
		
703 d7288179 pkanavos
		public void ShowContainerProperties()
704 d7288179 pkanavos
		{
705 d7288179 pkanavos
			var account = Settings.Accounts.First(acc => acc.IsActive);            
706 d7288179 pkanavos
			var dir = new DirectoryInfo(account.RootPath);
707 d7288179 pkanavos
			var fullName = (from folder in dir.EnumerateDirectories()
708 d7288179 pkanavos
							where (folder.Attributes & FileAttributes.Hidden) == 0
709 d7288179 pkanavos
							select folder.FullName).First();
710 d7288179 pkanavos
			ShowContainerProperties(fullName);            
711 d7288179 pkanavos
		}
712 d7288179 pkanavos
713 d7288179 pkanavos
		public void ShowContainerProperties(string filePath)
714 d7288179 pkanavos
		{
715 d7288179 pkanavos
			if (String.IsNullOrWhiteSpace(filePath))
716 d7288179 pkanavos
				throw new ArgumentNullException("filePath");
717 d7288179 pkanavos
			if (!Directory.Exists(filePath))
718 d7288179 pkanavos
				throw new ArgumentException(String.Format("Non existent file {0}",filePath),"filePath");
719 d7288179 pkanavos
			Contract.EndContractBlock();
720 d7288179 pkanavos
721 d7288179 pkanavos
			var pair=(from monitor in  Monitors
722 d7288179 pkanavos
							   where filePath.StartsWith(monitor.Value.RootPath, StringComparison.InvariantCultureIgnoreCase)
723 d7288179 pkanavos
								   select monitor).FirstOrDefault();
724 d7288179 pkanavos
			var accountMonitor = pair.Value;            
725 d7288179 pkanavos
			var info = accountMonitor.GetContainerInfo(filePath);
726 d7288179 pkanavos
727 d7288179 pkanavos
			
728 d7288179 pkanavos
729 d7288179 pkanavos
			var containerProperties = new ContainerPropertiesViewModel(this, info,filePath);
730 d7288179 pkanavos
			_windowManager.ShowWindow(containerProperties);
731 d7288179 pkanavos
		}
732 d7288179 pkanavos
733 d7288179 pkanavos
		public void SynchNow()
734 d7288179 pkanavos
		{
735 d7288179 pkanavos
			_pollAgent.SynchNow();
736 d7288179 pkanavos
		}
737 d7288179 pkanavos
738 397b9100 pkanavos
		public async Task<ObjectInfo> RefreshObjectInfo(ObjectInfo currentInfo)
739 d7288179 pkanavos
		{
740 d7288179 pkanavos
			if (currentInfo==null)
741 d7288179 pkanavos
				throw new ArgumentNullException("currentInfo");
742 d7288179 pkanavos
			Contract.EndContractBlock();		    
743 d7288179 pkanavos
            var monitor = Monitors[currentInfo.AccountKey];
744 397b9100 pkanavos
			var newInfo=await monitor.CloudClient.GetObjectInfo(currentInfo.Account, currentInfo.Container, currentInfo.Name).ConfigureAwait(false);
745 d7288179 pkanavos
			return newInfo;
746 d7288179 pkanavos
		}
747 d7288179 pkanavos
748 8d38a269 pkanavos
		public async Task<ContainerInfo> RefreshContainerInfo(ContainerInfo container)
749 d7288179 pkanavos
		{
750 d7288179 pkanavos
			if (container == null)
751 d7288179 pkanavos
				throw new ArgumentNullException("container");
752 d7288179 pkanavos
			Contract.EndContractBlock();
753 d7288179 pkanavos
754 d7288179 pkanavos
			var monitor = Monitors[container.AccountKey];
755 8d38a269 pkanavos
			var newInfo = await monitor.CloudClient.GetContainerInfo(container.Account, container.Name).ConfigureAwait(false);
756 d7288179 pkanavos
			return newInfo;
757 d7288179 pkanavos
		}
758 d7288179 pkanavos
759 d7288179 pkanavos
	    private bool _isPaused;
760 d7288179 pkanavos
	    public bool IsPaused
761 d7288179 pkanavos
	    {
762 d7288179 pkanavos
	        get { return _isPaused; }
763 d7288179 pkanavos
	        set
764 d7288179 pkanavos
	        {
765 d7288179 pkanavos
	            _isPaused = value;
766 d7288179 pkanavos
                PauseSyncCaption = IsPaused ? "Resume syncing" : "Pause syncing";
767 d7288179 pkanavos
                var iconKey = IsPaused ? "TraySyncPaused" : "TrayInSynch";
768 d7288179 pkanavos
                StatusIcon = String.Format(@"../Images/{0}.ico", iconKey);
769 d7288179 pkanavos
770 d7288179 pkanavos
                NotifyOfPropertyChange(() => IsPaused);
771 d7288179 pkanavos
	        }
772 d7288179 pkanavos
	    }
773 d7288179 pkanavos
774 d7288179 pkanavos
	    public void ToggleSynching()
775 d7288179 pkanavos
		{
776 d7288179 pkanavos
			IsPaused=!IsPaused;
777 d7288179 pkanavos
			foreach (var monitor in Monitors.Values)
778 d7288179 pkanavos
			{
779 d7288179 pkanavos
			    monitor.Pause = IsPaused ;
780 d7288179 pkanavos
			}
781 d7288179 pkanavos
            _pollAgent.Pause = IsPaused;
782 d7288179 pkanavos
            _networkAgent.Pause = IsPaused;
783 d7288179 pkanavos
784 d7288179 pkanavos
785 d7288179 pkanavos
		}
786 d7288179 pkanavos
787 d7288179 pkanavos
        public void ExitPithos()
788 d7288179 pkanavos
        {
789 d7288179 pkanavos
            try
790 d7288179 pkanavos
            {
791 d7288179 pkanavos
792 d7288179 pkanavos
                foreach (var monitor in Monitors.Select(pair => pair.Value))
793 d7288179 pkanavos
                {
794 d7288179 pkanavos
                    monitor.Stop();
795 d7288179 pkanavos
                }
796 d7288179 pkanavos
797 d7288179 pkanavos
                var view = GetView() as Window;
798 d7288179 pkanavos
                if (view != null)
799 d7288179 pkanavos
                    view.Close();
800 d7288179 pkanavos
            }
801 d7288179 pkanavos
            catch (Exception exc)
802 d7288179 pkanavos
            {
803 d7288179 pkanavos
                Log.Info("Exception while exiting", exc);                
804 d7288179 pkanavos
            }
805 d7288179 pkanavos
            finally
806 d7288179 pkanavos
            {
807 d7288179 pkanavos
                Application.Current.Shutdown();
808 d7288179 pkanavos
            }
809 d7288179 pkanavos
        }
810 d7288179 pkanavos
811 d7288179 pkanavos
	    #endregion
812 d7288179 pkanavos
813 d7288179 pkanavos
814 d7288179 pkanavos
		private readonly Dictionary<PithosStatus, StatusInfo> _iconNames = new List<StatusInfo>
815 d7288179 pkanavos
			{
816 d7288179 pkanavos
				new StatusInfo(PithosStatus.InSynch, "All files up to date", "TrayInSynch"),
817 d7288179 pkanavos
				new StatusInfo(PithosStatus.PollSyncing, "Polling Files", "TraySynching"),
818 d7288179 pkanavos
                new StatusInfo(PithosStatus.LocalSyncing, "Syncing Files", "TraySynching"),
819 d7288179 pkanavos
				new StatusInfo(PithosStatus.SyncPaused, "Sync Paused", "TraySyncPaused")
820 d7288179 pkanavos
			}.ToDictionary(s => s.Status);
821 d7288179 pkanavos
822 d7288179 pkanavos
		readonly IWindowManager _windowManager;
823 d7288179 pkanavos
		
824 d7288179 pkanavos
        //private int _syncCount=0;
825 d7288179 pkanavos
826 d7288179 pkanavos
827 d7288179 pkanavos
        private PithosStatus _pithosStatus = PithosStatus.Disconnected;
828 d7288179 pkanavos
829 d7288179 pkanavos
        public void SetPithosStatus(PithosStatus status)
830 d7288179 pkanavos
        {
831 d7288179 pkanavos
            if (_pithosStatus == PithosStatus.LocalSyncing && status == PithosStatus.PollComplete)
832 d7288179 pkanavos
                return;
833 d7288179 pkanavos
            if (_pithosStatus == PithosStatus.PollSyncing && status == PithosStatus.LocalComplete)
834 d7288179 pkanavos
                return;
835 d7288179 pkanavos
            if (status == PithosStatus.LocalComplete || status == PithosStatus.PollComplete)
836 d7288179 pkanavos
                _pithosStatus = PithosStatus.InSynch;
837 d7288179 pkanavos
            else
838 d7288179 pkanavos
                _pithosStatus = status;
839 d7288179 pkanavos
            UpdateStatus();
840 d7288179 pkanavos
        }
841 d7288179 pkanavos
842 d7288179 pkanavos
        public void SetPithosStatus(PithosStatus status,string message)
843 d7288179 pkanavos
        {
844 d7288179 pkanavos
            StatusMessage = message;
845 d7288179 pkanavos
            SetPithosStatus(status);
846 d7288179 pkanavos
        }
847 d7288179 pkanavos
848 d7288179 pkanavos
	  /*  public Notifier GetNotifier(Notification startNotification, Notification endNotification)
849 d7288179 pkanavos
	    {
850 d7288179 pkanavos
	        return new Notifier(this, startNotification, endNotification);
851 d7288179 pkanavos
	    }*/
852 d7288179 pkanavos
853 cfb09103 pkanavos
	    public Notifier GetNotifier(string startMessage, string endMessage, bool isActive=true,params object[] args)
854 d7288179 pkanavos
	    {
855 cfb09103 pkanavos
	        return isActive?new Notifier(this, 
856 e7fb3ef2 George Pantazis
                new StatusNotification(String.Format(startMessage,args)),
857 cfb09103 pkanavos
                new StatusNotification(String.Format(endMessage,args)))
858 cfb09103 pkanavos
                :new Notifier(this,(Notification) null,null);
859 d7288179 pkanavos
	    }
860 d7288179 pkanavos
861 d7288179 pkanavos
862 d7288179 pkanavos
	    ///<summary>
863 d7288179 pkanavos
		/// Updates the visual status indicators of the application depending on status changes, e.g. icon, stat		
864 d7288179 pkanavos
		///</summary>
865 d7288179 pkanavos
		public void UpdateStatus()
866 d7288179 pkanavos
		{
867 d7288179 pkanavos
868 d7288179 pkanavos
			if (_iconNames.ContainsKey(_pithosStatus))
869 d7288179 pkanavos
			{
870 d7288179 pkanavos
				var info = _iconNames[_pithosStatus];
871 d7288179 pkanavos
				StatusIcon = String.Format(@"../Images/{0}.ico", info.IconName);
872 d7288179 pkanavos
			}
873 d7288179 pkanavos
874 d7288179 pkanavos
            if (_pithosStatus == PithosStatus.InSynch)
875 d7288179 pkanavos
                StatusMessage = "All files up to date";
876 d7288179 pkanavos
		}
877 d7288179 pkanavos
878 d7288179 pkanavos
879 d7288179 pkanavos
	   
880 dd5f5163 pkanavos
		public async Task StartMonitor(PithosMonitor monitor,int retries=0)
881 dd5f5163 pkanavos
		{
882 dd5f5163 pkanavos
		    using (log4net.ThreadContext.Stacks["Monitor"].Push("Start"))
883 dd5f5163 pkanavos
		    {
884 dd5f5163 pkanavos
		        try
885 dd5f5163 pkanavos
		        {
886 dd5f5163 pkanavos
		            Log.InfoFormat("Start Monitoring {0}", monitor.UserName);
887 dd5f5163 pkanavos
888 dd5f5163 pkanavos
		            await monitor.Start();
889 dd5f5163 pkanavos
		        }
890 dd5f5163 pkanavos
                catch (HttpRequestWithStatusException exc)
891 dd5f5163 pkanavos
		        {
892 dd5f5163 pkanavos
		            if (AbandonRetry(monitor, retries))
893 dd5f5163 pkanavos
		                return;
894 dd5f5163 pkanavos
895 dd5f5163 pkanavos
		            //HttpStatusCode statusCode = HttpStatusCode.OK;
896 dd5f5163 pkanavos
		            //var response =  as HttpWebResponse;
897 dd5f5163 pkanavos
		            //if (response != null)
898 dd5f5163 pkanavos
		            var statusCode = exc.StatusCode;//response.StatusCode;
899 dd5f5163 pkanavos
900 dd5f5163 pkanavos
		            switch (statusCode)
901 dd5f5163 pkanavos
		            {
902 dd5f5163 pkanavos
		                case HttpStatusCode.Unauthorized:
903 dd5f5163 pkanavos
		                    var message = String.Format("API Key Expired for {0}. Starting Renewal",
904 dd5f5163 pkanavos
		                                                monitor.UserName);
905 dd5f5163 pkanavos
		                    Log.Error(message, exc);
906 dd5f5163 pkanavos
		                    var account =
907 dd5f5163 pkanavos
		                        Settings.Accounts.Find(
908 dd5f5163 pkanavos
		                            acc => acc.AccountKey == new Uri(monitor.AuthenticationUrl).Combine(monitor.UserName));
909 dd5f5163 pkanavos
		                    account.IsExpired = true;
910 dd5f5163 pkanavos
                            Settings.Save();
911 dd5f5163 pkanavos
		                    Notify(new ExpirationNotification(account));
912 dd5f5163 pkanavos
		                    //TryAuthorize(monitor.UserName, retries).Wait();
913 dd5f5163 pkanavos
		                    break;
914 dd5f5163 pkanavos
		                case HttpStatusCode.ProxyAuthenticationRequired:
915 dd5f5163 pkanavos
		                    TryAuthenticateProxy(monitor, retries);
916 dd5f5163 pkanavos
		                    break;
917 dd5f5163 pkanavos
		                default:
918 dd5f5163 pkanavos
		                    TryLater(monitor, exc, retries);
919 dd5f5163 pkanavos
		                    break;
920 dd5f5163 pkanavos
		            }
921 dd5f5163 pkanavos
		        }
922 dd5f5163 pkanavos
		        catch (Exception exc)
923 dd5f5163 pkanavos
		        {
924 dd5f5163 pkanavos
		            if (AbandonRetry(monitor, retries))
925 dd5f5163 pkanavos
		                return;
926 dd5f5163 pkanavos
927 dd5f5163 pkanavos
		            TryLater(monitor, exc, retries);
928 dd5f5163 pkanavos
		        }
929 dd5f5163 pkanavos
		    }
930 dd5f5163 pkanavos
931 d7288179 pkanavos
		}
932 d7288179 pkanavos
933 dd5f5163 pkanavos
	    private void TryAuthenticateProxy(PithosMonitor monitor,int retries)
934 d7288179 pkanavos
		{
935 2115e2a5 pkanavos
			Execute.OnUIThread(async () =>
936 d7288179 pkanavos
								   {                                       
937 d7288179 pkanavos
									   var proxyAccount = IoC.Get<ProxyAccountViewModel>();
938 d7288179 pkanavos
										proxyAccount.Settings = Settings;
939 d7288179 pkanavos
									   if (true != _windowManager.ShowDialog(proxyAccount)) 
940 d7288179 pkanavos
										   return;
941 2115e2a5 pkanavos
									   await StartMonitor(monitor, retries);
942 d7288179 pkanavos
									   NotifyOfPropertyChange(() => Accounts);
943 d7288179 pkanavos
								   });
944 d7288179 pkanavos
		}
945 d7288179 pkanavos
946 d7288179 pkanavos
		private bool AbandonRetry(PithosMonitor monitor, int retries)
947 d7288179 pkanavos
		{
948 d7288179 pkanavos
			if (retries > 3)
949 d7288179 pkanavos
			{
950 d7288179 pkanavos
				var message = String.Format("Monitoring of account {0} has failed too many times. Will not retry",
951 d7288179 pkanavos
											monitor.UserName);
952 d7288179 pkanavos
				_events.Publish(new Notification
953 d7288179 pkanavos
									{Title = "Account monitoring failed", Message = message, Level = TraceLevel.Error});
954 d7288179 pkanavos
				return true;
955 d7288179 pkanavos
			}
956 d7288179 pkanavos
			return false;
957 d7288179 pkanavos
		}
958 d7288179 pkanavos
959 d7288179 pkanavos
960 d7288179 pkanavos
	    private void TryLater(PithosMonitor monitor, Exception exc,int retries)
961 d7288179 pkanavos
		{
962 d7288179 pkanavos
			var message = String.Format("An exception occured. Can't start monitoring\nWill retry in 10 seconds");
963 2115e2a5 pkanavos
            
964 2115e2a5 pkanavos
			TaskEx.Delay(10000).ContinueWith(t=>StartMonitor(monitor,retries+1));
965 d7288179 pkanavos
			_events.Publish(new Notification
966 d7288179 pkanavos
								{Title = "Error", Message = message, Level = TraceLevel.Error});
967 d7288179 pkanavos
			Log.Error(message, exc);
968 d7288179 pkanavos
		}
969 d7288179 pkanavos
970 d7288179 pkanavos
971 d7288179 pkanavos
		public void NotifyChange(string status, TraceLevel level=TraceLevel.Info)
972 d7288179 pkanavos
		{
973 d7288179 pkanavos
			StatusMessage = status;
974 d7288179 pkanavos
			
975 d7288179 pkanavos
			_events.Publish(new Notification { Title = "Pithos+", Message = status, Level = level });
976 d7288179 pkanavos
		}
977 d7288179 pkanavos
978 d7288179 pkanavos
		public void NotifyChangedFile(string filePath)
979 d7288179 pkanavos
		{
980 d7288179 pkanavos
            if (RecentFiles.Any(e => e.FullPath == filePath))
981 d7288179 pkanavos
                return;
982 d7288179 pkanavos
            
983 d7288179 pkanavos
			IProducerConsumerCollection<FileEntry> files=RecentFiles;
984 d7288179 pkanavos
			FileEntry popped;
985 d7288179 pkanavos
			while (files.Count > 5)
986 d7288179 pkanavos
				files.TryTake(out popped);
987 d7288179 pkanavos
            var entry = new FileEntry { FullPath = filePath };
988 d7288179 pkanavos
			files.TryAdd(entry);
989 d7288179 pkanavos
		}
990 d7288179 pkanavos
991 d7288179 pkanavos
		public void NotifyAccount(AccountInfo account)
992 d7288179 pkanavos
		{
993 d7288179 pkanavos
			if (account== null)
994 d7288179 pkanavos
				return;
995 d7288179 pkanavos
			//TODO: What happens to an existing account whose Token has changed?
996 d7288179 pkanavos
			account.SiteUri= String.Format("{0}/ui/?token={1}&user={2}",
997 d7288179 pkanavos
				account.SiteUri, Uri.EscapeDataString(account.Token),
998 d7288179 pkanavos
				Uri.EscapeDataString(account.UserName));
999 d7288179 pkanavos
1000 d7288179 pkanavos
			if (!Accounts.Any(item => item.UserName == account.UserName && item.SiteUri == account.SiteUri))
1001 d7288179 pkanavos
				Accounts.TryAdd(account);
1002 d7288179 pkanavos
1003 d7288179 pkanavos
		}
1004 d7288179 pkanavos
1005 d7288179 pkanavos
		public void NotifyConflicts(IEnumerable<FileSystemInfo> conflictFiles, string message)
1006 d7288179 pkanavos
		{
1007 d7288179 pkanavos
			if (conflictFiles == null)
1008 d7288179 pkanavos
				return;
1009 d7288179 pkanavos
		    //Convert to list to avoid multiple iterations
1010 d7288179 pkanavos
            var files = conflictFiles.ToList();
1011 d7288179 pkanavos
			if (files.Count==0)
1012 d7288179 pkanavos
				return;
1013 d7288179 pkanavos
1014 d7288179 pkanavos
			UpdateStatus();
1015 d7288179 pkanavos
			//TODO: Create a more specific message. For now, just show a warning
1016 d7288179 pkanavos
			NotifyForFiles(files,message,TraceLevel.Warning);
1017 d7288179 pkanavos
1018 d7288179 pkanavos
		}
1019 d7288179 pkanavos
1020 d7288179 pkanavos
		public void NotifyForFiles(IEnumerable<FileSystemInfo> files, string message,TraceLevel level=TraceLevel.Info)
1021 d7288179 pkanavos
		{
1022 d7288179 pkanavos
			if (files == null)
1023 d7288179 pkanavos
				return;
1024 d7288179 pkanavos
			if (!files.Any())
1025 d7288179 pkanavos
				return;
1026 d7288179 pkanavos
1027 d7288179 pkanavos
			StatusMessage = message;
1028 d7288179 pkanavos
1029 d7288179 pkanavos
			_events.Publish(new Notification { Title = "Pithos+", Message = message, Level = level});
1030 d7288179 pkanavos
		}
1031 d7288179 pkanavos
1032 d7288179 pkanavos
		public void Notify(Notification notification)
1033 d7288179 pkanavos
		{
1034 d7288179 pkanavos
            TaskEx.Run(()=> _events.Publish(notification));
1035 d7288179 pkanavos
		}
1036 d7288179 pkanavos
1037 d7288179 pkanavos
1038 d7288179 pkanavos
		public void RemoveMonitor(string serverUrl,string accountName)
1039 d7288179 pkanavos
		{
1040 d7288179 pkanavos
			if (String.IsNullOrWhiteSpace(accountName))
1041 d7288179 pkanavos
				return;
1042 d7288179 pkanavos
1043 d7288179 pkanavos
			var accountInfo=_accounts.FirstOrDefault(account => account.UserName == accountName && account.StorageUri.ToString().StartsWith(serverUrl));
1044 d7288179 pkanavos
            if (accountInfo != null)
1045 d7288179 pkanavos
            {
1046 d7288179 pkanavos
                _accounts.TryRemove(accountInfo);
1047 d7288179 pkanavos
                _pollAgent.RemoveAccount(accountInfo);
1048 d7288179 pkanavos
            }
1049 d7288179 pkanavos
1050 d7288179 pkanavos
            var accountKey = new Uri(serverUrl).Combine(accountName);
1051 d7288179 pkanavos
		    PithosMonitor monitor;
1052 d7288179 pkanavos
			if (Monitors.TryRemove(accountKey, out monitor))
1053 d7288179 pkanavos
			{
1054 d7288179 pkanavos
				monitor.Stop();
1055 d7288179 pkanavos
                //TODO: Also remove any pending actions for this account
1056 d7288179 pkanavos
                //from the network queue                
1057 d7288179 pkanavos
			}
1058 d7288179 pkanavos
		}
1059 d7288179 pkanavos
1060 d7288179 pkanavos
		public void RefreshOverlays()
1061 d7288179 pkanavos
		{
1062 d7288179 pkanavos
			foreach (var pair in Monitors)
1063 d7288179 pkanavos
			{
1064 d7288179 pkanavos
				var monitor = pair.Value;
1065 d7288179 pkanavos
1066 d7288179 pkanavos
				var path = monitor.RootPath;
1067 d7288179 pkanavos
1068 d7288179 pkanavos
				if (String.IsNullOrWhiteSpace(path))
1069 d7288179 pkanavos
					continue;
1070 d7288179 pkanavos
1071 d7288179 pkanavos
				if (!Directory.Exists(path) && !File.Exists(path))
1072 d7288179 pkanavos
					continue;
1073 d7288179 pkanavos
1074 d7288179 pkanavos
				IntPtr pathPointer = Marshal.StringToCoTaskMemAuto(path);
1075 d7288179 pkanavos
1076 d7288179 pkanavos
				try
1077 d7288179 pkanavos
				{
1078 d7288179 pkanavos
					NativeMethods.SHChangeNotify(HChangeNotifyEventID.SHCNE_UPDATEITEM,
1079 d7288179 pkanavos
												 HChangeNotifyFlags.SHCNF_PATHW | HChangeNotifyFlags.SHCNF_FLUSHNOWAIT,
1080 d7288179 pkanavos
												 pathPointer, IntPtr.Zero);
1081 d7288179 pkanavos
				}
1082 d7288179 pkanavos
				finally
1083 d7288179 pkanavos
				{
1084 d7288179 pkanavos
					Marshal.FreeHGlobal(pathPointer);
1085 d7288179 pkanavos
				}
1086 d7288179 pkanavos
			}
1087 d7288179 pkanavos
		}
1088 d7288179 pkanavos
1089 d7288179 pkanavos
		#region Event Handlers
1090 d7288179 pkanavos
		
1091 d7288179 pkanavos
		public void Handle(SelectiveSynchChanges message)
1092 d7288179 pkanavos
		{
1093 d7288179 pkanavos
		    TaskEx.Run(() =>
1094 d7288179 pkanavos
		    {
1095 d7288179 pkanavos
		        PithosMonitor monitor;
1096 d7288179 pkanavos
		        if (Monitors.TryGetValue(message.Account.AccountKey, out monitor))
1097 d7288179 pkanavos
		        {
1098 d7288179 pkanavos
                    Selectives.SetIsSelectiveEnabled(message.Account.AccountKey, message.Enabled);
1099 d7288179 pkanavos
		            monitor.SetSelectivePaths(message.Uris, message.Added, message.Removed);
1100 d7288179 pkanavos
		        }
1101 d7288179 pkanavos
1102 d7288179 pkanavos
		        var account = Accounts.FirstOrDefault(acc => acc.AccountKey == message.Account.AccountKey);
1103 d7288179 pkanavos
		        if (account != null)
1104 d7288179 pkanavos
		        {
1105 d7288179 pkanavos
		            var added=monitor.UrisToFilePaths(message.Added);
1106 d7288179 pkanavos
                    _pollAgent.SynchNow(added);
1107 d7288179 pkanavos
		        }
1108 d7288179 pkanavos
		    });
1109 d7288179 pkanavos
1110 d7288179 pkanavos
		}
1111 d7288179 pkanavos
1112 d7288179 pkanavos
1113 d7288179 pkanavos
		private bool _pollStarted;
1114 d7288179 pkanavos
	    private Sparkle _sparkle;
1115 d7288179 pkanavos
	    private bool _manualUpgradeCheck;
1116 f3b6a335 pkanavos
	    private int _progress;
1117 d7288179 pkanavos
1118 d7288179 pkanavos
	    //SMELL: Doing so much work for notifications in the shell is wrong
1119 d7288179 pkanavos
		//The notifications should be moved to their own view/viewmodel pair
1120 d7288179 pkanavos
		//and different templates should be used for different message types
1121 d7288179 pkanavos
		//This will also allow the addition of extra functionality, eg. actions
1122 d7288179 pkanavos
		//
1123 d7288179 pkanavos
		public void Handle(Notification notification)
1124 d7288179 pkanavos
		{
1125 d7288179 pkanavos
			UpdateStatus();
1126 d7288179 pkanavos
1127 d7288179 pkanavos
			if (!Settings.ShowDesktopNotifications)
1128 d7288179 pkanavos
				return;
1129 d7288179 pkanavos
1130 f3b6a335 pkanavos
            var progress = notification as ProgressNotification;
1131 f3b6a335 pkanavos
1132 f3b6a335 pkanavos
1133 f3b6a335 pkanavos
            if (progress != null)
1134 f3b6a335 pkanavos
            {
1135 f3b6a335 pkanavos
                double percentage = (progress.TotalBlocks == progress.Block) ? 1
1136 f3b6a335 pkanavos
                    : (progress.Block + progress.BlockPercentage / 100.0) / (double)progress.TotalBlocks;
1137 f3b6a335 pkanavos
                StatusMessage = String.Format("{0} {1:p2} of {2} - {3}",
1138 f3b6a335 pkanavos
                                              progress.Action,
1139 f3b6a335 pkanavos
                                              percentage,
1140 f3b6a335 pkanavos
                                              progress.FileSize.ToByteSize(),
1141 f3b6a335 pkanavos
                                              progress.FileName);
1142 f3b6a335 pkanavos
                Progress = (int)(percentage * 100);
1143 f3b6a335 pkanavos
                return;
1144 f3b6a335 pkanavos
            }
1145 f3b6a335 pkanavos
1146 f3b6a335 pkanavos
            //If this is not a progress bar message, set the bar to 0
1147 f3b6a335 pkanavos
            Progress = 0;
1148 f3b6a335 pkanavos
            
1149 f3b6a335 pkanavos
            if (notification is PollNotification)
1150 d7288179 pkanavos
			{
1151 d7288179 pkanavos
				_pollStarted = true;
1152 d7288179 pkanavos
				return;
1153 d7288179 pkanavos
			}
1154 d7288179 pkanavos
			if (notification is CloudNotification)
1155 d7288179 pkanavos
			{
1156 d7288179 pkanavos
				if (!_pollStarted) 
1157 d7288179 pkanavos
					return;
1158 d7288179 pkanavos
				_pollStarted= false;
1159 d7288179 pkanavos
				notification.Title = "Pithos+";
1160 d7288179 pkanavos
				notification.Message = "Start Synchronisation";
1161 d7288179 pkanavos
			}
1162 d7288179 pkanavos
1163 d7288179 pkanavos
		    var deleteNotification = notification as CloudDeleteNotification;
1164 d7288179 pkanavos
            if (deleteNotification != null)
1165 d7288179 pkanavos
            {
1166 d7288179 pkanavos
                StatusMessage = String.Format("Deleted {0}", deleteNotification.Data.Name);
1167 d7288179 pkanavos
                return;
1168 d7288179 pkanavos
            }
1169 d7288179 pkanavos
1170 d7288179 pkanavos
1171 d7288179 pkanavos
		    var info = notification as StatusNotification;
1172 d7288179 pkanavos
            if (info != null)
1173 d7288179 pkanavos
            {
1174 d7288179 pkanavos
                StatusMessage = info.Title;
1175 d7288179 pkanavos
                return;
1176 d7288179 pkanavos
            }
1177 d7288179 pkanavos
			if (String.IsNullOrWhiteSpace(notification.Message) && String.IsNullOrWhiteSpace(notification.Title))
1178 d7288179 pkanavos
				return;
1179 d7288179 pkanavos
1180 d7288179 pkanavos
            if (notification.Level <= TraceLevel.Warning)
1181 d7288179 pkanavos
			    ShowBalloonFor(notification);
1182 d7288179 pkanavos
		}
1183 d7288179 pkanavos
1184 d7288179 pkanavos
	    private void ShowBalloonFor(Notification notification)
1185 d7288179 pkanavos
	    {
1186 d7288179 pkanavos
            Contract.Requires(notification!=null);
1187 d7288179 pkanavos
            
1188 d7288179 pkanavos
            if (!Settings.ShowDesktopNotifications) 
1189 d7288179 pkanavos
                return;
1190 d7288179 pkanavos
            
1191 d7288179 pkanavos
            BalloonIcon icon;
1192 d7288179 pkanavos
	        switch (notification.Level)
1193 d7288179 pkanavos
	        {
1194 d7288179 pkanavos
                case TraceLevel.Verbose:
1195 d7288179 pkanavos
	                return;
1196 d7288179 pkanavos
	            case TraceLevel.Info:	            
1197 d7288179 pkanavos
	                icon = BalloonIcon.Info;
1198 d7288179 pkanavos
	                break;
1199 d7288179 pkanavos
                case TraceLevel.Error:
1200 d7288179 pkanavos
                    icon = BalloonIcon.Error;
1201 d7288179 pkanavos
                    break;
1202 d7288179 pkanavos
                case TraceLevel.Warning:
1203 d7288179 pkanavos
	                icon = BalloonIcon.Warning;
1204 d7288179 pkanavos
	                break;
1205 d7288179 pkanavos
	            default:
1206 d7288179 pkanavos
	                return;
1207 d7288179 pkanavos
	        }
1208 d7288179 pkanavos
1209 d7288179 pkanavos
	        var tv = (ShellView) GetView();
1210 d7288179 pkanavos
	        System.Action clickAction = null;
1211 d7288179 pkanavos
	        if (notification is ExpirationNotification)
1212 d7288179 pkanavos
	        {
1213 d7288179 pkanavos
	            clickAction = () => ShowPreferences("AccountTab");
1214 d7288179 pkanavos
	        }
1215 d7288179 pkanavos
	        var balloon = new PithosBalloon
1216 d7288179 pkanavos
	                          {
1217 d7288179 pkanavos
	                              Title = notification.Title,
1218 d7288179 pkanavos
	                              Message = notification.Message,
1219 d7288179 pkanavos
	                              Icon = icon,
1220 d7288179 pkanavos
	                              ClickAction = clickAction
1221 d7288179 pkanavos
	                          };
1222 d7288179 pkanavos
	        tv.TaskbarView.ShowCustomBalloon(balloon, PopupAnimation.Fade, 4000);
1223 d7288179 pkanavos
	    }
1224 d7288179 pkanavos
1225 d7288179 pkanavos
	    #endregion
1226 d7288179 pkanavos
1227 d7288179 pkanavos
		public void Handle(ShowFilePropertiesEvent message)
1228 d7288179 pkanavos
		{
1229 d7288179 pkanavos
			if (message == null)
1230 d7288179 pkanavos
				throw new ArgumentNullException("message");
1231 d7288179 pkanavos
			if (String.IsNullOrWhiteSpace(message.FileName) )
1232 d7288179 pkanavos
				throw new ArgumentException("message");
1233 d7288179 pkanavos
			Contract.EndContractBlock();
1234 d7288179 pkanavos
1235 d7288179 pkanavos
			var fileName = message.FileName;
1236 d7288179 pkanavos
			//TODO: Display file properties for non-container folders
1237 d7288179 pkanavos
			if (File.Exists(fileName))
1238 d7288179 pkanavos
				//Retrieve the full name with exact casing. Pithos names are case sensitive				
1239 d7288179 pkanavos
				ShowFileProperties(FileInfoExtensions.GetProperFilePathCapitalization(fileName));
1240 d7288179 pkanavos
			else if (Directory.Exists(fileName))
1241 d7288179 pkanavos
				//Retrieve the full name with exact casing. Pithos names are case sensitive
1242 d7288179 pkanavos
			{
1243 d7288179 pkanavos
				var path = FileInfoExtensions.GetProperDirectoryCapitalization(fileName);
1244 d7288179 pkanavos
				if (IsContainer(path))
1245 d7288179 pkanavos
					ShowContainerProperties(path);
1246 d7288179 pkanavos
				else
1247 d7288179 pkanavos
					ShowFileProperties(path);
1248 d7288179 pkanavos
			}
1249 d7288179 pkanavos
		}
1250 d7288179 pkanavos
1251 d7288179 pkanavos
		private bool IsContainer(string path)
1252 d7288179 pkanavos
		{
1253 d7288179 pkanavos
			var matchingFolders = from account in _accounts
1254 d7288179 pkanavos
								  from rootFolder in Directory.GetDirectories(account.AccountPath)
1255 d7288179 pkanavos
								  where rootFolder.Equals(path, StringComparison.InvariantCultureIgnoreCase)
1256 d7288179 pkanavos
								  select rootFolder;
1257 d7288179 pkanavos
			return matchingFolders.Any();
1258 d7288179 pkanavos
		}
1259 d7288179 pkanavos
1260 d7288179 pkanavos
		public FileStatus GetFileStatus(string localFileName)
1261 d7288179 pkanavos
		{
1262 d7288179 pkanavos
			if (String.IsNullOrWhiteSpace(localFileName))
1263 d7288179 pkanavos
				throw new ArgumentNullException("localFileName");
1264 d7288179 pkanavos
			Contract.EndContractBlock();
1265 d7288179 pkanavos
			
1266 d7288179 pkanavos
			var statusKeeper = IoC.Get<IStatusKeeper>();
1267 d7288179 pkanavos
			var status=statusKeeper.GetFileStatus(localFileName);
1268 d7288179 pkanavos
			return status;
1269 d7288179 pkanavos
		}
1270 d7288179 pkanavos
1271 d7288179 pkanavos
	    public void RemoveAccountFromDatabase(AccountSettings account)
1272 d7288179 pkanavos
	    {
1273 d7288179 pkanavos
            var statusKeeper = IoC.Get<IStatusKeeper>();
1274 d7288179 pkanavos
            statusKeeper.ClearFolderStatus(account.RootPath);	        
1275 d7288179 pkanavos
	    }
1276 d7288179 pkanavos
	}
1277 d7288179 pkanavos
}