Added Clear Conflict action to resolver
[pithos-ms-client] / trunk / Pithos.Interfaces / ObjectInfo.cs
index 1675be1..7301002 100644 (file)
@@ -1,14 +1,72 @@
+#region
+/* -----------------------------------------------------------------------
+ * <copyright file="ObjectInfo.cs" company="GRNet">
+ * 
+ * Copyright 2011-2012 GRNET S.A. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials
+ *      provided with the distribution.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and
+ * documentation are those of the authors and should not be
+ * interpreted as representing official policies, either expressed
+ * or implied, of GRNET S.A.
+ * </copyright>
+ * -----------------------------------------------------------------------
+ */
+#endregion
 using System;
 using System.Collections.Generic;
+using System.Diagnostics;
+using System.Diagnostics.Contracts;
+using System.Dynamic;
 using System.Globalization;
 using System.IO;
+using System.Linq;
+using System.Text;
+using Newtonsoft.Json;
 
 namespace Pithos.Interfaces
 {
-    public class ObjectInfo
+    [DebuggerDisplay("Name {Name}")]
+    public class ObjectInfo//:DynamicObject 
     {
+        private readonly List<string> _knownContainers= new List<string>{"trash"};
         public string Name { get; set; }
+
+        public string ETag { get; set; }
+
         public string Hash { get; set; }
+
+        public string X_Object_Hash { get { return Hash; } set { Hash = value; } }
+
+        [JsonProperty("x_object_uuid")]
+        public string UUID { get; set; }
+
         public long Bytes { get; set; }
         public string Content_Type { get; set; }
         public DateTime Last_Modified { get; set; }
@@ -30,28 +88,134 @@ namespace Pithos.Interfaces
                 ExtractKnownExtensions();
             }
         }
+        
+        
+        private Dictionary<string, string> _permissions=new Dictionary<string, string>();
+        [JsonProperty("x_object_sharing")]
+        [JsonConverter(typeof(PermissionConverter))]
+        public Dictionary<string, string> Permissions
+        {
+            get { return _permissions; }
+            set
+            {
+                _permissions = value;                
+            }
+        }
 
+        /// <summary>
+        /// Version number
+        /// </summary>
+        [JsonProperty("x_object_version")]
         public long? Version { get; set; }
-        public DateTime? VersionTimeStamp { get; set; }
+
+
+        /// <summary>
+        /// Shared object permissions can be Read or Write
+        /// </summary>
+        [JsonProperty("x_object_allowed_to")]
+        public string AllowedTo { get; set; }
+
+
+        /// <summary>
+        /// Version timestamp
+        /// </summary>
+        [JsonProperty("X_Object_Version_Timestamp"), JsonConverter(typeof(PithosDateTimeConverter))]
+        public DateTime? VersionTimestamp { get; set; }
+
+        [JsonProperty("X_Object_Modified_By")]
+        public string ModifiedBy { get; set; }
+
 
         public Stream Stream { get; set; }
 
 
+        public Uri StorageUri { get; set; }
+
+        public string Account { get; set; }
+
+        public string Container { get; set; }
+
+        public Uri Uri
+        {
+            get
+            {
+                var relativeUrl=String.Format("{0}/{1}/{2}",Account, Container,Name);
+                return StorageUri==null 
+                    ? new Uri(relativeUrl,UriKind.Relative) 
+                    : new Uri(StorageUri, relativeUrl);
+            }
+        }
+
+        public string ContendDisposition { get; set; }
+
+        public string ContentEncoding { get; set; }
+
+        public string Manifest { get; set; }
+        
+        public bool IsPublic
+        {
+            get { return !String.IsNullOrWhiteSpace(PublicUrl); }
+            set
+            {
+                if (!value)
+                    PublicUrl = null;
+                else if (String.IsNullOrWhiteSpace(PublicUrl))
+                    PublicUrl="true";                
+            }
+        }
+
+        [JsonProperty("X_Object_Public")]
+        public string PublicUrl { get; set; }
+
+        public string PreviousHash { get; set; }
+
+        public ObjectInfo()
+        {}
+
+        public ObjectInfo(string accountPath,string accountName,FileSystemInfo fileInfo)
+        {
+            if (String.IsNullOrWhiteSpace(accountPath))
+                throw new ArgumentNullException("accountPath");
+            if (string.IsNullOrWhiteSpace(accountName))
+                throw new ArgumentNullException("accountName");
+            if (fileInfo == null)
+                throw new ArgumentNullException("fileInfo");
+            Contract.EndContractBlock();
+
+            var relativeUrl = fileInfo.WithProperCapitalization().AsRelativeUrlTo(accountPath);
+            //The first part of the URL is the container
+            var slashIndex = relativeUrl.IndexOf('/');
+            var container = relativeUrl.Substring(0, slashIndex);
+            //The second is the file's url relative to the container
+            var fileUrl = relativeUrl.Substring(slashIndex + 1);
+
+            Account = accountName;
+            Container = container;
+            Name = fileUrl; 
+        }
+
+
         private void ExtractKnownExtensions()
         {
-            Version=GetLong("X-Object-Version");
-            VersionTimeStamp = GetTimestamp("X-Object-Version-TimeStamp");
+            Version=GetLong(KnownExtensions.X_Object_Version);
+            VersionTimestamp = GetTimestamp(KnownExtensions.X_Object_Version_Timestamp);
+            ModifiedBy = GetString(KnownExtensions.X_Object_Modified_By);
         }
 
