Statistics
| Branch: | Revision:

root / trunk / Pithos.Client.WPF / Shell / ShellViewModel.cs @ 62d5b25f

History | View | Annotate | Download (26.3 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 255f5f86 Panagiotis Kanavos
		private Lazy<FileVersionInfo> _fileVersion;
125 422c9598 Panagiotis Kanavos
126 cf761c0d Panagiotis Kanavos
		///<summary>
127 cf761c0d Panagiotis Kanavos
		/// The Shell depends on MEF to provide implementations for windowManager, events, the status checker service and the settings
128 cf761c0d Panagiotis Kanavos
		///</summary>
129 cf761c0d Panagiotis Kanavos
		///<remarks>
130 cf761c0d Panagiotis Kanavos
		/// The PithosSettings class encapsulates the app's settings to abstract their storage mechanism (App settings, a database or registry)
131 cf761c0d Panagiotis Kanavos
		///</remarks>
132 4ec636f6 Panagiotis Kanavos
		[ImportingConstructor]		
133 4ec636f6 Panagiotis Kanavos
		public ShellViewModel(IWindowManager windowManager, IEventAggregator events, IStatusChecker statusChecker, PithosSettings settings)
134 4ec636f6 Panagiotis Kanavos
		{
135 4ec636f6 Panagiotis Kanavos
			try
136 4ec636f6 Panagiotis Kanavos
			{
137 d3a13891 Panagiotis Kanavos
138 4ec636f6 Panagiotis Kanavos
				_windowManager = windowManager;
139 cf761c0d Panagiotis Kanavos
				//CHECK: Caliburn doesn't need explicit command construction
140 4ec636f6 Panagiotis Kanavos
				//OpenPithosFolderCommand = new PithosCommand(OpenPithosFolder);
141 4ec636f6 Panagiotis Kanavos
				_statusChecker = statusChecker;
142 cf761c0d Panagiotis Kanavos
				//The event subst
143 4ec636f6 Panagiotis Kanavos
				_events = events;
144 4ec636f6 Panagiotis Kanavos
				_events.Subscribe(this);
145 c53aa229 Panagiotis Kanavos
146 4ec636f6 Panagiotis Kanavos
				Settings = settings;
147 c53aa229 Panagiotis Kanavos
148 255f5f86 Panagiotis Kanavos
				Proxy.SetFromSettings(settings);
149 34bdb91d Panagiotis Kanavos
150 4ec636f6 Panagiotis Kanavos
				StatusMessage = "In Synch";
151 7e26c075 Panagiotis Kanavos
152 255f5f86 Panagiotis Kanavos
				_fileVersion=  new Lazy<FileVersionInfo>(() =>
153 255f5f86 Panagiotis Kanavos
				{
154 255f5f86 Panagiotis Kanavos
					Assembly assembly = Assembly.GetExecutingAssembly();
155 255f5f86 Panagiotis Kanavos
					var fileVersion = FileVersionInfo.GetVersionInfo(assembly.Location);
156 255f5f86 Panagiotis Kanavos
					return fileVersion;
157 255f5f86 Panagiotis Kanavos
				});
158 4ec636f6 Panagiotis Kanavos
				_accounts.CollectionChanged += (sender, e) =>
159 4ec636f6 Panagiotis Kanavos
												   {
160 4ec636f6 Panagiotis Kanavos
													   NotifyOfPropertyChange(() => OpenFolderCaption);
161 4ec636f6 Panagiotis Kanavos
													   NotifyOfPropertyChange(() => HasAccounts);
162 4ec636f6 Panagiotis Kanavos
												   };
163 6aa29f4f Panagiotis Kanavos
164 4ec636f6 Panagiotis Kanavos
			}
165 4ec636f6 Panagiotis Kanavos
			catch (Exception exc)
166 4ec636f6 Panagiotis Kanavos
			{
167 4ec636f6 Panagiotis Kanavos
				Log.Error("Error while starting the ShellViewModel",exc);
168 4ec636f6 Panagiotis Kanavos
				throw;
169 4ec636f6 Panagiotis Kanavos
			}
170 4ec636f6 Panagiotis Kanavos
		}
171 c53aa229 Panagiotis Kanavos
172 6aa29f4f Panagiotis Kanavos
173 4ec636f6 Panagiotis Kanavos
		protected override void OnActivate()
174 4ec636f6 Panagiotis Kanavos
		{
175 4ec636f6 Panagiotis Kanavos
			base.OnActivate();
176 42800be8 Panagiotis Kanavos
177 255f5f86 Panagiotis Kanavos
			
178 34bdb91d Panagiotis Kanavos
179 4ec636f6 Panagiotis Kanavos
			StartMonitoring();                    
180 4ec636f6 Panagiotis Kanavos
		}
181 7b0a5fec Panagiotis Kanavos
182 42800be8 Panagiotis Kanavos
183 34bdb91d Panagiotis Kanavos
184 4f6d51d4 Panagiotis Kanavos
		private async void StartMonitoring()
185 4ec636f6 Panagiotis Kanavos
		{
186 4ec636f6 Panagiotis Kanavos
			try
187 4ec636f6 Panagiotis Kanavos
			{
188 4ec636f6 Panagiotis Kanavos
				var accounts = Settings.Accounts.Select(MonitorAccount);
189 4ec636f6 Panagiotis Kanavos
				await TaskEx.WhenAll(accounts);
190 4ec636f6 Panagiotis Kanavos
				_statusService = StatusService.Start();
191 692ec33b Panagiotis Kanavos
192 692ec33b Panagiotis Kanavos
/*
193 4ec636f6 Panagiotis Kanavos
				foreach (var account in Settings.Accounts)
194 4ec636f6 Panagiotis Kanavos
				{
195 4ec636f6 Panagiotis Kanavos
					await MonitorAccount(account);
196 4ec636f6 Panagiotis Kanavos
				}
197 692ec33b Panagiotis Kanavos
*/
198 4ec636f6 Panagiotis Kanavos
				
199 4ec636f6 Panagiotis Kanavos
			}
200 4ec636f6 Panagiotis Kanavos
			catch (AggregateException exc)
201 4ec636f6 Panagiotis Kanavos
			{
202 4ec636f6 Panagiotis Kanavos
				exc.Handle(e =>
203 4ec636f6 Panagiotis Kanavos
				{
204 4ec636f6 Panagiotis Kanavos
					Log.Error("Error while starting monitoring", e);
205 4ec636f6 Panagiotis Kanavos
					return true;
206 4ec636f6 Panagiotis Kanavos
				});
207 4ec636f6 Panagiotis Kanavos
				throw;
208 4ec636f6 Panagiotis Kanavos
			}
209 4ec636f6 Panagiotis Kanavos
		}
210 4ec636f6 Panagiotis Kanavos
211 4ec636f6 Panagiotis Kanavos
		protected override void OnDeactivate(bool close)
212 4ec636f6 Panagiotis Kanavos
		{
213 4ec636f6 Panagiotis Kanavos
			base.OnDeactivate(close);
214 4ec636f6 Panagiotis Kanavos
			if (close)
215 4ec636f6 Panagiotis Kanavos
			{
216 4ec636f6 Panagiotis Kanavos
				StatusService.Stop(_statusService);
217 4ec636f6 Panagiotis Kanavos
				_statusService = null;
218 4ec636f6 Panagiotis Kanavos
			}
219 4ec636f6 Panagiotis Kanavos
		}
220 4ec636f6 Panagiotis Kanavos
221 4ec636f6 Panagiotis Kanavos
		public Task MonitorAccount(AccountSettings account)
222 4ec636f6 Panagiotis Kanavos
		{
223 4ec636f6 Panagiotis Kanavos
			return Task.Factory.StartNew(() =>
224 4ec636f6 Panagiotis Kanavos
			{                                                
225 4f6d51d4 Panagiotis Kanavos
				PithosMonitor monitor;
226 4ec636f6 Panagiotis Kanavos
				var accountName = account.AccountName;
227 4ec636f6 Panagiotis Kanavos
228 4ec636f6 Panagiotis Kanavos
				if (_monitors.TryGetValue(accountName, out monitor))
229 4ec636f6 Panagiotis Kanavos
				{
230 4ec636f6 Panagiotis Kanavos
					//If the account is active
231 4ec636f6 Panagiotis Kanavos
					if (account.IsActive)
232 4ec636f6 Panagiotis Kanavos
						//Start the monitor. It's OK to start an already started monitor,
233 4ec636f6 Panagiotis Kanavos
						//it will just ignore the call                        
234 4ec636f6 Panagiotis Kanavos
						StartMonitor(monitor).Wait();                        
235 4ec636f6 Panagiotis Kanavos
					else
236 4ec636f6 Panagiotis Kanavos
					{
237 4ec636f6 Panagiotis Kanavos
						//If the account is inactive
238 4ec636f6 Panagiotis Kanavos
						//Stop and remove the monitor
239 4ec636f6 Panagiotis Kanavos
						RemoveMonitor(accountName);
240 4ec636f6 Panagiotis Kanavos
					}
241 4ec636f6 Panagiotis Kanavos
					return;
242 4ec636f6 Panagiotis Kanavos
				}
243 4ec636f6 Panagiotis Kanavos
244 255f5f86 Panagiotis Kanavos
				
245 4ec636f6 Panagiotis Kanavos
				//Create a new monitor/ Can't use MEF here, it would return a single instance for all monitors
246 4ec636f6 Panagiotis Kanavos
				monitor = new PithosMonitor
247 4ec636f6 Panagiotis Kanavos
							  {
248 4ec636f6 Panagiotis Kanavos
								  UserName = accountName,
249 4ec636f6 Panagiotis Kanavos
								  ApiKey = account.ApiKey,                                  
250 4ec636f6 Panagiotis Kanavos
								  StatusNotification = this,
251 4ec636f6 Panagiotis Kanavos
								  RootPath = account.RootPath
252 4ec636f6 Panagiotis Kanavos
							  };
253 4ec636f6 Panagiotis Kanavos
				//PithosMonitor uses MEF so we need to resolve it
254 4ec636f6 Panagiotis Kanavos
				IoC.BuildUp(monitor);
255 4ec636f6 Panagiotis Kanavos
256 255f5f86 Panagiotis Kanavos
				monitor.AuthenticationUrl = account.ServerUrl;
257 4ec636f6 Panagiotis Kanavos
258 4ec636f6 Panagiotis Kanavos
				_monitors[accountName] = monitor;
259 4ec636f6 Panagiotis Kanavos
260 4ec636f6 Panagiotis Kanavos
				if (account.IsActive)
261 4ec636f6 Panagiotis Kanavos
				{
262 4ec636f6 Panagiotis Kanavos
					//Don't start a monitor if it doesn't have an account and ApiKey
263 4ec636f6 Panagiotis Kanavos
					if (String.IsNullOrWhiteSpace(monitor.UserName) ||
264 4ec636f6 Panagiotis Kanavos
						String.IsNullOrWhiteSpace(monitor.ApiKey))
265 4ec636f6 Panagiotis Kanavos
						return;
266 4ec636f6 Panagiotis Kanavos
					StartMonitor(monitor);
267 4ec636f6 Panagiotis Kanavos
				}
268 4ec636f6 Panagiotis Kanavos
			});
269 4ec636f6 Panagiotis Kanavos
		}
270 4ec636f6 Panagiotis Kanavos
271 4ec636f6 Panagiotis Kanavos
272 4ec636f6 Panagiotis Kanavos
		protected override void OnViewLoaded(object view)
273 4ec636f6 Panagiotis Kanavos
		{
274 4ec636f6 Panagiotis Kanavos
			UpdateStatus();
275 4ec636f6 Panagiotis Kanavos
			var window = (Window)view;            
276 4ec636f6 Panagiotis Kanavos
			TaskEx.Delay(1000).ContinueWith(t => Execute.OnUIThread(window.Hide));
277 4ec636f6 Panagiotis Kanavos
			base.OnViewLoaded(view);
278 4ec636f6 Panagiotis Kanavos
		}
279 4ec636f6 Panagiotis Kanavos
280 4ec636f6 Panagiotis Kanavos
281 4ec636f6 Panagiotis Kanavos
		#region Status Properties
282 4ec636f6 Panagiotis Kanavos
283 4ec636f6 Panagiotis Kanavos
		private string _statusMessage;
284 4ec636f6 Panagiotis Kanavos
		public string StatusMessage
285 4ec636f6 Panagiotis Kanavos
		{
286 4ec636f6 Panagiotis Kanavos
			get { return _statusMessage; }
287 4ec636f6 Panagiotis Kanavos
			set
288 4ec636f6 Panagiotis Kanavos
			{
289 4ec636f6 Panagiotis Kanavos
				_statusMessage = value;
290 4ec636f6 Panagiotis Kanavos
				NotifyOfPropertyChange(() => StatusMessage);
291 4ec636f6 Panagiotis Kanavos
			}
292 4ec636f6 Panagiotis Kanavos
		}
293 4ec636f6 Panagiotis Kanavos
294 4ec636f6 Panagiotis Kanavos
		private readonly ObservableConcurrentCollection<AccountInfo> _accounts = new ObservableConcurrentCollection<AccountInfo>();
295 4ec636f6 Panagiotis Kanavos
		public ObservableConcurrentCollection<AccountInfo> Accounts
296 4ec636f6 Panagiotis Kanavos
		{
297 4ec636f6 Panagiotis Kanavos
			get { return _accounts; }
298 4ec636f6 Panagiotis Kanavos
		}
299 4ec636f6 Panagiotis Kanavos
300 4ec636f6 Panagiotis Kanavos
		public bool HasAccounts
301 4ec636f6 Panagiotis Kanavos
		{
302 4ec636f6 Panagiotis Kanavos
			get { return _accounts.Count > 0; }
303 4ec636f6 Panagiotis Kanavos
		}
304 4ec636f6 Panagiotis Kanavos
305 4ec636f6 Panagiotis Kanavos
306 4ec636f6 Panagiotis Kanavos
		public string OpenFolderCaption
307 4ec636f6 Panagiotis Kanavos
		{
308 4ec636f6 Panagiotis Kanavos
			get
309 4ec636f6 Panagiotis Kanavos
			{
310 4ec636f6 Panagiotis Kanavos
				return (_accounts.Count == 0)
311 4ec636f6 Panagiotis Kanavos
						? "No Accounts Defined"
312 4ec636f6 Panagiotis Kanavos
						: "Open Pithos Folder";
313 4ec636f6 Panagiotis Kanavos
			}
314 4ec636f6 Panagiotis Kanavos
		}
315 4ec636f6 Panagiotis Kanavos
316 4ec636f6 Panagiotis Kanavos
		private string _pauseSyncCaption="Pause Synching";
317 4ec636f6 Panagiotis Kanavos
		public string PauseSyncCaption
318 4ec636f6 Panagiotis Kanavos
		{
319 4ec636f6 Panagiotis Kanavos
			get { return _pauseSyncCaption; }
320 4ec636f6 Panagiotis Kanavos
			set
321 4ec636f6 Panagiotis Kanavos
			{
322 4ec636f6 Panagiotis Kanavos
				_pauseSyncCaption = value;
323 4ec636f6 Panagiotis Kanavos
				NotifyOfPropertyChange(() => PauseSyncCaption);
324 4ec636f6 Panagiotis Kanavos
			}
325 4ec636f6 Panagiotis Kanavos
		}
326 4ec636f6 Panagiotis Kanavos
327 4ec636f6 Panagiotis Kanavos
		private readonly ObservableConcurrentCollection<FileEntry> _recentFiles = new ObservableConcurrentCollection<FileEntry>();
328 4ec636f6 Panagiotis Kanavos
		public ObservableConcurrentCollection<FileEntry> RecentFiles
329 4ec636f6 Panagiotis Kanavos
		{
330 4ec636f6 Panagiotis Kanavos
			get { return _recentFiles; }
331 4ec636f6 Panagiotis Kanavos
		}
332 4ec636f6 Panagiotis Kanavos
333 4ec636f6 Panagiotis Kanavos
334 4ec636f6 Panagiotis Kanavos
		private string _statusIcon="../Images/Pithos.ico";
335 4ec636f6 Panagiotis Kanavos
		public string StatusIcon
336 4ec636f6 Panagiotis Kanavos
		{
337 4ec636f6 Panagiotis Kanavos
			get { return _statusIcon; }
338 4ec636f6 Panagiotis Kanavos
			set
339 4ec636f6 Panagiotis Kanavos
			{
340 255f5f86 Panagiotis Kanavos
				//TODO: Ensure all status icons use the Pithos logo
341 4f6d51d4 Panagiotis Kanavos
				_statusIcon = value;
342 4ec636f6 Panagiotis Kanavos
				NotifyOfPropertyChange(() => StatusIcon);
343 4ec636f6 Panagiotis Kanavos
			}
344 4ec636f6 Panagiotis Kanavos
		}
345 4ec636f6 Panagiotis Kanavos
346 4ec636f6 Panagiotis Kanavos
		#endregion
347 4ec636f6 Panagiotis Kanavos
348 4ec636f6 Panagiotis Kanavos
		#region Commands
349 4ec636f6 Panagiotis Kanavos
350 4ec636f6 Panagiotis Kanavos
		public void ShowPreferences()
351 4ec636f6 Panagiotis Kanavos
		{
352 4ec636f6 Panagiotis Kanavos
			Settings.Reload();
353 4ec636f6 Panagiotis Kanavos
			var preferences = new PreferencesViewModel(_windowManager,_events, this,Settings);            
354 4ec636f6 Panagiotis Kanavos
			_windowManager.ShowDialog(preferences);
355 4ec636f6 Panagiotis Kanavos
			
356 4ec636f6 Panagiotis Kanavos
		}
357 4ec636f6 Panagiotis Kanavos
358 4ec636f6 Panagiotis Kanavos
		public void AboutPithos()
359 4ec636f6 Panagiotis Kanavos
		{
360 4ec636f6 Panagiotis Kanavos
			var about = new AboutViewModel();
361 4ec636f6 Panagiotis Kanavos
			_windowManager.ShowWindow(about);
362 4ec636f6 Panagiotis Kanavos
		}
363 4ec636f6 Panagiotis Kanavos
364 4ec636f6 Panagiotis Kanavos
		public void SendFeedback()
365 4ec636f6 Panagiotis Kanavos
		{
366 4ec636f6 Panagiotis Kanavos
			var feedBack =  IoC.Get<FeedbackViewModel>();
367 4ec636f6 Panagiotis Kanavos
			_windowManager.ShowWindow(feedBack);
368 4ec636f6 Panagiotis Kanavos
		}
369 4ec636f6 Panagiotis Kanavos
370 4ec636f6 Panagiotis Kanavos
		//public PithosCommand OpenPithosFolderCommand { get; private set; }
371 4ec636f6 Panagiotis Kanavos
372 4ec636f6 Panagiotis Kanavos
		public void OpenPithosFolder()
373 4ec636f6 Panagiotis Kanavos
		{
374 4ec636f6 Panagiotis Kanavos
			var account = Settings.Accounts.FirstOrDefault(acc => acc.IsActive);
375 4ec636f6 Panagiotis Kanavos
			if (account == null)
376 4ec636f6 Panagiotis Kanavos
				return;
377 4ec636f6 Panagiotis Kanavos
			Process.Start(account.RootPath);
378 4ec636f6 Panagiotis Kanavos
		}
379 4ec636f6 Panagiotis Kanavos
380 4ec636f6 Panagiotis Kanavos
		public void OpenPithosFolder(AccountInfo account)
381 4ec636f6 Panagiotis Kanavos
		{
382 4ec636f6 Panagiotis Kanavos
			Process.Start(account.AccountPath);
383 4ec636f6 Panagiotis Kanavos
		}
384 4ec636f6 Panagiotis Kanavos
385 4ec636f6 Panagiotis Kanavos
		
386 f734ab5b Panagiotis Kanavos
/*
387 4ec636f6 Panagiotis Kanavos
		public void GoToSite()
388 4ec636f6 Panagiotis Kanavos
		{            
389 4ec636f6 Panagiotis Kanavos
			var site = Properties.Settings.Default.PithosSite;
390 4ec636f6 Panagiotis Kanavos
			Process.Start(site);            
391 4ec636f6 Panagiotis Kanavos
		}
392 f734ab5b Panagiotis Kanavos
*/
393 6aa29f4f Panagiotis Kanavos
394 4ec636f6 Panagiotis Kanavos
		public void GoToSite(AccountInfo account)
395 4ec636f6 Panagiotis Kanavos
		{
396 4ec636f6 Panagiotis Kanavos
			/*var site = String.Format("{0}/ui/?token={1}&user={2}",
397 4ec636f6 Panagiotis Kanavos
				account.SiteUri,account.Token,
398 4ec636f6 Panagiotis Kanavos
				account.UserName);*/
399 4ec636f6 Panagiotis Kanavos
			Process.Start(account.SiteUri);
400 4ec636f6 Panagiotis Kanavos
		}
401 4ec636f6 Panagiotis Kanavos
402 4ec636f6 Panagiotis Kanavos
		public void ShowFileProperties()
403 4ec636f6 Panagiotis Kanavos
		{
404 4ec636f6 Panagiotis Kanavos
			var account = Settings.Accounts.First(acc => acc.IsActive);            
405 4ec636f6 Panagiotis Kanavos
			var dir = new DirectoryInfo(account.RootPath + @"\pithos");
406 4ec636f6 Panagiotis Kanavos
			var files=dir.GetFiles();
407 4ec636f6 Panagiotis Kanavos
			var r=new Random();
408 4ec636f6 Panagiotis Kanavos
			var idx=r.Next(0, files.Length);
409 4ec636f6 Panagiotis Kanavos
			ShowFileProperties(files[idx].FullName);            
410 4ec636f6 Panagiotis Kanavos
		}
411 4ec636f6 Panagiotis Kanavos
412 4ec636f6 Panagiotis Kanavos
		public void ShowFileProperties(string filePath)
413 4ec636f6 Panagiotis Kanavos
		{
414 4ec636f6 Panagiotis Kanavos
			if (String.IsNullOrWhiteSpace(filePath))
415 4ec636f6 Panagiotis Kanavos
				throw new ArgumentNullException("filePath");
416 4f6d51d4 Panagiotis Kanavos
			if (!File.Exists(filePath) && !Directory.Exists(filePath))
417 4ec636f6 Panagiotis Kanavos
				throw new ArgumentException(String.Format("Non existent file {0}",filePath),"filePath");
418 4ec636f6 Panagiotis Kanavos
			Contract.EndContractBlock();
419 4ec636f6 Panagiotis Kanavos
420 4ec636f6 Panagiotis Kanavos
			var pair=(from monitor in  Monitors
421 4ec636f6 Panagiotis Kanavos
							   where filePath.StartsWith(monitor.Value.RootPath, StringComparison.InvariantCultureIgnoreCase)
422 4ec636f6 Panagiotis Kanavos
								   select monitor).FirstOrDefault();
423 255f5f86 Panagiotis Kanavos
			var accountMonitor = pair.Value;
424 4ec636f6 Panagiotis Kanavos
425 4ec636f6 Panagiotis Kanavos
			if (accountMonitor == null)
426 4ec636f6 Panagiotis Kanavos
				return;
427 4ec636f6 Panagiotis Kanavos
428 4ec636f6 Panagiotis Kanavos
			var infoTask=Task.Factory.StartNew(()=>accountMonitor.GetObjectInfo(filePath));
429 4ec636f6 Panagiotis Kanavos
430 4ec636f6 Panagiotis Kanavos
			
431 4ec636f6 Panagiotis Kanavos
432 4ec636f6 Panagiotis Kanavos
			var fileProperties = new FilePropertiesViewModel(this, infoTask,filePath);
433 4ec636f6 Panagiotis Kanavos
			_windowManager.ShowWindow(fileProperties);
434 4ec636f6 Panagiotis Kanavos
		} 
435 4ec636f6 Panagiotis Kanavos
		
436 4ec636f6 Panagiotis Kanavos
		public void ShowContainerProperties()
437 4ec636f6 Panagiotis Kanavos
		{
438 4ec636f6 Panagiotis Kanavos
			var account = Settings.Accounts.First(acc => acc.IsActive);            
439 4ec636f6 Panagiotis Kanavos
			var dir = new DirectoryInfo(account.RootPath);
440 4ec636f6 Panagiotis Kanavos
			var fullName = (from folder in dir.EnumerateDirectories()
441 4ec636f6 Panagiotis Kanavos
							where (folder.Attributes & FileAttributes.Hidden) == 0
442 4ec636f6 Panagiotis Kanavos
							select folder.FullName).First();
443 4ec636f6 Panagiotis Kanavos
			ShowContainerProperties(fullName);            
444 4ec636f6 Panagiotis Kanavos
		}
445 4ec636f6 Panagiotis Kanavos
446 4ec636f6 Panagiotis Kanavos
		public void ShowContainerProperties(string filePath)
447 4ec636f6 Panagiotis Kanavos
		{
448 4ec636f6 Panagiotis Kanavos
			if (String.IsNullOrWhiteSpace(filePath))
449 4ec636f6 Panagiotis Kanavos
				throw new ArgumentNullException("filePath");
450 4ec636f6 Panagiotis Kanavos
			if (!Directory.Exists(filePath))
451 4ec636f6 Panagiotis Kanavos
				throw new ArgumentException(String.Format("Non existent file {0}",filePath),"filePath");
452 4ec636f6 Panagiotis Kanavos
			Contract.EndContractBlock();
453 4ec636f6 Panagiotis Kanavos
454 4ec636f6 Panagiotis Kanavos
			var pair=(from monitor in  Monitors
455 4ec636f6 Panagiotis Kanavos
							   where filePath.StartsWith(monitor.Value.RootPath, StringComparison.InvariantCultureIgnoreCase)
456 4ec636f6 Panagiotis Kanavos
								   select monitor).FirstOrDefault();
457 255f5f86 Panagiotis Kanavos
			var accountMonitor = pair.Value;            
458 4ec636f6 Panagiotis Kanavos
			var info = accountMonitor.GetContainerInfo(filePath);
459 4ec636f6 Panagiotis Kanavos
460 4ec636f6 Panagiotis Kanavos
			
461 4ec636f6 Panagiotis Kanavos
462 4ec636f6 Panagiotis Kanavos
			var containerProperties = new ContainerPropertiesViewModel(this, info,filePath);
463 4ec636f6 Panagiotis Kanavos
			_windowManager.ShowWindow(containerProperties);
464 4ec636f6 Panagiotis Kanavos
		}
465 4ec636f6 Panagiotis Kanavos
466 255f5f86 Panagiotis Kanavos
		public void SynchNow()
467 255f5f86 Panagiotis Kanavos
		{
468 aa7ac00e Panagiotis Kanavos
			var agent = IoC.Get<PollAgent>();
469 255f5f86 Panagiotis Kanavos
			agent.SynchNow();
470 255f5f86 Panagiotis Kanavos
		}
471 133f83c2 Panagiotis Kanavos
472 4ec636f6 Panagiotis Kanavos
		public ObjectInfo RefreshObjectInfo(ObjectInfo currentInfo)
473 4ec636f6 Panagiotis Kanavos
		{
474 4ec636f6 Panagiotis Kanavos
			if (currentInfo==null)
475 4ec636f6 Panagiotis Kanavos
				throw new ArgumentNullException("currentInfo");
476 4ec636f6 Panagiotis Kanavos
			Contract.EndContractBlock();
477 4ec636f6 Panagiotis Kanavos
478 4ec636f6 Panagiotis Kanavos
			var monitor = Monitors[currentInfo.Account];
479 4ec636f6 Panagiotis Kanavos
			var newInfo=monitor.CloudClient.GetObjectInfo(currentInfo.Account, currentInfo.Container, currentInfo.Name);
480 4ec636f6 Panagiotis Kanavos
			return newInfo;
481 4ec636f6 Panagiotis Kanavos
		}
482 4ec636f6 Panagiotis Kanavos
483 4ec636f6 Panagiotis Kanavos
		public ContainerInfo RefreshContainerInfo(ContainerInfo container)
484 4ec636f6 Panagiotis Kanavos
		{
485 4ec636f6 Panagiotis Kanavos
			if (container == null)
486 4ec636f6 Panagiotis Kanavos
				throw new ArgumentNullException("container");
487 4ec636f6 Panagiotis Kanavos
			Contract.EndContractBlock();
488 4ec636f6 Panagiotis Kanavos
489 4ec636f6 Panagiotis Kanavos
			var monitor = Monitors[container.Account];
490 4ec636f6 Panagiotis Kanavos
			var newInfo = monitor.CloudClient.GetContainerInfo(container.Account, container.Name);
491 4ec636f6 Panagiotis Kanavos
			return newInfo;
492 4ec636f6 Panagiotis Kanavos
		}
493 4ec636f6 Panagiotis Kanavos
494 4ec636f6 Panagiotis Kanavos
495 4ec636f6 Panagiotis Kanavos
		public void ToggleSynching()
496 4ec636f6 Panagiotis Kanavos
		{
497 4ec636f6 Panagiotis Kanavos
			bool isPaused=false;
498 4ec636f6 Panagiotis Kanavos
			foreach (var pair in Monitors)
499 4ec636f6 Panagiotis Kanavos
			{
500 4ec636f6 Panagiotis Kanavos
				var monitor = pair.Value;
501 4ec636f6 Panagiotis Kanavos
				monitor.Pause = !monitor.Pause;
502 4ec636f6 Panagiotis Kanavos
				isPaused = monitor.Pause;
503 4ec636f6 Panagiotis Kanavos
			}
504 4ec636f6 Panagiotis Kanavos
505 4ec636f6 Panagiotis Kanavos
			PauseSyncCaption = isPaused ? "Resume syncing" : "Pause syncing";
506 4ec636f6 Panagiotis Kanavos
			var iconKey = isPaused? "TraySyncPaused" : "TrayInSynch";
507 4ec636f6 Panagiotis Kanavos
			StatusIcon = String.Format(@"../Images/{0}.ico", iconKey);
508 4ec636f6 Panagiotis Kanavos
		}
509 4ec636f6 Panagiotis Kanavos
510 4ec636f6 Panagiotis Kanavos
		public void ExitPithos()
511 4ec636f6 Panagiotis Kanavos
		{
512 4ec636f6 Panagiotis Kanavos
			foreach (var pair in Monitors)
513 4ec636f6 Panagiotis Kanavos
			{
514 4ec636f6 Panagiotis Kanavos
				var monitor = pair.Value;
515 4ec636f6 Panagiotis Kanavos
				monitor.Stop();
516 4ec636f6 Panagiotis Kanavos
			}
517 4ec636f6 Panagiotis Kanavos
518 4ec636f6 Panagiotis Kanavos
			((Window)GetView()).Close();
519 4ec636f6 Panagiotis Kanavos
		}
520 4ec636f6 Panagiotis Kanavos
		#endregion
521 4ec636f6 Panagiotis Kanavos
522 4ec636f6 Panagiotis Kanavos
523 4f6d51d4 Panagiotis Kanavos
		private readonly Dictionary<PithosStatus, StatusInfo> _iconNames = new List<StatusInfo>
524 4ec636f6 Panagiotis Kanavos
			{
525 4ec636f6 Panagiotis Kanavos
				new StatusInfo(PithosStatus.InSynch, "All files up to date", "TrayInSynch"),
526 4ec636f6 Panagiotis Kanavos
				new StatusInfo(PithosStatus.Syncing, "Syncing Files", "TraySynching"),
527 4ec636f6 Panagiotis Kanavos
				new StatusInfo(PithosStatus.SyncPaused, "Sync Paused", "TraySyncPaused")
528 4ec636f6 Panagiotis Kanavos
			}.ToDictionary(s => s.Status);
529 4ec636f6 Panagiotis Kanavos
530 4ec636f6 Panagiotis Kanavos
		readonly IWindowManager _windowManager;
531 255f5f86 Panagiotis Kanavos
		
532 c53aa229 Panagiotis Kanavos
533 cf761c0d Panagiotis Kanavos
		///<summary>
534 cf761c0d Panagiotis Kanavos
		/// Updates the visual status indicators of the application depending on status changes, e.g. icon, stat		
535 cf761c0d Panagiotis Kanavos
		///</summary>
536 4ec636f6 Panagiotis Kanavos
		public void UpdateStatus()
537 4ec636f6 Panagiotis Kanavos
		{
538 4ec636f6 Panagiotis Kanavos
			var pithosStatus = _statusChecker.GetPithosStatus();
539 4ec636f6 Panagiotis Kanavos
540 4f6d51d4 Panagiotis Kanavos
			if (_iconNames.ContainsKey(pithosStatus))
541 4ec636f6 Panagiotis Kanavos
			{
542 4f6d51d4 Panagiotis Kanavos
				var info = _iconNames[pithosStatus];
543 4ec636f6 Panagiotis Kanavos
				StatusIcon = String.Format(@"../Images/{0}.ico", info.IconName);
544 4ec636f6 Panagiotis Kanavos
545 4ec636f6 Panagiotis Kanavos
546 4ec636f6 Panagiotis Kanavos
547 422c9598 Panagiotis Kanavos
				StatusMessage = String.Format("Pithos {0}\r\n{1}", _fileVersion.Value.FileVersion,info.StatusText);
548 4ec636f6 Panagiotis Kanavos
			}
549 4ec636f6 Panagiotis Kanavos
			
550 852d2cf2 Panagiotis Kanavos
			//_events.Publish(new Notification { Title = "Start", Message = "Start Monitoring", Level = TraceLevel.Info});
551 4ec636f6 Panagiotis Kanavos
		}
552 4ec636f6 Panagiotis Kanavos
553 4ec636f6 Panagiotis Kanavos
554 4ec636f6 Panagiotis Kanavos
	   
555 4ec636f6 Panagiotis Kanavos
		private Task StartMonitor(PithosMonitor monitor,int retries=0)
556 4ec636f6 Panagiotis Kanavos
		{
557 4ec636f6 Panagiotis Kanavos
			return Task.Factory.StartNew(() =>
558 4ec636f6 Panagiotis Kanavos
			{
559 4ec636f6 Panagiotis Kanavos
				using (log4net.ThreadContext.Stacks["Monitor"].Push("Start"))
560 4ec636f6 Panagiotis Kanavos
				{
561 4ec636f6 Panagiotis Kanavos
					try
562 4ec636f6 Panagiotis Kanavos
					{
563 4ec636f6 Panagiotis Kanavos
						Log.InfoFormat("Start Monitoring {0}", monitor.UserName);
564 4ec636f6 Panagiotis Kanavos
565 4ec636f6 Panagiotis Kanavos
						monitor.Start();
566 4ec636f6 Panagiotis Kanavos
					}
567 4ec636f6 Panagiotis Kanavos
					catch (WebException exc)
568 4ec636f6 Panagiotis Kanavos
					{
569 4ec636f6 Panagiotis Kanavos
						if (AbandonRetry(monitor, retries))
570 4ec636f6 Panagiotis Kanavos
							return;
571 4ec636f6 Panagiotis Kanavos
572 255f5f86 Panagiotis Kanavos
						HttpStatusCode statusCode =HttpStatusCode.OK;
573 255f5f86 Panagiotis Kanavos
						var response = exc.Response as HttpWebResponse;
574 255f5f86 Panagiotis Kanavos
						if(response!=null)
575 255f5f86 Panagiotis Kanavos
							statusCode = response.StatusCode;
576 255f5f86 Panagiotis Kanavos
577 255f5f86 Panagiotis Kanavos
						switch (statusCode)
578 255f5f86 Panagiotis Kanavos
						{
579 255f5f86 Panagiotis Kanavos
							case HttpStatusCode.Unauthorized:
580 255f5f86 Panagiotis Kanavos
								var message = String.Format("API Key Expired for {0}. Starting Renewal",
581 255f5f86 Panagiotis Kanavos
															monitor.UserName);
582 255f5f86 Panagiotis Kanavos
								Log.Error(message, exc);
583 62d5b25f Panagiotis Kanavos
								TryAuthorize(monitor.UserName, retries).Wait();
584 255f5f86 Panagiotis Kanavos
								break;
585 255f5f86 Panagiotis Kanavos
							case HttpStatusCode.ProxyAuthenticationRequired:
586 255f5f86 Panagiotis Kanavos
								TryAuthenticateProxy(monitor,retries);
587 255f5f86 Panagiotis Kanavos
								break;
588 255f5f86 Panagiotis Kanavos
							default:
589 255f5f86 Panagiotis Kanavos
								TryLater(monitor, exc, retries);
590 255f5f86 Panagiotis Kanavos
								break;
591 255f5f86 Panagiotis Kanavos
						}
592 4ec636f6 Panagiotis Kanavos
					}
593 4ec636f6 Panagiotis Kanavos
					catch (Exception exc)
594 4ec636f6 Panagiotis Kanavos
					{
595 4ec636f6 Panagiotis Kanavos
						if (AbandonRetry(monitor, retries)) 
596 4ec636f6 Panagiotis Kanavos
							return;
597 4ec636f6 Panagiotis Kanavos
598 4ec636f6 Panagiotis Kanavos
						TryLater(monitor,exc,retries);
599 4ec636f6 Panagiotis Kanavos
					}
600 4ec636f6 Panagiotis Kanavos
				}
601 4ec636f6 Panagiotis Kanavos
			});
602 4ec636f6 Panagiotis Kanavos
		}
603 4ec636f6 Panagiotis Kanavos
604 255f5f86 Panagiotis Kanavos
		private void TryAuthenticateProxy(PithosMonitor monitor,int retries)
605 255f5f86 Panagiotis Kanavos
		{
606 255f5f86 Panagiotis Kanavos
			Execute.OnUIThread(() =>
607 255f5f86 Panagiotis Kanavos
								   {                                       
608 255f5f86 Panagiotis Kanavos
									   var proxyAccount = IoC.Get<ProxyAccountViewModel>();
609 255f5f86 Panagiotis Kanavos
										proxyAccount.Settings = this.Settings;
610 255f5f86 Panagiotis Kanavos
									   if (true != _windowManager.ShowDialog(proxyAccount)) 
611 255f5f86 Panagiotis Kanavos
										   return;
612 255f5f86 Panagiotis Kanavos
									   StartMonitor(monitor, retries);
613 255f5f86 Panagiotis Kanavos
									   NotifyOfPropertyChange(() => Accounts);
614 255f5f86 Panagiotis Kanavos
								   });
615 255f5f86 Panagiotis Kanavos
		}
616 65282d58 Panagiotis Kanavos
617 255f5f86 Panagiotis Kanavos
		private bool AbandonRetry(PithosMonitor monitor, int retries)
618 4ec636f6 Panagiotis Kanavos
		{
619 4ec636f6 Panagiotis Kanavos
			if (retries > 1)
620 4ec636f6 Panagiotis Kanavos
			{
621 4ec636f6 Panagiotis Kanavos
				var message = String.Format("Monitoring of account {0} has failed too many times. Will not retry",
622 4ec636f6 Panagiotis Kanavos
											monitor.UserName);
623 4ec636f6 Panagiotis Kanavos
				_events.Publish(new Notification
624 4ec636f6 Panagiotis Kanavos
									{Title = "Account monitoring failed", Message = message, Level = TraceLevel.Error});
625 4ec636f6 Panagiotis Kanavos
				return true;
626 4ec636f6 Panagiotis Kanavos
			}
627 4ec636f6 Panagiotis Kanavos
			return false;
628 4ec636f6 Panagiotis Kanavos
		}
629 4ec636f6 Panagiotis Kanavos
630 4ec636f6 Panagiotis Kanavos
631 62d5b25f Panagiotis Kanavos
		private async Task TryAuthorize(string userName, int retries)
632 4ec636f6 Panagiotis Kanavos
		{
633 4ec636f6 Panagiotis Kanavos
			_events.Publish(new Notification { Title = "Authorization failed", Message = "Your API Key has probably expired. You will be directed to a page where you can renew it", Level = TraceLevel.Error });
634 4ec636f6 Panagiotis Kanavos
635 4ec636f6 Panagiotis Kanavos
			try
636 4ec636f6 Panagiotis Kanavos
			{
637 4ec636f6 Panagiotis Kanavos
638 4ec636f6 Panagiotis Kanavos
				var credentials = await PithosAccount.RetrieveCredentials(Settings.PithosLoginUrl);
639 4ec636f6 Panagiotis Kanavos
640 4f6d51d4 Panagiotis Kanavos
				var account = Settings.Accounts.First(act => act.AccountName == credentials.UserName);
641 62d5b25f Panagiotis Kanavos
                //The server may return credentials for a different account
642 62d5b25f Panagiotis Kanavos
			    var monitor = _monitors[account.AccountName];
643 4ec636f6 Panagiotis Kanavos
				account.ApiKey = credentials.Password;
644 62d5b25f Panagiotis Kanavos
                monitor.ApiKey = credentials.Password;
645 4ec636f6 Panagiotis Kanavos
				Settings.Save();
646 4ec636f6 Panagiotis Kanavos
				await TaskEx.Delay(10000);
647 62d5b25f Panagiotis Kanavos
                StartMonitor(monitor, retries + 1);
648 4ec636f6 Panagiotis Kanavos
				NotifyOfPropertyChange(()=>Accounts);
649 4ec636f6 Panagiotis Kanavos
			}
650 4ec636f6 Panagiotis Kanavos
			catch (AggregateException exc)
651 4ec636f6 Panagiotis Kanavos
			{
652 62d5b25f Panagiotis Kanavos
				string message = String.Format("API Key retrieval for {0} failed", userName);
653 4ec636f6 Panagiotis Kanavos
				Log.Error(message, exc.InnerException);
654 4ec636f6 Panagiotis Kanavos
				_events.Publish(new Notification { Title = "Authorization failed", Message = message, Level = TraceLevel.Error });
655 4ec636f6 Panagiotis Kanavos
			}
656 4ec636f6 Panagiotis Kanavos
			catch (Exception exc)
657 4ec636f6 Panagiotis Kanavos
			{
658 62d5b25f Panagiotis Kanavos
				string message = String.Format("API Key retrieval for {0} failed", userName);
659 4ec636f6 Panagiotis Kanavos
				Log.Error(message, exc);
660 4ec636f6 Panagiotis Kanavos
				_events.Publish(new Notification { Title = "Authorization failed", Message = message, Level = TraceLevel.Error });
661 4ec636f6 Panagiotis Kanavos
			}
662 4ec636f6 Panagiotis Kanavos
663 4ec636f6 Panagiotis Kanavos
		}
664 4ec636f6 Panagiotis Kanavos
665 4ec636f6 Panagiotis Kanavos
		private static bool IsUnauthorized(WebException exc)
666 4ec636f6 Panagiotis Kanavos
		{
667 4ec636f6 Panagiotis Kanavos
			if (exc==null)
668 4ec636f6 Panagiotis Kanavos
				throw new ArgumentNullException("exc");
669 4ec636f6 Panagiotis Kanavos
			Contract.EndContractBlock();
670 4ec636f6 Panagiotis Kanavos
671 4ec636f6 Panagiotis Kanavos
			var response = exc.Response as HttpWebResponse;
672 4ec636f6 Panagiotis Kanavos
			if (response == null)
673 4ec636f6 Panagiotis Kanavos
				return false;
674 4ec636f6 Panagiotis Kanavos
			return (response.StatusCode == HttpStatusCode.Unauthorized);
675 4ec636f6 Panagiotis Kanavos
		}
676 4ec636f6 Panagiotis Kanavos
677 4ec636f6 Panagiotis Kanavos
		private void TryLater(PithosMonitor monitor, Exception exc,int retries)
678 4ec636f6 Panagiotis Kanavos
		{
679 4ec636f6 Panagiotis Kanavos
			var message = String.Format("An exception occured. Can't start monitoring\nWill retry in 10 seconds");
680 4ec636f6 Panagiotis Kanavos
			Task.Factory.StartNewDelayed(10000, () => StartMonitor(monitor,retries+1));
681 4ec636f6 Panagiotis Kanavos
			_events.Publish(new Notification
682 4ec636f6 Panagiotis Kanavos
								{Title = "Error", Message = message, Level = TraceLevel.Error});
683 4ec636f6 Panagiotis Kanavos
			Log.Error(message, exc);
684 4ec636f6 Panagiotis Kanavos
		}
685 4ec636f6 Panagiotis Kanavos
686 4ec636f6 Panagiotis Kanavos
687 4ec636f6 Panagiotis Kanavos
		public void NotifyChange(string status, TraceLevel level=TraceLevel.Info)
688 4ec636f6 Panagiotis Kanavos
		{
689 4f6d51d4 Panagiotis Kanavos
			StatusMessage = status;
690 4ec636f6 Panagiotis Kanavos
			
691 4ec636f6 Panagiotis Kanavos
			_events.Publish(new Notification { Title = "Pithos", Message = status, Level = level });
692 4ec636f6 Panagiotis Kanavos
		}
693 4ec636f6 Panagiotis Kanavos
694 4ec636f6 Panagiotis Kanavos
		public void NotifyChangedFile(string filePath)
695 4ec636f6 Panagiotis Kanavos
		{
696 4ec636f6 Panagiotis Kanavos
			var entry = new FileEntry {FullPath=filePath};
697 4f6d51d4 Panagiotis Kanavos
			IProducerConsumerCollection<FileEntry> files=RecentFiles;
698 4ec636f6 Panagiotis Kanavos
			FileEntry popped;
699 4ec636f6 Panagiotis Kanavos
			while (files.Count > 5)
700 4ec636f6 Panagiotis Kanavos
				files.TryTake(out popped);
701 4ec636f6 Panagiotis Kanavos
			files.TryAdd(entry);
702 4ec636f6 Panagiotis Kanavos
		}
703 4ec636f6 Panagiotis Kanavos
704 4ec636f6 Panagiotis Kanavos
		public void NotifyAccount(AccountInfo account)
705 4ec636f6 Panagiotis Kanavos
		{
706 4ec636f6 Panagiotis Kanavos
			if (account== null)
707 4ec636f6 Panagiotis Kanavos
				return;
708 4ec636f6 Panagiotis Kanavos
			//TODO: What happens to an existing account whose Token has changed?
709 4ec636f6 Panagiotis Kanavos
			account.SiteUri= String.Format("{0}/ui/?token={1}&user={2}",
710 eae84ae8 Panagiotis Kanavos
				account.SiteUri, Uri.EscapeDataString(account.Token),
711 255f5f86 Panagiotis Kanavos
				Uri.EscapeDataString(account.UserName));
712 4ec636f6 Panagiotis Kanavos
713 4ec636f6 Panagiotis Kanavos
			if (Accounts.All(item => item.UserName != account.UserName))
714 4ec636f6 Panagiotis Kanavos
				Accounts.TryAdd(account);
715 4ec636f6 Panagiotis Kanavos
716 4ec636f6 Panagiotis Kanavos
		}
717 4ec636f6 Panagiotis Kanavos
718 255f5f86 Panagiotis Kanavos
		public void NotifyConflicts(IEnumerable<FileSystemInfo> conflictFiles, string message)
719 255f5f86 Panagiotis Kanavos
		{
720 255f5f86 Panagiotis Kanavos
			if (conflictFiles == null)
721 255f5f86 Panagiotis Kanavos
				return;
722 255f5f86 Panagiotis Kanavos
			if (!conflictFiles.Any())
723 255f5f86 Panagiotis Kanavos
				return;
724 e5b65606 Panagiotis Kanavos
725 255f5f86 Panagiotis Kanavos
			UpdateStatus();
726 255f5f86 Panagiotis Kanavos
			//TODO: Create a more specific message. For now, just show a warning
727 255f5f86 Panagiotis Kanavos
			NotifyForFiles(conflictFiles,message,TraceLevel.Warning);
728 9c6d3193 Panagiotis Kanavos
729 255f5f86 Panagiotis Kanavos
		}
730 9c6d3193 Panagiotis Kanavos
731 255f5f86 Panagiotis Kanavos
		public void NotifyForFiles(IEnumerable<FileSystemInfo> files, string message,TraceLevel level=TraceLevel.Info)
732 255f5f86 Panagiotis Kanavos
		{
733 255f5f86 Panagiotis Kanavos
			if (files == null)
734 255f5f86 Panagiotis Kanavos
				return;
735 255f5f86 Panagiotis Kanavos
			if (!files.Any())
736 255f5f86 Panagiotis Kanavos
				return;
737 9c6d3193 Panagiotis Kanavos
738 255f5f86 Panagiotis Kanavos
			StatusMessage = message;
739 9c6d3193 Panagiotis Kanavos
740 255f5f86 Panagiotis Kanavos
			_events.Publish(new Notification { Title = "Pithos", Message = message, Level = level});
741 255f5f86 Panagiotis Kanavos
		}
742 9c6d3193 Panagiotis Kanavos
743 255f5f86 Panagiotis Kanavos
		public void Notify(Notification notification)
744 255f5f86 Panagiotis Kanavos
		{
745 255f5f86 Panagiotis Kanavos
			_events.Publish(notification);
746 255f5f86 Panagiotis Kanavos
		}
747 e5b65606 Panagiotis Kanavos
748 4ec636f6 Panagiotis Kanavos
749 255f5f86 Panagiotis Kanavos
		public void RemoveMonitor(string accountName)
750 4ec636f6 Panagiotis Kanavos
		{
751 4ec636f6 Panagiotis Kanavos
			if (String.IsNullOrWhiteSpace(accountName))
752 4ec636f6 Panagiotis Kanavos
				return;
753 4ec636f6 Panagiotis Kanavos
754 4ec636f6 Panagiotis Kanavos
			var accountInfo=_accounts.FirstOrDefault(account => account.UserName == accountName);
755 4ec636f6 Panagiotis Kanavos
			_accounts.TryRemove(accountInfo);
756 4ec636f6 Panagiotis Kanavos
757 4ec636f6 Panagiotis Kanavos
			PithosMonitor monitor;
758 4ec636f6 Panagiotis Kanavos
			if (Monitors.TryRemove(accountName, out monitor))
759 4ec636f6 Panagiotis Kanavos
			{
760 4ec636f6 Panagiotis Kanavos
				monitor.Stop();
761 4ec636f6 Panagiotis Kanavos
			}
762 4ec636f6 Panagiotis Kanavos
		}
763 4ec636f6 Panagiotis Kanavos
764 4ec636f6 Panagiotis Kanavos
		public void RefreshOverlays()
765 4ec636f6 Panagiotis Kanavos
		{
766 4ec636f6 Panagiotis Kanavos
			foreach (var pair in Monitors)
767 4ec636f6 Panagiotis Kanavos
			{
768 4ec636f6 Panagiotis Kanavos
				var monitor = pair.Value;
769 4ec636f6 Panagiotis Kanavos
770 4ec636f6 Panagiotis Kanavos
				var path = monitor.RootPath;
771 4ec636f6 Panagiotis Kanavos
772 4ec636f6 Panagiotis Kanavos
				if (String.IsNullOrWhiteSpace(path))
773 4ec636f6 Panagiotis Kanavos
					continue;
774 4ec636f6 Panagiotis Kanavos
775 4ec636f6 Panagiotis Kanavos
				if (!Directory.Exists(path) && !File.Exists(path))
776 4ec636f6 Panagiotis Kanavos
					continue;
777 4ec636f6 Panagiotis Kanavos
778 4ec636f6 Panagiotis Kanavos
				IntPtr pathPointer = Marshal.StringToCoTaskMemAuto(path);
779 4ec636f6 Panagiotis Kanavos
780 4ec636f6 Panagiotis Kanavos
				try
781 4ec636f6 Panagiotis Kanavos
				{
782 4ec636f6 Panagiotis Kanavos
					NativeMethods.SHChangeNotify(HChangeNotifyEventID.SHCNE_UPDATEITEM,
783 4ec636f6 Panagiotis Kanavos
												 HChangeNotifyFlags.SHCNF_PATHW | HChangeNotifyFlags.SHCNF_FLUSHNOWAIT,
784 4ec636f6 Panagiotis Kanavos
												 pathPointer, IntPtr.Zero);
785 4ec636f6 Panagiotis Kanavos
				}
786 4ec636f6 Panagiotis Kanavos
				finally
787 4ec636f6 Panagiotis Kanavos
				{
788 4ec636f6 Panagiotis Kanavos
					Marshal.FreeHGlobal(pathPointer);
789 4ec636f6 Panagiotis Kanavos
				}
790 4ec636f6 Panagiotis Kanavos
			}
791 4ec636f6 Panagiotis Kanavos
		}
792 4ec636f6 Panagiotis Kanavos
793 4ec636f6 Panagiotis Kanavos
		#region Event Handlers
794 4ec636f6 Panagiotis Kanavos
		
795 4ec636f6 Panagiotis Kanavos
		public void Handle(SelectiveSynchChanges message)
796 4ec636f6 Panagiotis Kanavos
		{
797 4ec636f6 Panagiotis Kanavos
			var accountName = message.Account.AccountName;
798 4ec636f6 Panagiotis Kanavos
			PithosMonitor monitor;
799 4ec636f6 Panagiotis Kanavos
			if (_monitors.TryGetValue(accountName, out monitor))
800 4ec636f6 Panagiotis Kanavos
			{
801 759bd3c4 Panagiotis Kanavos
				monitor.SetSelectivePaths(message.Uris,message.Added,message.Removed);
802 4ec636f6 Panagiotis Kanavos
803 4ec636f6 Panagiotis Kanavos
			}
804 4ec636f6 Panagiotis Kanavos
			
805 4ec636f6 Panagiotis Kanavos
		}
806 4ec636f6 Panagiotis Kanavos
807 4ec636f6 Panagiotis Kanavos
808 255f5f86 Panagiotis Kanavos
		private bool _pollStarted = false;
809 eae84ae8 Panagiotis Kanavos
810 255f5f86 Panagiotis Kanavos
		//SMELL: Doing so much work for notifications in the shell is wrong
811 255f5f86 Panagiotis Kanavos
		//The notifications should be moved to their own view/viewmodel pair
812 255f5f86 Panagiotis Kanavos
		//and different templates should be used for different message types
813 255f5f86 Panagiotis Kanavos
		//This will also allow the addition of extra functionality, eg. actions
814 255f5f86 Panagiotis Kanavos
		//
815 4ec636f6 Panagiotis Kanavos
		public void Handle(Notification notification)
816 4ec636f6 Panagiotis Kanavos
		{
817 255f5f86 Panagiotis Kanavos
			UpdateStatus();
818 e5b65606 Panagiotis Kanavos
819 4ec636f6 Panagiotis Kanavos
			if (!Settings.ShowDesktopNotifications)
820 4ec636f6 Panagiotis Kanavos
				return;
821 eae84ae8 Panagiotis Kanavos
822 255f5f86 Panagiotis Kanavos
			if (notification is PollNotification)
823 255f5f86 Panagiotis Kanavos
			{
824 255f5f86 Panagiotis Kanavos
				_pollStarted = true;
825 255f5f86 Panagiotis Kanavos
				return;
826 255f5f86 Panagiotis Kanavos
			}
827 255f5f86 Panagiotis Kanavos
			if (notification is CloudNotification)
828 255f5f86 Panagiotis Kanavos
			{
829 255f5f86 Panagiotis Kanavos
				if (!_pollStarted) 
830 255f5f86 Panagiotis Kanavos
					return;
831 255f5f86 Panagiotis Kanavos
				_pollStarted= false;
832 255f5f86 Panagiotis Kanavos
				notification.Title = "Pithos";
833 255f5f86 Panagiotis Kanavos
				notification.Message = "Start Synchronisation";
834 255f5f86 Panagiotis Kanavos
			}
835 255f5f86 Panagiotis Kanavos
836 255f5f86 Panagiotis Kanavos
			if (String.IsNullOrWhiteSpace(notification.Message) && String.IsNullOrWhiteSpace(notification.Title))
837 255f5f86 Panagiotis Kanavos
				return;
838 2dc6f765 Panagiotis Kanavos
839 4f6d51d4 Panagiotis Kanavos
			BalloonIcon icon;
840 4ec636f6 Panagiotis Kanavos
			switch (notification.Level)
841 4ec636f6 Panagiotis Kanavos
			{
842 4ec636f6 Panagiotis Kanavos
				case TraceLevel.Error:
843 4ec636f6 Panagiotis Kanavos
					icon = BalloonIcon.Error;
844 4ec636f6 Panagiotis Kanavos
					break;
845 4ec636f6 Panagiotis Kanavos
				case TraceLevel.Info:
846 4ec636f6 Panagiotis Kanavos
				case TraceLevel.Verbose:
847 4ec636f6 Panagiotis Kanavos
					icon = BalloonIcon.Info;
848 4ec636f6 Panagiotis Kanavos
					break;
849 4ec636f6 Panagiotis Kanavos
				case TraceLevel.Warning:
850 4ec636f6 Panagiotis Kanavos
					icon = BalloonIcon.Warning;
851 4ec636f6 Panagiotis Kanavos
					break;
852 4ec636f6 Panagiotis Kanavos
				default:
853 4ec636f6 Panagiotis Kanavos
					icon = BalloonIcon.None;
854 4ec636f6 Panagiotis Kanavos
					break;
855 4ec636f6 Panagiotis Kanavos
			}
856 255f5f86 Panagiotis Kanavos
			
857 4ec636f6 Panagiotis Kanavos
			if (Settings.ShowDesktopNotifications)
858 4ec636f6 Panagiotis Kanavos
			{
859 eae84ae8 Panagiotis Kanavos
				var tv = (ShellView) GetView();                
860 255f5f86 Panagiotis Kanavos
				var balloon=new PithosBalloon{Title=notification.Title,Message=notification.Message,Icon=icon};
861 255f5f86 Panagiotis Kanavos
				tv.TaskbarView.ShowCustomBalloon(balloon,PopupAnimation.Fade,4000);
862 fb9d6e00 Panagiotis Kanavos
//				tv.TaskbarView.ShowBalloonTip(notification.Title, notification.Message, icon);
863 4ec636f6 Panagiotis Kanavos
			}
864 4ec636f6 Panagiotis Kanavos
		}
865 4ec636f6 Panagiotis Kanavos
		#endregion
866 4ec636f6 Panagiotis Kanavos
867 4ec636f6 Panagiotis Kanavos
		public void Handle(ShowFilePropertiesEvent message)
868 4ec636f6 Panagiotis Kanavos
		{
869 4ec636f6 Panagiotis Kanavos
			if (message == null)
870 4ec636f6 Panagiotis Kanavos
				throw new ArgumentNullException("message");
871 4ec636f6 Panagiotis Kanavos
			if (String.IsNullOrWhiteSpace(message.FileName) )
872 4ec636f6 Panagiotis Kanavos
				throw new ArgumentException("message");
873 4ec636f6 Panagiotis Kanavos
			Contract.EndContractBlock();
874 4ec636f6 Panagiotis Kanavos
875 4ec636f6 Panagiotis Kanavos
			var fileName = message.FileName;
876 255f5f86 Panagiotis Kanavos
			//TODO: Display file properties for non-container folders
877 4ec636f6 Panagiotis Kanavos
			if (File.Exists(fileName))
878 255f5f86 Panagiotis Kanavos
				//Retrieve the full name with exact casing. Pithos names are case sensitive				
879 255f5f86 Panagiotis Kanavos
				ShowFileProperties(FileInfoExtensions.GetProperFilePathCapitalization(fileName));
880 4ec636f6 Panagiotis Kanavos
			else if (Directory.Exists(fileName))
881 255f5f86 Panagiotis Kanavos
				//Retrieve the full name with exact casing. Pithos names are case sensitive
882 4f6d51d4 Panagiotis Kanavos
			{
883 255f5f86 Panagiotis Kanavos
				var path = FileInfoExtensions.GetProperDirectoryCapitalization(fileName);
884 255f5f86 Panagiotis Kanavos
				if (IsContainer(path))
885 255f5f86 Panagiotis Kanavos
					ShowContainerProperties(path);
886 255f5f86 Panagiotis Kanavos
				else
887 255f5f86 Panagiotis Kanavos
					ShowFileProperties(path);
888 4f6d51d4 Panagiotis Kanavos
			}
889 4ec636f6 Panagiotis Kanavos
		}
890 4f6d51d4 Panagiotis Kanavos
891 255f5f86 Panagiotis Kanavos
		private bool IsContainer(string path)
892 255f5f86 Panagiotis Kanavos
		{
893 255f5f86 Panagiotis Kanavos
			var matchingFolders = from account in _accounts
894 255f5f86 Panagiotis Kanavos
								  from rootFolder in Directory.GetDirectories(account.AccountPath)
895 255f5f86 Panagiotis Kanavos
								  where rootFolder.Equals(path, StringComparison.InvariantCultureIgnoreCase)
896 255f5f86 Panagiotis Kanavos
								  select rootFolder;
897 255f5f86 Panagiotis Kanavos
			return matchingFolders.Any();
898 255f5f86 Panagiotis Kanavos
		}
899 255f5f86 Panagiotis Kanavos
900 255f5f86 Panagiotis Kanavos
		public FileStatus GetFileStatus(string localFileName)
901 255f5f86 Panagiotis Kanavos
		{
902 255f5f86 Panagiotis Kanavos
			if (String.IsNullOrWhiteSpace(localFileName))
903 255f5f86 Panagiotis Kanavos
				throw new ArgumentNullException("localFileName");
904 255f5f86 Panagiotis Kanavos
			Contract.EndContractBlock();
905 255f5f86 Panagiotis Kanavos
			
906 255f5f86 Panagiotis Kanavos
			var statusKeeper = IoC.Get<IStatusKeeper>();
907 255f5f86 Panagiotis Kanavos
			var status=statusKeeper.GetFileStatus(localFileName);
908 255f5f86 Panagiotis Kanavos
			return status;
909 255f5f86 Panagiotis Kanavos
		}
910 4ec636f6 Panagiotis Kanavos
	}
911 9bae55d1 Panagiotis Kanavos
}