Statistics
| Branch: | Revision:

root / trunk / Pithos.Client.WPF / Shell / ShellViewModel.cs @ 7f5882da

History | View | Annotate | Download (26.4 kB)

1 255f5f86 Panagiotis Kanavos
#region
2 255f5f86 Panagiotis Kanavos
/* -----------------------------------------------------------------------
3 255f5f86 Panagiotis Kanavos
 * <copyright file="ShellViewModel.cs" company="GRNet">
4 255f5f86 Panagiotis Kanavos
 * 
5 255f5f86 Panagiotis Kanavos
 * Copyright 2011-2012 GRNET S.A. All rights reserved.
6 255f5f86 Panagiotis Kanavos
 *
7 255f5f86 Panagiotis Kanavos
 * Redistribution and use in source and binary forms, with or
8 255f5f86 Panagiotis Kanavos
 * without modification, are permitted provided that the following
9 255f5f86 Panagiotis Kanavos
 * conditions are met:
10 255f5f86 Panagiotis Kanavos
 *
11 255f5f86 Panagiotis Kanavos
 *   1. Redistributions of source code must retain the above
12 255f5f86 Panagiotis Kanavos
 *      copyright notice, this list of conditions and the following
13 255f5f86 Panagiotis Kanavos
 *      disclaimer.
14 255f5f86 Panagiotis Kanavos
 *
15 255f5f86 Panagiotis Kanavos
 *   2. Redistributions in binary form must reproduce the above
16 255f5f86 Panagiotis Kanavos
 *      copyright notice, this list of conditions and the following
17 255f5f86 Panagiotis Kanavos
 *      disclaimer in the documentation and/or other materials
18 255f5f86 Panagiotis Kanavos
 *      provided with the distribution.
19 255f5f86 Panagiotis Kanavos
 *
20 255f5f86 Panagiotis Kanavos
 *
21 255f5f86 Panagiotis Kanavos
 * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
22 255f5f86 Panagiotis Kanavos
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 255f5f86 Panagiotis Kanavos
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 255f5f86 Panagiotis Kanavos
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
25 255f5f86 Panagiotis Kanavos
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 255f5f86 Panagiotis Kanavos
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 255f5f86 Panagiotis Kanavos
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28 255f5f86 Panagiotis Kanavos
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 255f5f86 Panagiotis Kanavos
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 255f5f86 Panagiotis Kanavos
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 255f5f86 Panagiotis Kanavos
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 255f5f86 Panagiotis Kanavos
 * POSSIBILITY OF SUCH DAMAGE.
33 255f5f86 Panagiotis Kanavos
 *
34 255f5f86 Panagiotis Kanavos
 * The views and conclusions contained in the software and
35 255f5f86 Panagiotis Kanavos
 * documentation are those of the authors and should not be
36 255f5f86 Panagiotis Kanavos
 * interpreted as representing official policies, either expressed
37 255f5f86 Panagiotis Kanavos
 * or implied, of GRNET S.A.
38 255f5f86 Panagiotis Kanavos
 * </copyright>
39 255f5f86 Panagiotis Kanavos
 * -----------------------------------------------------------------------
40 255f5f86 Panagiotis Kanavos
 */