+        private string GetString(string name)
+        {            
+            string value;
+            _extensions.TryGetValue(name, out value);
+            return value ;                        
+        }
+        
         private long? GetLong(string name)
         {
             string version;
             long value;
-            if (_extensions.TryGetValue(name, out version) && long.TryParse(version, out value))
-            {
-                return value;
-            }
-            return null;
+            return _extensions.TryGetValue(name, out version) && long.TryParse(version, out value)
+                       ? (long?) value
+                       : null;
         }
 
         private DateTime? GetTimestamp(string name)
@@ -73,7 +237,155 @@ namespace Pithos.Interfaces
             Hash = String.Empty,
             Bytes = 0,
             Content_Type = String.Empty,
-            Last_Modified = DateTime.MinValue
+            Last_Modified = DateTime.MinValue,
+            Exists=false
         };
+
+        private bool _exists=true;
+
+        public bool Exists
+        {
+            get {
+                return _exists;
+            }
+            set {
+                _exists = value;
+            }
+        }
+
+
+        public string RelativeUrlToFilePath(string currentAccount)
+        {
+            if (Name==null)
+                throw new InvalidOperationException("Name can't be null");
+            if (String.IsNullOrWhiteSpace(currentAccount))
+                throw new ArgumentNullException("currentAccount");
+            Contract.EndContractBlock();
+
+            if (this == Empty)
+                return String.Empty;
+
+            var unescaped = Uri.UnescapeDataString(Name);
+            var path = unescaped.Replace("/", "\\");
+            var pathParts=new Stack<string>();
+            pathParts.Push(path);
+            if (!String.IsNullOrWhiteSpace(Container) && !_knownContainers.Contains(Container))
+                pathParts.Push(Container);
+            if (!currentAccount.Equals(Account, StringComparison.InvariantCultureIgnoreCase))
+            {
+                if (Account != null)
+                {
+                    pathParts.Push(Account);
+                    pathParts.Push(FolderConstants.OthersFolder);
+                }
+            }
+            var finalPath=Path.Combine(pathParts.ToArray());
+            return finalPath;
+        }
+
+/*
+        public override bool TrySetMember(SetMemberBinder binder, object value)
+        {
+            if (binder.Name.StartsWith("x_object_meta"))
+            {
+                Tags[binder.Name] = value.ToString();
+            }
+            return false;
+        }
+*/
+
+        public string GetPermissionString()
+        {
+            if (Permissions==null)
+                throw new InvalidOperationException();
+            Contract.EndContractBlock();
+
+            if (Permissions.Count == 0)
+                return "~";
+            var permissionBuilder = new StringBuilder();
+            var groupings = Permissions.GroupBy(pair => pair.Value.Trim(), pair => pair.Key.Trim());
+            foreach (var grouping in groupings)
+            {
+                permissionBuilder.AppendFormat("{0}={1};", grouping.Key, String.Join(",", grouping));
+            }
+            var permissions = Uri.EscapeDataString(permissionBuilder.ToString().Trim(';'));
+            return permissions;
+        }
+
+        public void SetPermissions(string permissions)
+        {
+            if (String.IsNullOrWhiteSpace(permissions))
+                return;
+            
+            Permissions = PermissionConverter.ParsePermissions(permissions);
+        }
+
+        //The previous values that correspond to a NoModification object
+        //have the same account, container and possibly the same folder
+        public bool CorrespondsTo(ObjectInfo other)
+        {
+            return other.Account == this.Account
+                   && other.Container == this.Container
+                   && (this.Name == null || other.Name.StartsWith(this.Name));
+        }
+
+        public bool IsWritable(string account)
+        {
+            //If the Allowed To header has no value, try to determine the Share permissions
+            if (AllowedTo == null)
+            {
+                //If this file has no permissions defined, we can probably write it
+                //This case should occur only when the info comes from a listing of the user's own files
+                if (Permissions == null || Permissions.Count == 0)
+                    return true;
+                string perms;
+
+                //Do we have an explicit write share to this account?
+                return Permissions.TryGetValue(account, out perms) 
+                    && perms.Equals("write",StringComparison.InvariantCultureIgnoreCase);
+                
+            }
+            //Otherwise return the permissions specified by AllowedTo
+            return AllowedTo.Equals("write",StringComparison.InvariantCultureIgnoreCase) ;
+        }
+
+        public ObjectInfo Previous { get; private set; }
+
+        public bool IsDirectory
+        {
+            get
+            {
+                if (Content_Type == null)
+                    return false;
+                if (Content_Type.StartsWith(@"application/directory",StringComparison.InvariantCultureIgnoreCase))
+                    return true;
+                if (Content_Type.StartsWith(@"application/folder",StringComparison.InvariantCultureIgnoreCase))
+                    return true;
+                return false;
+            }
+        }
+
+        public Uri AccountKey
+        {
+            get { return new Uri(StorageUri,"../" + Account); }
+        }
+
+        public ObjectInfo SetPrevious(ObjectInfo previous)
+        {            
+            Previous = previous;
+            PreviousHash = previous.Hash;
+            return this;
+        }
+
+        public bool? IsShared
+        {
+            get
+            {
+                if (Uri == null || StorageUri == null)
+                    return null;
+                var isShared = !Uri.ToString().StartsWith(StorageUri.ToString());
+                return isShared;
+            }
+        }
     }
 }
\ No newline at end of file