Statistics
| Branch: | Revision:

root / trunk / Pithos.Client.WPF / Shell / ShellViewModel.cs @ 6bcdd8e2

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