41 255f5f86 Panagiotis Kanavos
#endregion
42 255f5f86 Panagiotis Kanavos
using System.Collections.Concurrent;
43 c53aa229 Panagiotis Kanavos
using System.Diagnostics;
44 c28a075a Panagiotis Kanavos
using System.Diagnostics.Contracts;
45 c53aa229 Panagiotis Kanavos
using System.IO;
46 c28a075a Panagiotis Kanavos
using System.Net;
47 d17258c2 Panagiotis Kanavos
using System.Reflection;
48 c53aa229 Panagiotis Kanavos
using System.Runtime.InteropServices;
49 c53aa229 Panagiotis Kanavos
using System.ServiceModel;
50 c53aa229 Panagiotis Kanavos
using System.Threading.Tasks;
51 c53aa229 Panagiotis Kanavos
using System.Windows;
52 fb9d6e00 Panagiotis Kanavos
using System.Windows.Controls.Primitives;
53 9bae55d1 Panagiotis Kanavos
using Caliburn.Micro;
54 c53aa229 Panagiotis Kanavos
using Hardcodet.Wpf.TaskbarNotification;
55 c53aa229 Panagiotis Kanavos
using Pithos.Client.WPF.Configuration;
56 42800be8 Panagiotis Kanavos
using Pithos.Client.WPF.FileProperties;
57 65282d58 Panagiotis Kanavos
using Pithos.Client.WPF.Preferences;
58 d3a13891 Panagiotis Kanavos
using Pithos.Client.WPF.SelectiveSynch;
59 42800be8 Panagiotis Kanavos
using Pithos.Client.WPF.Services;
60 5cb9d74f Panagiotis Kanavos
using Pithos.Client.WPF.Shell;
61 c53aa229 Panagiotis Kanavos
using Pithos.Core;
62 29a6b387 Panagiotis Kanavos
using Pithos.Core.Agents;
63 c53aa229 Panagiotis Kanavos
using Pithos.Interfaces;
64 c53aa229 Panagiotis Kanavos
using System;
65 c53aa229 Panagiotis Kanavos
using System.Collections.Generic;
66 c53aa229 Panagiotis Kanavos
using System.Linq;
67 0bd56b7c Panagiotis Kanavos
using Pithos.Network;
68 c53aa229 Panagiotis Kanavos
using StatusService = Pithos.Client.WPF.Services.StatusService;
69 9bae55d1 Panagiotis Kanavos
70 9bae55d1 Panagiotis Kanavos
namespace Pithos.Client.WPF {
71 4ec636f6 Panagiotis Kanavos
	using System.ComponentModel.Composition;
72 9bae55d1 Panagiotis Kanavos
73 4ec636f6 Panagiotis Kanavos
	
74 cf761c0d Panagiotis Kanavos
	///<summary>
75 cf761c0d Panagiotis Kanavos
	/// The "shell" of the Pithos application displays the taskbar  icon, menu and notifications.
76 cf761c0d Panagiotis Kanavos
	/// The shell also hosts the status service called by shell extensions to retrieve file info
77 cf761c0d Panagiotis Kanavos
	///</summary>
78 cf761c0d Panagiotis Kanavos
	///<remarks>
79 cf761c0d Panagiotis Kanavos
	/// It is a strange "shell" as its main visible element is an icon instead of a window
80 cf761c0d Panagiotis Kanavos
	/// The shell subscribes to the following events:
81 cf761c0d Panagiotis Kanavos
	/// * Notification:  Raised by components that want to notify the user. Usually displayed in a balloon
82 cf761c0d Panagiotis Kanavos
	/// * 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
83 cf761c0d Panagiotis Kanavos
	/// * ShowFilePropertiesEvent: Raised when a shell command requests the display of the file/container properties dialog
84 cf761c0d Panagiotis Kanavos
	///</remarks>		
85 cf761c0d Panagiotis Kanavos
	//TODO: CODE SMELL Why does the shell handle the SelectiveSynchChanges?
86 4ec636f6 Panagiotis Kanavos
	[Export(typeof(IShell))]
87 4ec636f6 Panagiotis Kanavos
	public class ShellViewModel : Screen, IStatusNotification, IShell,
88 4ec636f6 Panagiotis Kanavos
		IHandle<Notification>, IHandle<SelectiveSynchChanges>, IHandle<ShowFilePropertiesEvent>
89 4ec636f6 Panagiotis Kanavos
	{
90 cf761c0d Panagiotis Kanavos
		//The Status Checker provides the current synch state
91 cf761c0d Panagiotis Kanavos
		//TODO: Could we remove the status checker and use events in its place?
92 4f6d51d4 Panagiotis Kanavos
		private readonly IStatusChecker _statusChecker;
93 4f6d51d4 Panagiotis Kanavos
		private readonly IEventAggregator _events;
94 c53aa229 Panagiotis Kanavos
95 4ec636f6 Panagiotis Kanavos
		public PithosSettings Settings { get; private set; }
96 c53aa229 Panagiotis Kanavos
97 4ec636f6 Panagiotis Kanavos
98 255f5f86 Panagiotis Kanavos
		private readonly ConcurrentDictionary<string, PithosMonitor> _monitors = new ConcurrentDictionary<string, PithosMonitor>();
99 cf761c0d Panagiotis Kanavos
		///<summary>
100 cf761c0d Panagiotis Kanavos
		/// Dictionary of account monitors, keyed by account
101 cf761c0d Panagiotis Kanavos
		///</summary>
102 cf761c0d Panagiotis Kanavos
		///<remarks>
103 cf761c0d Panagiotis Kanavos
		/// One monitor class is created for each account. The Shell needs access to the monitors to execute start/stop/pause commands,
104 cf761c0d Panagiotis Kanavos
		/// retrieve account and boject info		
105 cf761c0d Panagiotis Kanavos
		///</remarks>
106 cf761c0d Panagiotis Kanavos
		// TODO: Does the Shell REALLY need access to the monitors? Could we achieve the same results with a better design?
107 cf761c0d Panagiotis Kanavos
		// TODO: The monitors should be internal to Pithos.Core, even though exposing them makes coding of the Object and Container windows easier
108 255f5f86 Panagiotis Kanavos
		public ConcurrentDictionary<string, PithosMonitor> Monitors
109 4ec636f6 Panagiotis Kanavos
		{
110 4ec636f6 Panagiotis Kanavos
			get { return _monitors; }
111 4ec636f6 Panagiotis Kanavos
		}
112 c53aa229 Panagiotis Kanavos
113 cf761c0d Panagiotis Kanavos
114 255f5f86 Panagiotis Kanavos
		///<summary>
115 255f5f86 Panagiotis Kanavos
		/// The status service is used by Shell extensions to retrieve file status information
116 255f5f86 Panagiotis Kanavos
		///</summary>
117 255f5f86 Panagiotis Kanavos
		//TODO: CODE SMELL! This is the shell! While hosting in the shell makes executing start/stop commands easier, it is still a smell
118 255f5f86 Panagiotis Kanavos
		private ServiceHost _statusService;
119 c53aa229 Panagiotis Kanavos
120 cf761c0d Panagiotis Kanavos
		//Logging in the Pithos client is provided by log4net
121 4ec636f6 Panagiotis Kanavos
		private static readonly log4net.ILog Log = log4net.LogManager.GetLogger("Pithos");
122 c53aa229 Panagiotis Kanavos
123 255f5f86 Panagiotis Kanavos
		//Lazily initialized File Version info. This is done once and lazily to avoid blocking the UI
124 7f5882da Panagiotis Kanavos
		private readonly Lazy<FileVersionInfo> _fileVersion;
125 422c9598 Panagiotis Kanavos
126 7f5882da Panagiotis Kanavos
	    private readonly PollAgent _pollAgent;
127 31c97141 Panagiotis Kanavos
128 cf761c0d Panagiotis Kanavos
		///<summary>
129 cf761c0d Panagiotis Kanavos
		/// The Shell depends on MEF to provide implementations for windowManager, events, the status checker service and the settings
130 cf761c0d Panagiotis Kanavos
		///</summary>
131 cf761c0d Panagiotis Kanavos
		///<remarks>
132 cf761c0d Panagiotis Kanavos
		/// The PithosSettings class encapsulates the app's settings to abstract their storage mechanism (App settings, a database or registry)
133 cf761c0d Panagiotis Kanavos
		///</remarks>
134 4ec636f6 Panagiotis Kanavos
		[ImportingConstructor]		
135 31c97141 Panagiotis Kanavos
		public ShellViewModel(IWindowManager windowManager, IEventAggregator events, IStatusChecker statusChecker, PithosSettings settings,PollAgent pollAgent)
136 4ec636f6 Panagiotis Kanavos
		{
137 4ec636f6 Panagiotis Kanavos
			try
138 4ec636f6 Panagiotis Kanavos
			{
139 d3a13891 Panagiotis Kanavos
140 4ec636f6 Panagiotis Kanavos
				_windowManager = windowManager;
141 cf761c0d Panagiotis Kanavos
				//CHECK: Caliburn doesn't need explicit command construction
142 4ec636f6 Panagiotis Kanavos
				//OpenPithosFolderCommand = new PithosCommand(OpenPithosFolder);
143 4ec636f6 Panagiotis Kanavos
				_statusChecker = statusChecker;
144 cf761c0d Panagiotis Kanavos
				//The event subst
145 4ec636f6 Panagiotis Kanavos
				_events = events;
146 4ec636f6 Panagiotis Kanavos
				_events.Subscribe(this);
147 c53aa229 Panagiotis Kanavos
148 31c97141 Panagiotis Kanavos
			    _pollAgent = pollAgent;
149 4ec636f6 Panagiotis Kanavos
				Settings = settings;
150 c53aa229 Panagiotis Kanavos
151 255f5f86 Panagiotis Kanavos
				Proxy.SetFromSettings(settings);
152 34bdb91d Panagiotis Kanavos
153 4ec636f6 Panagiotis Kanavos
				StatusMessage = "In Synch";
154 7e26c075 Panagiotis Kanavos
155 255f5f86 Panagiotis Kanavos
				_fileVersion=  new Lazy<FileVersionInfo>(() =>
156 255f5f86 Panagiotis Kanavos
				{
157 255f5f86 Panagiotis Kanavos
					Assembly assembly = Assembly.GetExecutingAssembly();
158 255f5f86 Panagiotis Kanavos
					var fileVersion = FileVersionInfo.GetVersionInfo(assembly.Location);
159 255f5f86 Panagiotis Kanavos
					return fileVersion;
160 255f5f86 Panagiotis Kanavos
				});
161 4ec636f6 Panagiotis Kanavos
				_accounts.CollectionChanged += (sender, e) =>
162 4ec636f6 Panagiotis Kanavos
												   {
163 4ec636f6 Panagiotis Kanavos
													   NotifyOfPropertyChange(() => OpenFolderCaption);
164 4ec636f6 Panagiotis Kanavos
													   NotifyOfPropertyChange(() => HasAccounts);
165 4ec636f6 Panagiotis Kanavos
												   };
166 6aa29f4f Panagiotis Kanavos
167 4ec636f6 Panagiotis Kanavos
			}
168 4ec636f6 Panagiotis Kanavos
			catch (Exception exc)
169 4ec636f6 Panagiotis Kanavos
			{
170 4ec636f6 Panagiotis Kanavos
				Log.Error("Error while starting the ShellViewModel",exc);
171 4ec636f6 Panagiotis Kanavos
				throw;
172 4ec636f6 Panagiotis Kanavos
			}
173 4ec636f6 Panagiotis Kanavos
		}
174 c53aa229 Panagiotis Kanavos
175 6aa29f4f Panagiotis Kanavos
176 4ec636f6 Panagiotis Kanavos
		protected override void OnActivate()
177 4ec636f6 Panagiotis Kanavos
		{
178 4ec636f6 Panagiotis Kanavos
			base.OnActivate();
179 42800be8 Panagiotis Kanavos
180 255f5f86 Panagiotis Kanavos
			
181 34bdb91d Panagiotis Kanavos
182 4ec636f6 Panagiotis Kanavos
			StartMonitoring();                    
183 4ec636f6 Panagiotis Kanavos
		}
184 7b0a5fec Panagiotis Kanavos
185 42800be8 Panagiotis Kanavos
186 34bdb91d Panagiotis Kanavos
187 4f6d51d4 Panagiotis Kanavos
		private async void StartMonitoring()
188 4ec636f6 Panagiotis Kanavos
		{
189 4ec636f6 Panagiotis Kanavos
			try
190 4ec636f6 Panagiotis Kanavos
			{
191 4ec636f6 Panagiotis Kanavos
				var accounts = Settings.Accounts.Select(MonitorAccount);
192 4ec636f6 Panagiotis Kanavos
				await TaskEx.WhenAll(accounts);
193 4ec636f6 Panagiotis Kanavos
				_statusService = StatusService.Start();
194 692ec33b Panagiotis Kanavos
195 692ec33b Panagiotis Kanavos
/*
196 4ec636f6 Panagiotis Kanavos
				foreach (var account in Settings.Accounts)
197 4ec636f6 Panagiotis Kanavos
				{
198 4ec636f6 Panagiotis Kanavos
					await MonitorAccount(account);
199 4ec636f6 Panagiotis Kanavos
				}
200 692ec33b Panagiotis Kanavos
*/
201 4ec636f6 Panagiotis Kanavos
				
202 4ec636f6 Panagiotis Kanavos
			}
203 4ec636f6 Panagiotis Kanavos
			catch (AggregateException exc)
204 4ec636f6 Panagiotis Kanavos
			{
205 4ec636f6 Panagiotis Kanavos
				exc.Handle(e =>
206 4ec636f6 Panagiotis Kanavos
				{
207 4ec636f6 Panagiotis Kanavos
					Log.Error("Error while starting monitoring", e);
208 4ec636f6 Panagiotis Kanavos
					return true;
209 4ec636f6 Panagiotis Kanavos
				});
210 4ec636f6 Panagiotis Kanavos
				throw;
211 4ec636f6 Panagiotis Kanavos
			}
212 4ec636f6 Panagiotis Kanavos
		}
213 4ec636f6 Panagiotis Kanavos
214 4ec636f6 Panagiotis Kanavos
		protected override void OnDeactivate(bool close)
215 4ec636f6 Panagiotis Kanavos
		{
216 4ec636f6 Panagiotis Kanavos
			base.OnDeactivate(close);
217 4ec636f6 Panagiotis Kanavos
			if (close)
218 4ec636f6 Panagiotis Kanavos
			{
219 4ec636f6 Panagiotis Kanavos
				StatusService.Stop(_statusService);
220 4ec636f6 Panagiotis Kanavos
				_statusService = null;
221 4ec636f6 Panagiotis Kanavos
			}
222 4ec636f6 Panagiotis Kanavos
		}
223 4ec636f6 Panagiotis Kanavos
224 4ec636f6 Panagiotis Kanavos
		public Task MonitorAccount(AccountSettings account)
225 4ec636f6 Panagiotis Kanavos
		{
226 4ec636f6 Panagiotis Kanavos
			return Task.Factory.StartNew(() =>
227 4ec636f6 Panagiotis Kanavos
			{                                                
228 4f6d51d4 Panagiotis Kanavos
				PithosMonitor monitor;
229 4ec636f6 Panagiotis Kanavos
				var accountName = account.AccountName;
230 4ec636f6 Panagiotis Kanavos
231 4ec636f6 Panagiotis Kanavos
				if (_monitors.TryGetValue(accountName, out monitor))
232 4ec636f6 Panagiotis Kanavos
				{
233 4ec636f6 Panagiotis Kanavos
					//If the account is active
234 c636df1f Panagiotis Kanavos
                    if (account.IsActive)
235 c636df1f Panagiotis Kanavos
                    {
236 c636df1f Panagiotis Kanavos
                        //The Api Key may have changed throuth the Preferences dialog
237 c636df1f Panagiotis Kanavos
                        monitor.ApiKey = account.ApiKey;
238 c636df1f Panagiotis Kanavos
						Debug.Assert(monitor.StatusNotification == this,"An existing monitor should already have a StatusNotification service object");
239 c636df1f Panagiotis Kanavos
                        monitor.RootPath = account.RootPath;
240 c636df1f Panagiotis Kanavos
                        //Start the monitor. It's OK to start an already started monitor,
241 c636df1f Panagiotis Kanavos
                        //it will just ignore the call                        
242 c636df1f Panagiotis Kanavos
                        StartMonitor(monitor).Wait();
243 c636df1f Panagiotis Kanavos
                    }
244 c636df1f Panagiotis Kanavos
                    else
245 c636df1f Panagiotis Kanavos
                    {
246 c636df1f Panagiotis Kanavos
                        //If the account is inactive
247 c636df1f Panagiotis Kanavos
                        //Stop and remove the monitor
248 c636df1f Panagiotis Kanavos
                        RemoveMonitor(accountName);
249 c636df1f Panagiotis Kanavos
                    }
250 4ec636f6 Panagiotis Kanavos
					return;
251 4ec636f6 Panagiotis Kanavos
				}
252 4ec636f6 Panagiotis Kanavos
253 255f5f86 Panagiotis Kanavos
				
254 4ec636f6 Panagiotis Kanavos
				//Create a new monitor/ Can't use MEF here, it would return a single instance for all monitors
255 4ec636f6 Panagiotis Kanavos
				monitor = new PithosMonitor
256 4ec636f6 Panagiotis Kanavos
							  {
257 4ec636f6 Panagiotis Kanavos
								  UserName = accountName,
258 4ec636f6 Panagiotis Kanavos
								  ApiKey = account.ApiKey,                                  
259 4ec636f6 Panagiotis Kanavos
								  StatusNotification = this,
260 4ec636f6 Panagiotis Kanavos
								  RootPath = account.RootPath
261 4ec636f6 Panagiotis Kanavos
							  };
262 4ec636f6 Panagiotis Kanavos
				//PithosMonitor uses MEF so we need to resolve it
263 4ec636f6 Panagiotis Kanavos
				IoC.BuildUp(monitor);
264 4ec636f6 Panagiotis Kanavos
265 255f5f86 Panagiotis Kanavos
				monitor.AuthenticationUrl = account.ServerUrl;
266 4ec636f6 Panagiotis Kanavos
267 4ec636f6 Panagiotis Kanavos
				_monitors[accountName] = monitor;
268 4ec636f6 Panagiotis Kanavos
269 4ec636f6 Panagiotis Kanavos
				if (account.IsActive)
270 4ec636f6 Panagiotis Kanavos
				{
271 4ec636f6 Panagiotis Kanavos
					//Don't start a monitor if it doesn't have an account and ApiKey
272 4ec636f6 Panagiotis Kanavos
					if (String.IsNullOrWhiteSpace(monitor.UserName) ||
273 4ec636f6 Panagiotis Kanavos
						String.IsNullOrWhiteSpace(monitor.ApiKey))
274 4ec636f6 Panagiotis Kanavos
						return;
275 4ec636f6 Panagiotis Kanavos
					StartMonitor(monitor);
276 4ec636f6 Panagiotis Kanavos
				}
277 4ec636f6 Panagiotis Kanavos
			});
278 4ec636f6 Panagiotis Kanavos
		}
279 4ec636f6 Panagiotis Kanavos
280 4ec636f6 Panagiotis Kanavos
281 4ec636f6 Panagiotis Kanavos
		protected override void OnViewLoaded(object view)
282 4ec636f6 Panagiotis Kanavos
		{
283 4ec636f6 Panagiotis Kanavos
			UpdateStatus();
284 4ec636f6 Panagiotis Kanavos
			var window = (Window)view;            
285 4ec636f6 Panagiotis Kanavos
			TaskEx.Delay(1000).ContinueWith(t => Execute.OnUIThread(window.Hide));
286 4ec636f6 Panagiotis Kanavos
			base.OnViewLoaded(view);
287 4ec636f6 Panagiotis Kanavos
		}
288 4ec636f6 Panagiotis Kanavos
289 4ec636f6 Panagiotis Kanavos
290 4ec636f6 Panagiotis Kanavos
		#region Status Properties
291 4ec636f6 Panagiotis Kanavos
292 4ec636f6 Panagiotis Kanavos
		private string _statusMessage;
293 4ec636f6 Panagiotis Kanavos
		public string StatusMessage
294 4ec636f6 Panagiotis Kanavos
		{
295 4ec636f6 Panagiotis Kanavos
			get { return _statusMessage; }
296 4ec636f6 Panagiotis Kanavos
			set
297 4ec636f6 Panagiotis Kanavos
			{
298 4ec636f6 Panagiotis Kanavos
				_statusMessage = value;
299 4ec636f6 Panagiotis Kanavos
				NotifyOfPropertyChange(() => StatusMessage);
300 4ec636f6 Panagiotis Kanavos
			}
301 4ec636f6 Panagiotis Kanavos
		}
302 4ec636f6 Panagiotis Kanavos
303 4ec636f6 Panagiotis Kanavos
		private readonly ObservableConcurrentCollection<AccountInfo> _accounts = new ObservableConcurrentCollection<AccountInfo>();
304 4ec636f6 Panagiotis Kanavos
		public ObservableConcurrentCollection<AccountInfo> Accounts
305 4ec636f6 Panagiotis Kanavos
		{
306 4ec636f6 Panagiotis Kanavos
			get { return _accounts; }
307 4ec636f6 Panagiotis Kanavos
		}
308 4ec636f6 Panagiotis Kanavos
309 4ec636f6 Panagiotis Kanavos
		public bool HasAccounts
310 4ec636f6 Panagiotis Kanavos
		{
311 4ec636f6 Panagiotis Kanavos
			get { return _accounts.Count > 0; }
312 4ec636f6 Panagiotis Kanavos
		}
313 4ec636f6 Panagiotis Kanavos
314 4ec636f6 Panagiotis Kanavos
315 4ec636f6 Panagiotis Kanavos
		public string OpenFolderCaption
316 4ec636f6 Panagiotis Kanavos
		{
317 4ec636f6 Panagiotis Kanavos
			get
318 4ec636f6 Panagiotis Kanavos
			{
319 4ec636f6 Panagiotis Kanavos
				return (_accounts.Count == 0)
320 4ec636f6 Panagiotis Kanavos
						? "No Accounts Defined"
321 4ec636f6 Panagiotis Kanavos
						: "Open Pithos Folder";
322 4ec636f6 Panagiotis Kanavos
			}
323 4ec636f6 Panagiotis Kanavos
		}
324 4ec636f6 Panagiotis Kanavos
325 4ec636f6 Panagiotis Kanavos
		private string _pauseSyncCaption="Pause Synching";
326 4ec636f6 Panagiotis Kanavos
		public string PauseSyncCaption
327 4ec636f6 Panagiotis Kanavos
		{
328 4ec636f6 Panagiotis Kanavos
			get { return _pauseSyncCaption; }
329 4ec636f6 Panagiotis Kanavos
			set
330 4ec636f6 Panagiotis Kanavos
			{
331 4ec636f6 Panagiotis Kanavos
				_pauseSyncCaption = value;
332 4ec636f6 Panagiotis Kanavos
				NotifyOfPropertyChange(() => PauseSyncCaption);
333 4ec636f6 Panagiotis Kanavos
			}
334 4ec636f6 Panagiotis Kanavos
		}
335 4ec636f6 Panagiotis Kanavos
336 4ec636f6 Panagiotis Kanavos
		private readonly ObservableConcurrentCollection<FileEntry> _recentFiles = new ObservableConcurrentCollection<FileEntry>();
337 4ec636f6 Panagiotis Kanavos
		public ObservableConcurrentCollection<FileEntry> RecentFiles
338 4ec636f6 Panagiotis Kanavos
		{
339 4ec636f6 Panagiotis Kanavos
			get { return _recentFiles; }
340 4ec636f6 Panagiotis Kanavos
		}
341 4ec636f6 Panagiotis Kanavos
342 4ec636f6 Panagiotis Kanavos
343 4ec636f6 Panagiotis Kanavos
		private string _statusIcon="../Images/Pithos.ico";
344 4ec636f6 Panagiotis Kanavos
		public string StatusIcon
345 4ec636f6 Panagiotis Kanavos
		{
346 4ec636f6 Panagiotis Kanavos
			get { return _statusIcon; }
347 4ec636f6 Panagiotis Kanavos
			set
348 4ec636f6 Panagiotis Kanavos
			{
349 255f5f86 Panagiotis Kanavos
				//TODO: Ensure all status icons use the Pithos logo
350 4f6d51d4 Panagiotis Kanavos
				_statusIcon = value;
351 4ec636f6 Panagiotis Kanavos
				NotifyOfPropertyChange(() => StatusIcon);
352 4ec636f6 Panagiotis Kanavos
			}
353 4ec636f6 Panagiotis Kanavos
		}
354 4ec636f6 Panagiotis Kanavos
355 4ec636f6 Panagiotis Kanavos
		#endregion
356 4ec636f6 Panagiotis Kanavos
357 4ec636f6 Panagiotis Kanavos
		#region Commands
358 4ec636f6 Panagiotis Kanavos
359 f2d88248 Panagiotis Kanavos
        public void ShowPreferences()
360 f2d88248 Panagiotis Kanavos
        {
361 f2d88248 Panagiotis Kanavos
            ShowPreferences(null);
362 f2d88248 Panagiotis Kanavos
        }
363 f2d88248 Panagiotis Kanavos
364 f2d88248 Panagiotis Kanavos
		public void ShowPreferences(string currentTab)
365 4ec636f6 Panagiotis Kanavos
		{
366 1e26eceb Panagiotis Kanavos
			//Settings.Reload();
367 f2d88248 Panagiotis Kanavos
		    var preferences = new PreferencesViewModel(_windowManager, _events, this, Settings,currentTab);
368 f2d88248 Panagiotis Kanavos
		    _windowManager.ShowDialog(preferences);
369 4ec636f6 Panagiotis Kanavos
			
370 4ec636f6 Panagiotis Kanavos
		}
371 4ec636f6 Panagiotis Kanavos
372 4ec636f6 Panagiotis Kanavos
		public void AboutPithos()
373 4ec636f6 Panagiotis Kanavos
		{
374 4ec636f6 Panagiotis Kanavos
			var about = new AboutViewModel();
375 4ec636f6 Panagiotis Kanavos
			_windowManager.ShowWindow(about);
376 4ec636f6 Panagiotis Kanavos
		}
377 4ec636f6 Panagiotis Kanavos
378 4ec636f6 Panagiotis Kanavos
		public void SendFeedback()
379 4ec636f6 Panagiotis Kanavos
		{
380 4ec636f6 Panagiotis Kanavos
			var feedBack =  IoC.Get<FeedbackViewModel>();
381 4ec636f6 Panagiotis Kanavos
			_windowManager.ShowWindow(feedBack);
382 4ec636f6 Panagiotis Kanavos
		}
383 4ec636f6 Panagiotis Kanavos
384 4ec636f6 Panagiotis Kanavos
		//public PithosCommand OpenPithosFolderCommand { get; private set; }
385 4ec636f6 Panagiotis Kanavos
386 4ec636f6 Panagiotis Kanavos
		public void OpenPithosFolder()
387 4ec636f6 Panagiotis Kanavos
		{
388 4ec636f6 Panagiotis Kanavos
			var account = Settings.Accounts.FirstOrDefault(acc => acc.IsActive);
389 4ec636f6 Panagiotis Kanavos
			if (account == null)
390 4ec636f6 Panagiotis Kanavos
				return;
391 4ec636f6 Panagiotis Kanavos
			Process.Start(account.RootPath);
392 4ec636f6 Panagiotis Kanavos
		}
393 4ec636f6 Panagiotis Kanavos
394 4ec636f6 Panagiotis Kanavos
		public void OpenPithosFolder(AccountInfo account)
395 4ec636f6 Panagiotis Kanavos
		{
396 4ec636f6 Panagiotis Kanavos
			Process.Start(account.AccountPath);
397 4ec636f6 Panagiotis Kanavos
		}
398 4ec636f6 Panagiotis Kanavos
399 4ec636f6 Panagiotis Kanavos
		
400 f734ab5b Panagiotis Kanavos
/*
401 4ec636f6 Panagiotis Kanavos
		public void GoToSite()
402 4ec636f6 Panagiotis Kanavos
		{            
403 4ec636f6 Panagiotis Kanavos
			var site = Properties.Settings.Default.PithosSite;
404 4ec636f6 Panagiotis Kanavos
			Process.Start(site);            
405 4ec636f6 Panagiotis Kanavos
		}
406 f734ab5b Panagiotis Kanavos
*/
407 6aa29f4f Panagiotis Kanavos
408 4ec636f6 Panagiotis Kanavos
		public void GoToSite(AccountInfo account)
409 4ec636f6 Panagiotis Kanavos
		{
410 4ec636f6 Panagiotis Kanavos
			Process.Start(account.SiteUri);
411 4ec636f6 Panagiotis Kanavos
		}
412 4ec636f6 Panagiotis Kanavos
413 7f5882da Panagiotis Kanavos
        /// <summary>
414 7f5882da Panagiotis Kanavos
        /// Open an explorer window to the target path's directory
415 7f5882da Panagiotis Kanavos
        /// and select the file
416 7f5882da Panagiotis Kanavos
        /// </summary>
417 7f5882da Panagiotis Kanavos
        /// <param name="entry"></param>
418 7f5882da Panagiotis Kanavos
        public void GoToFile(FileEntry entry)
419 7f5882da Panagiotis Kanavos
        {
420 7f5882da Panagiotis Kanavos
            var fullPath = entry.FullPath;
421 7f5882da Panagiotis Kanavos
            if (!File.Exists(fullPath) && !Directory.Exists(fullPath))
422 7f5882da Panagiotis Kanavos
                return;
423 7f5882da Panagiotis Kanavos
            Process.Start("explorer.exe","/select, " + fullPath);
424 7f5882da Panagiotis Kanavos
        }
425 7f5882da Panagiotis Kanavos
426 4ec636f6 Panagiotis Kanavos
		public void ShowFileProperties()
427 4ec636f6 Panagiotis Kanavos
		{
428 4ec636f6 Panagiotis Kanavos
			var account = Settings.Accounts.First(acc => acc.IsActive);            
429 4ec636f6 Panagiotis Kanavos
			var dir = new DirectoryInfo(account.RootPath + @"\pithos");
430 4ec636f6 Panagiotis Kanavos
			var files=dir.GetFiles();
431 4ec636f6 Panagiotis Kanavos
			var r=new Random();
432 4ec636f6 Panagiotis Kanavos
			var idx=r.Next(0, files.Length);
433 4ec636f6 Panagiotis Kanavos
			ShowFileProperties(files[idx].FullName);            
434 4ec636f6 Panagiotis Kanavos
		}
435 4ec636f6 Panagiotis Kanavos
436 4ec636f6 Panagiotis Kanavos
		public void ShowFileProperties(string filePath)
437 4ec636f6 Panagiotis Kanavos
		{
438 4ec636f6 Panagiotis Kanavos
			if (String.IsNullOrWhiteSpace(filePath))
439 4ec636f6 Panagiotis Kanavos
				throw new ArgumentNullException("filePath");
440 4f6d51d4 Panagiotis Kanavos
			if (!File.Exists(filePath) && !Directory.Exists(filePath))
441 4ec636f6 Panagiotis Kanavos
				throw new ArgumentException(String.Format("Non existent file {0}",filePath),"filePath");
442 4ec636f6 Panagiotis Kanavos
			Contract.EndContractBlock();
443 4ec636f6 Panagiotis Kanavos
444 4ec636f6 Panagiotis Kanavos
			var pair=(from monitor in  Monitors
445 4ec636f6 Panagiotis Kanavos
							   where filePath.StartsWith(monitor.Value.RootPath, StringComparison.InvariantCultureIgnoreCase)
446 4ec636f6 Panagiotis Kanavos
								   select monitor).FirstOrDefault();
447 255f5f86 Panagiotis Kanavos
			var accountMonitor = pair.Value;
448 4ec636f6 Panagiotis Kanavos
449 4ec636f6 Panagiotis Kanavos
			if (accountMonitor == null)
450 4ec636f6 Panagiotis Kanavos
				return;
451 4ec636f6 Panagiotis Kanavos
452 4ec636f6 Panagiotis Kanavos
			var infoTask=Task.Factory.StartNew(()=>accountMonitor.GetObjectInfo(filePath));
453 4ec636f6 Panagiotis Kanavos
454 4ec636f6 Panagiotis Kanavos
			
455 4ec636f6 Panagiotis Kanavos
456 4ec636f6 Panagiotis Kanavos
			var fileProperties = new FilePropertiesViewModel(this, infoTask,filePath);
457 4ec636f6 Panagiotis Kanavos
			_windowManager.ShowWindow(fileProperties);
458 4ec636f6 Panagiotis Kanavos
		} 
459 4ec636f6 Panagiotis Kanavos
		
460 4ec636f6 Panagiotis Kanavos
		public void ShowContainerProperties()
461 4ec636f6 Panagiotis Kanavos
		{
462 4ec636f6 Panagiotis Kanavos
			var account = Settings.Accounts.First(acc => acc.IsActive);            
463 4ec636f6 Panagiotis Kanavos
			var dir = new DirectoryInfo(account.RootPath);
464 4ec636f6 Panagiotis Kanavos
			var fullName = (from folder in dir.EnumerateDirectories()
465 4ec636f6 Panagiotis Kanavos
							where (folder.Attributes & FileAttributes.Hidden) == 0
466 4ec636f6 Panagiotis Kanavos
							select folder.FullName).First();
467 4ec636f6 Panagiotis Kanavos
			ShowContainerProperties(fullName);            
468 4ec636f6 Panagiotis Kanavos
		}
469 4ec636f6 Panagiotis Kanavos
470 4ec636f6 Panagiotis Kanavos
		public void ShowContainerProperties(string filePath)
471 4ec636f6 Panagiotis Kanavos
		{
472 4ec636f6 Panagiotis Kanavos
			if (String.IsNullOrWhiteSpace(filePath))
473 4ec636f6 Panagiotis Kanavos
				throw new ArgumentNullException("filePath");
474 4ec636f6 Panagiotis Kanavos
			if (!Directory.Exists(filePath))
475 4ec636f6 Panagiotis Kanavos
				throw new ArgumentException(String.Format("Non existent file {0}",filePath),"filePath");
476 4ec636f6 Panagiotis Kanavos
			Contract.EndContractBlock();
477 4ec636f6 Panagiotis Kanavos
478 4ec636f6 Panagiotis Kanavos
			var pair=(from monitor in  Monitors
479 4ec636f6 Panagiotis Kanavos
							   where filePath.StartsWith(monitor.Value.RootPath, StringComparison.InvariantCultureIgnoreCase)
480 4ec636f6 Panagiotis Kanavos
								   select monitor).FirstOrDefault();
481 255f5f86 Panagiotis Kanavos
			var accountMonitor = pair.Value;            
482 4ec636f6 Panagiotis Kanavos
			var info = accountMonitor.GetContainerInfo(filePath);
483 4ec636f6 Panagiotis Kanavos
484 4ec636f6 Panagiotis Kanavos
			
485 4ec636f6 Panagiotis Kanavos
486 4ec636f6 Panagiotis Kanavos
			var containerProperties = new ContainerPropertiesViewModel(this, info,filePath);
487 4ec636f6 Panagiotis Kanavos
			_windowManager.ShowWindow(containerProperties);
488 4ec636f6 Panagiotis Kanavos
		}
489 4ec636f6 Panagiotis Kanavos
490 255f5f86 Panagiotis Kanavos
		public void SynchNow()
491 255f5f86 Panagiotis Kanavos
		{
492 31c97141 Panagiotis Kanavos
			_pollAgent.SynchNow();
493 255f5f86 Panagiotis Kanavos
		}
494 133f83c2 Panagiotis Kanavos
495 4ec636f6 Panagiotis Kanavos
		public ObjectInfo RefreshObjectInfo(ObjectInfo currentInfo)
496 4ec636f6 Panagiotis Kanavos
		{
497 4ec636f6 Panagiotis Kanavos
			if (currentInfo==null)
498 4ec636f6 Panagiotis Kanavos
				throw new ArgumentNullException("currentInfo");
499 4ec636f6 Panagiotis Kanavos
			Contract.EndContractBlock();
500 4ec636f6 Panagiotis Kanavos
501 4ec636f6 Panagiotis Kanavos
			var monitor = Monitors[currentInfo.Account];
502 4ec636f6 Panagiotis Kanavos
			var newInfo=monitor.CloudClient.GetObjectInfo(currentInfo.Account, currentInfo.Container, currentInfo.Name);
503 4ec636f6 Panagiotis Kanavos
			return newInfo;
504 4ec636f6 Panagiotis Kanavos
		}
505 4ec636f6 Panagiotis Kanavos
506 4ec636f6 Panagiotis Kanavos
		public ContainerInfo RefreshContainerInfo(ContainerInfo container)
507 4ec636f6 Panagiotis Kanavos
		{
508 4ec636f6 Panagiotis Kanavos
			if (container == null)
509 4ec636f6 Panagiotis Kanavos
				throw new ArgumentNullException("container");
510 4ec636f6 Panagiotis Kanavos
			Contract.EndContractBlock();
511 4ec636f6 Panagiotis Kanavos
512 4ec636f6 Panagiotis Kanavos
			var monitor = Monitors[container.Account];
513 4ec636f6 Panagiotis Kanavos
			var newInfo = monitor.CloudClient.GetContainerInfo(container.Account, container.Name);
514 4ec636f6 Panagiotis Kanavos
			return newInfo;
515 4ec636f6 Panagiotis Kanavos
		}
516 4ec636f6 Panagiotis Kanavos
517 4ec636f6 Panagiotis Kanavos
518 4ec636f6 Panagiotis Kanavos
		public void ToggleSynching()
519 4ec636f6 Panagiotis Kanavos
		{
520 4ec636f6 Panagiotis Kanavos
			bool isPaused=false;
521 4ec636f6 Panagiotis Kanavos
			foreach (var pair in Monitors)
522 4ec636f6 Panagiotis Kanavos
			{
523 4ec636f6 Panagiotis Kanavos
				var monitor = pair.Value;
524 4ec636f6 Panagiotis Kanavos
				monitor.Pause = !monitor.Pause;
525 4ec636f6 Panagiotis Kanavos
				isPaused = monitor.Pause;
526 4ec636f6 Panagiotis Kanavos
			}
527 4ec636f6 Panagiotis Kanavos
528 4ec636f6 Panagiotis Kanavos
			PauseSyncCaption = isPaused ? "Resume syncing" : "Pause syncing";
529 4ec636f6 Panagiotis Kanavos
			var iconKey = isPaused? "TraySyncPaused" : "TrayInSynch";
530 4ec636f6 Panagiotis Kanavos
			StatusIcon = String.Format(@"../Images/{0}.ico", iconKey);
531 4ec636f6 Panagiotis Kanavos
		}
532 4ec636f6 Panagiotis Kanavos
533 4ec636f6 Panagiotis Kanavos
		public void ExitPithos()
534 4ec636f6 Panagiotis Kanavos
		{
535 4ec636f6 Panagiotis Kanavos
			foreach (var pair in Monitors)
536 4ec636f6 Panagiotis Kanavos
			{
537 4ec636f6 Panagiotis Kanavos
				var monitor = pair.Value;
538 4ec636f6 Panagiotis Kanavos
				monitor.Stop();
539 4ec636f6 Panagiotis Kanavos
			}
540 4ec636f6 Panagiotis Kanavos
541 4ec636f6 Panagiotis Kanavos
			((Window)GetView()).Close();
542 4ec636f6 Panagiotis Kanavos
		}
543 4ec636f6 Panagiotis Kanavos
		#endregion
544 4ec636f6 Panagiotis Kanavos
545 4ec636f6 Panagiotis Kanavos
546 4f6d51d4 Panagiotis Kanavos
		private readonly Dictionary<PithosStatus, StatusInfo> _iconNames = new List<StatusInfo>
547 4ec636f6 Panagiotis Kanavos
			{
548 4ec636f6 Panagiotis Kanavos
				new StatusInfo(PithosStatus.InSynch, "All files up to date", "TrayInSynch"),
549 4ec636f6 Panagiotis Kanavos
				new StatusInfo(PithosStatus.Syncing, "Syncing Files", "TraySynching"),
550 4ec636f6 Panagiotis Kanavos
				new StatusInfo(PithosStatus.SyncPaused, "Sync Paused", "TraySyncPaused")
551 4ec636f6 Panagiotis Kanavos
			}.ToDictionary(s => s.Status);
552 4ec636f6 Panagiotis Kanavos
553 4ec636f6 Panagiotis Kanavos
		readonly IWindowManager _windowManager;
554 255f5f86 Panagiotis Kanavos
		
555 c53aa229 Panagiotis Kanavos
556 cf761c0d Panagiotis Kanavos
		///<summary>
557 cf761c0d Panagiotis Kanavos
		/// Updates the visual status indicators of the application depending on status changes, e.g. icon, stat		
558 cf761c0d Panagiotis Kanavos
		///</summary>
559 4ec636f6 Panagiotis Kanavos
		public void UpdateStatus()
560 4ec636f6 Panagiotis Kanavos
		{
561 4ec636f6 Panagiotis Kanavos
			var pithosStatus = _statusChecker.GetPithosStatus();
562 4ec636f6 Panagiotis Kanavos
563 4f6d51d4 Panagiotis Kanavos
			if (_iconNames.ContainsKey(pithosStatus))
564 4ec636f6 Panagiotis Kanavos
			{
565 4f6d51d4 Panagiotis Kanavos
				var info = _iconNames[pithosStatus];
566 4ec636f6 Panagiotis Kanavos
				StatusIcon = String.Format(@"../Images/{0}.ico", info.IconName);
567 4ec636f6 Panagiotis Kanavos
568 4ec636f6 Panagiotis Kanavos
569 4ec636f6 Panagiotis Kanavos
570 422c9598 Panagiotis Kanavos
				StatusMessage = String.Format("Pithos {0}\r\n{1}", _fileVersion.Value.FileVersion,info.StatusText);
571 4ec636f6 Panagiotis Kanavos
			}
572 4ec636f6 Panagiotis Kanavos
			
573 852d2cf2 Panagiotis Kanavos
			//_events.Publish(new Notification { Title = "Start", Message = "Start Monitoring", Level = TraceLevel.Info});
574 4ec636f6 Panagiotis Kanavos
		}
575 4ec636f6 Panagiotis Kanavos
576 4ec636f6 Panagiotis Kanavos
577 4ec636f6 Panagiotis Kanavos
	   
578 4ec636f6 Panagiotis Kanavos
		private Task StartMonitor(PithosMonitor monitor,int retries=0)
579 4ec636f6 Panagiotis Kanavos
		{
580 4ec636f6 Panagiotis Kanavos
			return Task.Factory.StartNew(() =>
581 4ec636f6 Panagiotis Kanavos
			{
582 4ec636f6 Panagiotis Kanavos
				using (log4net.ThreadContext.Stacks["Monitor"].Push("Start"))
583 4ec636f6 Panagiotis Kanavos
				{
584 4ec636f6 Panagiotis Kanavos
					try
585 4ec636f6 Panagiotis Kanavos
					{
586 4ec636f6 Panagiotis Kanavos
						Log.InfoFormat("Start Monitoring {0}", monitor.UserName);
587 4ec636f6 Panagiotis Kanavos
588 4ec636f6 Panagiotis Kanavos
						monitor.Start();
589 4ec636f6 Panagiotis Kanavos
					}
590 4ec636f6 Panagiotis Kanavos
					catch (WebException exc)
591 4ec636f6 Panagiotis Kanavos
					{
592 4ec636f6 Panagiotis Kanavos
						if (AbandonRetry(monitor, retries))
593 4ec636f6 Panagiotis Kanavos
							return;
594 4ec636f6 Panagiotis Kanavos
595 255f5f86 Panagiotis Kanavos
						HttpStatusCode statusCode =HttpStatusCode.OK;
596 255f5f86 Panagiotis Kanavos
						var response = exc.Response as HttpWebResponse;
597 255f5f86 Panagiotis Kanavos
						if(response!=null)
598 255f5f86 Panagiotis Kanavos
							statusCode = response.StatusCode;
599 255f5f86 Panagiotis Kanavos
600 255f5f86 Panagiotis Kanavos
						switch (statusCode)
601 255f5f86 Panagiotis Kanavos
						{
602 255f5f86 Panagiotis Kanavos
							case HttpStatusCode.Unauthorized:
603 255f5f86 Panagiotis Kanavos
								var message = String.Format("API Key Expired for {0}. Starting Renewal",
604 255f5f86 Panagiotis Kanavos
															monitor.UserName);
605 255f5f86 Panagiotis Kanavos
								Log.Error(message, exc);
606 1e26eceb Panagiotis Kanavos
						        var account = Settings.Accounts.Find(acc => acc.AccountName == monitor.UserName);                                
607 1e26eceb Panagiotis Kanavos
						        account.IsExpired = true;
608 1e26eceb Panagiotis Kanavos
                                Notify(new ExpirationNotification(account));
609 1e26eceb Panagiotis Kanavos
								//TryAuthorize(monitor.UserName, retries).Wait();
610 255f5f86 Panagiotis Kanavos
								break;
611 255f5f86 Panagiotis Kanavos
							case HttpStatusCode.ProxyAuthenticationRequired:
612 255f5f86 Panagiotis Kanavos
								TryAuthenticateProxy(monitor,retries);
613 255f5f86 Panagiotis Kanavos
								break;
614 255f5f86 Panagiotis Kanavos
							default:
615 255f5f86 Panagiotis Kanavos
								TryLater(monitor, exc, retries);
616 255f5f86 Panagiotis Kanavos
								break;
617 255f5f86 Panagiotis Kanavos
						}
618 4ec636f6 Panagiotis Kanavos
					}
619 4ec636f6 Panagiotis Kanavos
					catch (Exception exc)
620 4ec636f6 Panagiotis Kanavos
					{
621 4ec636f6 Panagiotis Kanavos
						if (AbandonRetry(monitor, retries)) 
622 4ec636f6 Panagiotis Kanavos
							return;
623 4ec636f6 Panagiotis Kanavos
624 4ec636f6 Panagiotis Kanavos
						TryLater(monitor,exc,retries);
625 4ec636f6 Panagiotis Kanavos
					}
626 4ec636f6 Panagiotis Kanavos
				}
627 4ec636f6 Panagiotis Kanavos
			});
628 4ec636f6 Panagiotis Kanavos
		}
629 4ec636f6 Panagiotis Kanavos
630 255f5f86 Panagiotis Kanavos
		private void TryAuthenticateProxy(PithosMonitor monitor,int retries)
631 255f5f86 Panagiotis Kanavos
		{
632 255f5f86 Panagiotis Kanavos
			Execute.OnUIThread(() =>
633 255f5f86 Panagiotis Kanavos
								   {                                       
634 255f5f86 Panagiotis Kanavos
									   var proxyAccount = IoC.Get<ProxyAccountViewModel>();
635 7f5882da Panagiotis Kanavos
										proxyAccount.Settings = Settings;
636 255f5f86 Panagiotis Kanavos
									   if (true != _windowManager.ShowDialog(proxyAccount)) 
637 255f5f86 Panagiotis Kanavos
										   return;
638 255f5f86 Panagiotis Kanavos
									   StartMonitor(monitor, retries);
639 255f5f86 Panagiotis Kanavos
									   NotifyOfPropertyChange(() => Accounts);
640 255f5f86 Panagiotis Kanavos
								   });
641 255f5f86 Panagiotis Kanavos
		}
642 65282d58 Panagiotis Kanavos
643 255f5f86 Panagiotis Kanavos
		private bool AbandonRetry(PithosMonitor monitor, int retries)
644 4ec636f6 Panagiotis Kanavos
		{
645 4ec636f6 Panagiotis Kanavos
			if (retries > 1)
646 4ec636f6 Panagiotis Kanavos
			{
647 4ec636f6 Panagiotis Kanavos
				var message = String.Format("Monitoring of account {0} has failed too many times. Will not retry",
648 4ec636f6 Panagiotis Kanavos
											monitor.UserName);
649 4ec636f6 Panagiotis Kanavos
				_events.Publish(new Notification
650 4ec636f6 Panagiotis Kanavos
									{Title = "Account monitoring failed", Message = message, Level = TraceLevel.Error});
651 4ec636f6 Panagiotis Kanavos
				return true;
652 4ec636f6 Panagiotis Kanavos
			}
653 4ec636f6 Panagiotis Kanavos
			return false;
654 4ec636f6 Panagiotis Kanavos
		}
655 4ec636f6 Panagiotis Kanavos
656 4ec636f6 Panagiotis Kanavos
657 7f5882da Panagiotis Kanavos
	    private void TryLater(PithosMonitor monitor, Exception exc,int retries)
658 4ec636f6 Panagiotis Kanavos
		{
659 4ec636f6 Panagiotis Kanavos
			var message = String.Format("An exception occured. Can't start monitoring\nWill retry in 10 seconds");
660 4ec636f6 Panagiotis Kanavos
			Task.Factory.StartNewDelayed(10000, () => StartMonitor(monitor,retries+1));
661 4ec636f6 Panagiotis Kanavos
			_events.Publish(new Notification
662 4ec636f6 Panagiotis Kanavos
								{Title = "Error", Message = message, Level = TraceLevel.Error});
663 4ec636f6 Panagiotis Kanavos
			Log.Error(message, exc);
664 4ec636f6 Panagiotis Kanavos
		}
665 4ec636f6 Panagiotis Kanavos
666 4ec636f6 Panagiotis Kanavos
667 4ec636f6 Panagiotis Kanavos
		public void NotifyChange(string status, TraceLevel level=TraceLevel.Info)
668 4ec636f6 Panagiotis Kanavos
		{
669 4f6d51d4 Panagiotis Kanavos
			StatusMessage = status;
670 4ec636f6 Panagiotis Kanavos
			
671 4ec636f6 Panagiotis Kanavos
			_events.Publish(new Notification { Title = "Pithos", Message = status, Level = level });
672 4ec636f6 Panagiotis Kanavos
		}
673 4ec636f6 Panagiotis Kanavos
674 4ec636f6 Panagiotis Kanavos
		public void NotifyChangedFile(string filePath)
675 4ec636f6 Panagiotis Kanavos
		{
676 7f5882da Panagiotis Kanavos
            if (RecentFiles.Any(e => e.FullPath == filePath))
677 7f5882da Panagiotis Kanavos
                return;
678 7f5882da Panagiotis Kanavos
            
679 4f6d51d4 Panagiotis Kanavos
			IProducerConsumerCollection<FileEntry> files=RecentFiles;
680 4ec636f6 Panagiotis Kanavos
			FileEntry popped;
681 4ec636f6 Panagiotis Kanavos
			while (files.Count > 5)
682 4ec636f6 Panagiotis Kanavos
				files.TryTake(out popped);
683 7f5882da Panagiotis Kanavos
            var entry = new FileEntry { FullPath = filePath };
684 4ec636f6 Panagiotis Kanavos
			files.TryAdd(entry);
685 4ec636f6 Panagiotis Kanavos
		}
686 4ec636f6 Panagiotis Kanavos
687 4ec636f6 Panagiotis Kanavos
		public void NotifyAccount(AccountInfo account)
688 4ec636f6 Panagiotis Kanavos
		{
689 4ec636f6 Panagiotis Kanavos
			if (account== null)
690 4ec636f6 Panagiotis Kanavos
				return;
691 4ec636f6 Panagiotis Kanavos
			//TODO: What happens to an existing account whose Token has changed?
692 4ec636f6 Panagiotis Kanavos
			account.SiteUri= String.Format("{0}/ui/?token={1}&user={2}",
693 eae84ae8 Panagiotis Kanavos
				account.SiteUri, Uri.EscapeDataString(account.Token),
694 255f5f86 Panagiotis Kanavos
				Uri.EscapeDataString(account.UserName));
695 4ec636f6 Panagiotis Kanavos
696 4ec636f6 Panagiotis Kanavos
			if (Accounts.All(item => item.UserName != account.UserName))
697 4ec636f6 Panagiotis Kanavos
				Accounts.TryAdd(account);
698 4ec636f6 Panagiotis Kanavos
699 4ec636f6 Panagiotis Kanavos
		}
700 4ec636f6 Panagiotis Kanavos
701 255f5f86 Panagiotis Kanavos
		public void NotifyConflicts(IEnumerable<FileSystemInfo> conflictFiles, string message)
702 255f5f86 Panagiotis Kanavos
		{
703 255f5f86 Panagiotis Kanavos
			if (conflictFiles == null)
704 255f5f86 Panagiotis Kanavos
				return;
705 7f5882da Panagiotis Kanavos
		    //Convert to list to avoid multiple iterations
706 7f5882da Panagiotis Kanavos
            var files = conflictFiles.ToList();
707 7f5882da Panagiotis Kanavos
			if (files.Count==0)
708 255f5f86 Panagiotis Kanavos
				return;
709 e5b65606 Panagiotis Kanavos
710 255f5f86 Panagiotis Kanavos
			UpdateStatus();
711 255f5f86 Panagiotis Kanavos
			//TODO: Create a more specific message. For now, just show a warning
712 7f5882da Panagiotis Kanavos
			NotifyForFiles(files,message,TraceLevel.Warning);
713 9c6d3193 Panagiotis Kanavos
714 255f5f86 Panagiotis Kanavos
		}
715 9c6d3193 Panagiotis Kanavos
716 255f5f86 Panagiotis Kanavos
		public void NotifyForFiles(IEnumerable<FileSystemInfo> files, string message,TraceLevel level=TraceLevel.Info)
717 255f5f86 Panagiotis Kanavos
		{
718 255f5f86 Panagiotis Kanavos
			if (files == null)
719 255f5f86 Panagiotis Kanavos
				return;
720 255f5f86 Panagiotis Kanavos
			if (!files.Any())
721 255f5f86 Panagiotis Kanavos
				return;
722 9c6d3193 Panagiotis Kanavos
723 255f5f86 Panagiotis Kanavos
			StatusMessage = message;
724 9c6d3193 Panagiotis Kanavos
725 255f5f86 Panagiotis Kanavos
			_events.Publish(new Notification { Title = "Pithos", Message = message, Level = level});
726 255f5f86 Panagiotis Kanavos
		}
727 9c6d3193 Panagiotis Kanavos
728 255f5f86 Panagiotis Kanavos
		public void Notify(Notification notification)
729 255f5f86 Panagiotis Kanavos
		{
730 255f5f86 Panagiotis Kanavos
			_events.Publish(notification);
731 255f5f86 Panagiotis Kanavos
		}
732 e5b65606 Panagiotis Kanavos
733 4ec636f6 Panagiotis Kanavos
734 255f5f86 Panagiotis Kanavos
		public void RemoveMonitor(string accountName)
735 4ec636f6 Panagiotis Kanavos
		{
736 4ec636f6 Panagiotis Kanavos
			if (String.IsNullOrWhiteSpace(accountName))
737 4ec636f6 Panagiotis Kanavos
				return;
738 4ec636f6 Panagiotis Kanavos
739 4ec636f6 Panagiotis Kanavos
			var accountInfo=_accounts.FirstOrDefault(account => account.UserName == accountName);
740 4ec636f6 Panagiotis Kanavos
			_accounts.TryRemove(accountInfo);
741 4ec636f6 Panagiotis Kanavos
742 ec1a1baf Panagiotis Kanavos
		    _pollAgent.RemoveAccount(accountInfo);
743 4ec636f6 Panagiotis Kanavos
			PithosMonitor monitor;
744 4ec636f6 Panagiotis Kanavos
			if (Monitors.TryRemove(accountName, out monitor))
745 4ec636f6 Panagiotis Kanavos
			{
746 4ec636f6 Panagiotis Kanavos
				monitor.Stop();
747 7f5882da Panagiotis Kanavos
                //TODO: Also remove any pending actions for this account
748 7f5882da Panagiotis Kanavos
                //from the network queue                
749 4ec636f6 Panagiotis Kanavos
			}
750 4ec636f6 Panagiotis Kanavos
		}
751 4ec636f6 Panagiotis Kanavos
752 4ec636f6 Panagiotis Kanavos
		public void RefreshOverlays()
753 4ec636f6 Panagiotis Kanavos
		{
754 4ec636f6 Panagiotis Kanavos
			foreach (var pair in Monitors)
755 4ec636f6 Panagiotis Kanavos
			{
756 4ec636f6 Panagiotis Kanavos
				var monitor = pair.Value;
757 4ec636f6 Panagiotis Kanavos
758 4ec636f6 Panagiotis Kanavos
				var path = monitor.RootPath;
759 4ec636f6 Panagiotis Kanavos
760 4ec636f6 Panagiotis Kanavos
				if (String.IsNullOrWhiteSpace(path))
761 4ec636f6 Panagiotis Kanavos
					continue;
762 4ec636f6 Panagiotis Kanavos
763 4ec636f6 Panagiotis Kanavos
				if (!Directory.Exists(path) && !File.Exists(path))
764 4ec636f6 Panagiotis Kanavos
					continue;
765 4ec636f6 Panagiotis Kanavos
766 4ec636f6 Panagiotis Kanavos
				IntPtr pathPointer = Marshal.StringToCoTaskMemAuto(path);
767 4ec636f6 Panagiotis Kanavos
768 4ec636f6 Panagiotis Kanavos
				try
769 4ec636f6 Panagiotis Kanavos
				{
770 4ec636f6 Panagiotis Kanavos
					NativeMethods.SHChangeNotify(HChangeNotifyEventID.SHCNE_UPDATEITEM,
771 4ec636f6 Panagiotis Kanavos
												 HChangeNotifyFlags.SHCNF_PATHW | HChangeNotifyFlags.SHCNF_FLUSHNOWAIT,
772 4ec636f6 Panagiotis Kanavos
												 pathPointer, IntPtr.Zero);
773 4ec636f6 Panagiotis Kanavos
				}
774 4ec636f6 Panagiotis Kanavos
				finally
775 4ec636f6 Panagiotis Kanavos
				{
776 4ec636f6 Panagiotis Kanavos
					Marshal.FreeHGlobal(pathPointer);
777 4ec636f6 Panagiotis Kanavos
				}
778 4ec636f6 Panagiotis Kanavos
			}
779 4ec636f6 Panagiotis Kanavos
		}
780 4ec636f6 Panagiotis Kanavos
781 4ec636f6 Panagiotis Kanavos
		#region Event Handlers
782 4ec636f6 Panagiotis Kanavos
		
783 4ec636f6 Panagiotis Kanavos
		public void Handle(SelectiveSynchChanges message)
784 4ec636f6 Panagiotis Kanavos
		{
785 4ec636f6 Panagiotis Kanavos
			var accountName = message.Account.AccountName;
786 4ec636f6 Panagiotis Kanavos
			PithosMonitor monitor;
787 4ec636f6 Panagiotis Kanavos
			if (_monitors.TryGetValue(accountName, out monitor))
788 4ec636f6 Panagiotis Kanavos
			{
789 759bd3c4 Panagiotis Kanavos
				monitor.SetSelectivePaths(message.Uris,message.Added,message.Removed);
790 4ec636f6 Panagiotis Kanavos
791 4ec636f6 Panagiotis Kanavos
			}
792 4ec636f6 Panagiotis Kanavos
			
793 4ec636f6 Panagiotis Kanavos
		}
794 4ec636f6 Panagiotis Kanavos
795 4ec636f6 Panagiotis Kanavos
796 7f5882da Panagiotis Kanavos
		private bool _pollStarted;
797 eae84ae8 Panagiotis Kanavos
798 255f5f86 Panagiotis Kanavos
		//SMELL: Doing so much work for notifications in the shell is wrong
799 255f5f86 Panagiotis Kanavos
		//The notifications should be moved to their own view/viewmodel pair
800 255f5f86 Panagiotis Kanavos
		//and different templates should be used for different message types
801 255f5f86 Panagiotis Kanavos
		//This will also allow the addition of extra functionality, eg. actions
802 255f5f86 Panagiotis Kanavos
		//
803 4ec636f6 Panagiotis Kanavos
		public void Handle(Notification notification)
804 4ec636f6 Panagiotis Kanavos
		{
805 255f5f86 Panagiotis Kanavos
			UpdateStatus();
806 e5b65606 Panagiotis Kanavos
807 4ec636f6 Panagiotis Kanavos
			if (!Settings.ShowDesktopNotifications)
808 4ec636f6 Panagiotis Kanavos
				return;
809 eae84ae8 Panagiotis Kanavos
810 255f5f86 Panagiotis Kanavos
			if (notification is PollNotification)
811 255f5f86 Panagiotis Kanavos
			{
812 255f5f86 Panagiotis Kanavos
				_pollStarted = true;
813 255f5f86 Panagiotis Kanavos
				return;
814 255f5f86 Panagiotis Kanavos
			}
815 255f5f86 Panagiotis Kanavos
			if (notification is CloudNotification)
816 255f5f86 Panagiotis Kanavos
			{
817 255f5f86 Panagiotis Kanavos
				if (!_pollStarted) 
818 255f5f86 Panagiotis Kanavos
					return;
819 255f5f86 Panagiotis Kanavos
				_pollStarted= false;
820 255f5f86 Panagiotis Kanavos
				notification.Title = "Pithos";
821 255f5f86 Panagiotis Kanavos
				notification.Message = "Start Synchronisation";
822 255f5f86 Panagiotis Kanavos
			}
823 255f5f86 Panagiotis Kanavos
824 255f5f86 Panagiotis Kanavos
			if (String.IsNullOrWhiteSpace(notification.Message) && String.IsNullOrWhiteSpace(notification.Title))
825 255f5f86 Panagiotis Kanavos
				return;
826 2dc6f765 Panagiotis Kanavos
827 4f6d51d4 Panagiotis Kanavos
			BalloonIcon icon;
828 4ec636f6 Panagiotis Kanavos
			switch (notification.Level)
829 4ec636f6 Panagiotis Kanavos
			{
830 4ec636f6 Panagiotis Kanavos
				case TraceLevel.Error:
831 4ec636f6 Panagiotis Kanavos
					icon = BalloonIcon.Error;
832 4ec636f6 Panagiotis Kanavos
					break;
833 4ec636f6 Panagiotis Kanavos
				case TraceLevel.Info:
834 4ec636f6 Panagiotis Kanavos
				case TraceLevel.Verbose:
835 4ec636f6 Panagiotis Kanavos
					icon = BalloonIcon.Info;
836 4ec636f6 Panagiotis Kanavos
					break;
837 4ec636f6 Panagiotis Kanavos
				case TraceLevel.Warning:
838 4ec636f6 Panagiotis Kanavos
					icon = BalloonIcon.Warning;
839 4ec636f6 Panagiotis Kanavos
					break;
840 4ec636f6 Panagiotis Kanavos
				default:
841 4ec636f6 Panagiotis Kanavos
					icon = BalloonIcon.None;
842 4ec636f6 Panagiotis Kanavos
					break;
843 4ec636f6 Panagiotis Kanavos
			}
844 255f5f86 Panagiotis Kanavos
			
845 4ec636f6 Panagiotis Kanavos
			if (Settings.ShowDesktopNotifications)
846 4ec636f6 Panagiotis Kanavos
			{
847 f2d88248 Panagiotis Kanavos
				var tv = (ShellView) GetView();
848 f2d88248 Panagiotis Kanavos
			    System.Action clickAction = null;
849 f2d88248 Panagiotis Kanavos
                if (notification is ExpirationNotification)
850 f2d88248 Panagiotis Kanavos
                {
851 f2d88248 Panagiotis Kanavos
                    clickAction = ()=>ShowPreferences("AccountTab");
852 f2d88248 Panagiotis Kanavos
                }
853 f2d88248 Panagiotis Kanavos
				var balloon=new PithosBalloon{Title=notification.Title,Message=notification.Message,Icon=icon,ClickAction=clickAction};
854 255f5f86 Panagiotis Kanavos
				tv.TaskbarView.ShowCustomBalloon(balloon,PopupAnimation.Fade,4000);
855 fb9d6e00 Panagiotis Kanavos
//				tv.TaskbarView.ShowBalloonTip(notification.Title, notification.Message, icon);
856 4ec636f6 Panagiotis Kanavos
			}
857 4ec636f6 Panagiotis Kanavos
		}
858 4ec636f6 Panagiotis Kanavos
		#endregion
859 4ec636f6 Panagiotis Kanavos
860 4ec636f6 Panagiotis Kanavos
		public void Handle(ShowFilePropertiesEvent message)
861 4ec636f6 Panagiotis Kanavos
		{
862 4ec636f6 Panagiotis Kanavos
			if (message == null)
863 4ec636f6 Panagiotis Kanavos
				throw new ArgumentNullException("message");
864 4ec636f6 Panagiotis Kanavos
			if (String.IsNullOrWhiteSpace(message.FileName) )
865 4ec636f6 Panagiotis Kanavos
				throw new ArgumentException("message");
866 4ec636f6 Panagiotis Kanavos
			Contract.EndContractBlock();
867 4ec636f6 Panagiotis Kanavos
868 4ec636f6 Panagiotis Kanavos
			var fileName = message.FileName;
869 255f5f86 Panagiotis Kanavos
			//TODO: Display file properties for non-container folders
870 4ec636f6 Panagiotis Kanavos
			if (File.Exists(fileName))
871 255f5f86 Panagiotis Kanavos
				//Retrieve the full name with exact casing. Pithos names are case sensitive				
872 255f5f86 Panagiotis Kanavos
				ShowFileProperties(FileInfoExtensions.GetProperFilePathCapitalization(fileName));
873 4ec636f6 Panagiotis Kanavos
			else if (Directory.Exists(fileName))
874 255f5f86 Panagiotis Kanavos
				//Retrieve the full name with exact casing. Pithos names are case sensitive
875 4f6d51d4 Panagiotis Kanavos
			{
876 255f5f86 Panagiotis Kanavos
				var path = FileInfoExtensions.GetProperDirectoryCapitalization(fileName);
877 255f5f86 Panagiotis Kanavos
				if (IsContainer(path))
878 255f5f86 Panagiotis Kanavos
					ShowContainerProperties(path);
879 255f5f86 Panagiotis Kanavos
				else
880 255f5f86 Panagiotis Kanavos
					ShowFileProperties(path);
881 4f6d51d4 Panagiotis Kanavos
			}
882 4ec636f6 Panagiotis Kanavos
		}
883 4f6d51d4 Panagiotis Kanavos
884 255f5f86 Panagiotis Kanavos
		private bool IsContainer(string path)
885 255f5f86 Panagiotis Kanavos
		{
886 255f5f86 Panagiotis Kanavos
			var matchingFolders = from account in _accounts
887 255f5f86 Panagiotis Kanavos
								  from rootFolder in Directory.GetDirectories(account.AccountPath)
888 255f5f86 Panagiotis Kanavos
								  where rootFolder.Equals(path, StringComparison.InvariantCultureIgnoreCase)
889 255f5f86 Panagiotis Kanavos
								  select rootFolder;
890 255f5f86 Panagiotis Kanavos
			return matchingFolders.Any();
891 255f5f86 Panagiotis Kanavos
		}
892 255f5f86 Panagiotis Kanavos
893 255f5f86 Panagiotis Kanavos
		public FileStatus GetFileStatus(string localFileName)
894 255f5f86 Panagiotis Kanavos
		{
895 255f5f86 Panagiotis Kanavos
			if (String.IsNullOrWhiteSpace(localFileName))
896 255f5f86 Panagiotis Kanavos
				throw new ArgumentNullException("localFileName");
897 255f5f86 Panagiotis Kanavos
			Contract.EndContractBlock();
898 255f5f86 Panagiotis Kanavos
			
899 255f5f86 Panagiotis Kanavos
			var statusKeeper = IoC.Get<IStatusKeeper>();
900 255f5f86 Panagiotis Kanavos
			var status=statusKeeper.GetFileStatus(localFileName);
901 255f5f86 Panagiotis Kanavos
			return status;
902 255f5f86 Panagiotis Kanavos
		}
903 4ec636f6 Panagiotis Kanavos
	}
904 9bae55d1 Panagiotis Kanavos
}