internal IEnumerable <object> ListItems(string path)
        {
            var result = AzureTablePathResolver.ResolvePath(this.Client, path);

            switch (result.PathType)
            {
            case PathType.AzureTableRoot:
                return(ListTables());

            case PathType.AzureTableQuery:
                return(ListEntities(result.Table, result.Query));

            default:
                return(null);
            }
        }
        public override void RemoveItem(string path, bool recurse)
        {
            var r = AzureTablePathResolver.ResolvePath(this.Client, path);

            if (r.Parts.Count == 1) //removing table
            {
                var table = this.Client.GetTableReference(r.Parts.Last());
                table.Delete();
                return;
            }
            else if (r.PathType != PathType.Invalid && r.Parts.Count > 1)
            {
                var entities = ListEntities(r.Table, r.Query);

                foreach (var e in entities)
                {
                    var o = TableOperation.Delete(e);
                    r.Table.Execute(o);
                    this.RootProvider.WriteWarning(string.Format("Entity {0} # {1} is removed.", e.PartitionKey, e.RowKey));
                }
                return;
            }

            if (r.PathType == PathType.Invalid)
            {
                var propertyName = Path.GetFileName(path);
                var entityPath   = PathResolver.GetParentPath(path);
                r = AzureTablePathResolver.ResolvePath(this.Client, entityPath); //override path

                var entities = ListEntities(r.Table, r.Query);

                foreach (var e in entities)
                {
                    if (e.Properties.ContainsKey(propertyName))
                    {
                        e.Properties.Remove(propertyName);
                        var o = TableOperation.Replace(e);
                        r.Table.Execute(o);
                        this.RootProvider.WriteWarning(string.Format("Entity {0} # {1} is updated.", e.PartitionKey, e.RowKey));
                    }
                }
                return;
            }

            this.RootProvider.WriteWarning("Nothing to do");
        }
        public override void GetChildNames(string path, ReturnContainers returnContainers)
        {
            var r = AzureTablePathResolver.ResolvePath(this.Client, path);

            switch (r.PathType)
            {
            case PathType.AzureTableRoot:
                var tables = ListTables();
                foreach (var table in tables)
                {
                    this.RootProvider.WriteItemObject(table.Name, path, true);
                }
                break;

            default:
                break;
            }
        }
        public override bool IsItemContainer(string path)
        {
            var parts = PathResolver.SplitPath(path);

            if (parts.Count == 0)
            {
                return(true);
            }

            try
            {
                var r = AzureTablePathResolver.ResolvePath(this.Client, path);
                return(r.Exists());
            }
            catch (Exception)
            {
                return(false);
            }
        }
        internal void CopyTo(string path, AzureTableServiceDriveInfo target, string copyPath, bool deleteOriginal = false)
        {
            var parts = PathResolver.SplitPath(path);

            if (parts.Count == 0)
            {
                this.RootProvider.WriteWarning("Not supported to copy multiple tables.");
                return;
            }

            var targetRef = AzureTablePathResolver.ResolvePath(target.Client, copyPath);

            if (targetRef.PathType == PathType.AzureTableRoot)
            {
                this.RootProvider.WriteWarning("Must specify the target table.");
                return;
            }

            var items = this.ListItems(path);

            foreach (ITableEntity i in items)
            {
                var o = TableOperation.InsertOrReplace(i);
                targetRef.Table.Execute(o);
                this.RootProvider.WriteWarning(string.Format("Entity {0} # {1} is inserted", i.PartitionKey, i.RowKey));
            }

            if (deleteOriginal)
            {
                var sourceRef = AzureTablePathResolver.ResolvePath(this.Client, path);
                foreach (ITableEntity i in items)
                {
                    var o = TableOperation.Delete(i);
                    sourceRef.Table.Execute(o);
                    this.RootProvider.WriteWarning(string.Format("Source Entity {0} # {1} is deleted", i.PartitionKey, i.RowKey));
                }
            }
        }
        public override bool HasChildItems(string path)
        {
            var r = AzureTablePathResolver.ResolvePath(this.Client, path);

            return(r.Exists());
        }
        /// <summary>
        /// It creates a table or a table entity, or update table entities
        /// </summary>
        public override void NewItem(
            string path,
            string type,
            object newItemValue)
        {
            var r = AzureTablePathResolver.ResolvePath(this.Client, path);

            if (r.Parts.Count == 0)
            {
                this.RootProvider.WriteWarning("Nothing to create.");
                return;
            }

            if (type == null)
            {
                type = string.Empty;
            }

            switch (type.ToLowerInvariant())
            {
            case "entity":
            {
                var keys = newItemValue as string;
                if (keys == null || !keys.Contains("#"))
                {
                    this.RootProvider.WriteWarning("It requires value formatted as <PartitionKey>#<RowKey>");
                    return;
                }

                var parts = keys.Split('#');
                var pk    = parts[0];
                var rk    = parts[1];

                var e = new TableEntity(pk, rk);
                var o = TableOperation.Insert(e);
                r.Table.Execute(o);
                break;
            }

            case "insertentity":
                CreateEntity(r, newItemValue, TableOperation.Insert);
                break;

            case "replaceentity":
                CreateEntity(r, newItemValue, TableOperation.Replace);
                break;

            case "mergeentity":
                CreateEntity(r, newItemValue, TableOperation.Merge);
                break;

            case "insertorreplaceentity":
                CreateEntity(r, newItemValue, TableOperation.InsertOrReplace);
                break;

            case "insertormergeentity":
                CreateEntity(r, newItemValue, TableOperation.InsertOrMerge);
                break;

            case "sastoken":
            {
                var parts = PathResolver.SplitPath(path);
                if (parts.Count > 0)
                {
                    var tableName  = parts[0];
                    var table      = this.Client.GetTableReference(tableName);
                    var policyName = string.Empty;
                    var policy     = CreateTablePermission(newItemValue as string, ref policyName);

                    if (policyName != string.Empty)         //policy-based SAStoken
                    {
                        var token = table.GetSharedAccessSignature(policy, policyName);
                        this.RootProvider.WriteItemObject(token, path, false);
                    }
                    else
                    {
                        var token = table.GetSharedAccessSignature(policy);
                        this.RootProvider.WriteItemObject(token, path, false);
                    }
                }
            }

            break;

            case "policy":
            {
                var parts = PathResolver.SplitPath(path);
                if (parts.Count > 0)
                {
                    var tableName         = parts[0];
                    var table             = this.Client.GetTableReference(tableName);
                    var policyName        = parts.Last();
                    var policyPlaceHolder = string.Empty;
                    var policy            = CreateTablePermission(newItemValue as string, ref policyPlaceHolder);

                    var permissions = table.GetPermissions();
                    if (permissions.SharedAccessPolicies.ContainsKey(policyName))
                    {
                        if (!this.RootProvider.ShouldContinue(string.Format("Should continue to update existing policy {0}?", policyName), "Policy existed"))
                        {
                            this.RootProvider.WriteWarning("Cancelled");
                            return;
                        }
                        else
                        {
                            permissions.SharedAccessPolicies[policyName] = policy;
                        }
                    }
                    else
                    {
                        permissions.SharedAccessPolicies.Add(policyName, policy);
                    }

                    table.SetPermissions(permissions);

                    this.RootProvider.WriteWarning(string.Format("Policy {0} updated or added.", policyName));
                }
            }
            break;

            default:
                if (r.Parts.Count == 1)     //create a table
                {
                    r.Table.Create();
                    this.RootProvider.WriteWarning("Table is created.");
                }
                else
                {
                    UpdateEntities(path, type, newItemValue);
                }
                break;
            }
        }
        private void UpdateEntities(string path, string type, object newItemValue)
        {
            //update existing entities
            this.RootProvider.WriteWarning("update existing entities");
            var propertyName = Path.GetFileName(path);
            var entityPath   = PathResolver.GetParentPath(path);
            var r            = AzureTablePathResolver.ResolvePath(this.Client, entityPath); //override path
            var isNull       = newItemValue == null;

            var entities = this.ListEntities(r.Table, r.Query);

            foreach (DynamicTableEntity e in entities)
            {
                if (isNull)
                {
                    //removing the property and save
                    if (e.Properties.ContainsKey(propertyName))
                    {
                        e.Properties.Remove(propertyName);
                        var op = TableOperation.InsertOrReplace(e);
                        r.Table.Execute(op);
                        this.RootProvider.WriteWarning(string.Format("Property {2} is removed from entity {0} # {1}.", e.PartitionKey, e.RowKey, propertyName));
                    }
                    else
                    {
                        this.RootProvider.WriteWarning(string.Format("Skipping entity {0} # {1} is .", e.PartitionKey, e.RowKey));
                    }

                    continue;
                }

                //Type choice:
                //0. if specified explicitly in type
                //1. if there is existing property
                //2. default to string

                var targetType = EdmType.String;

                if (!string.IsNullOrEmpty(type))
                {
                    if (!Enum.TryParse <EdmType>(type, true, out targetType))
                    {
                        throw new Exception("Failed to parse type " + type + ", valid values are:" + string.Join(",", Enum.GetNames(typeof(EdmType))));
                    }
                }
                else if (e.Properties.ContainsKey(propertyName))
                {
                    targetType = e.Properties[propertyName].PropertyType;
                }

                //Check property existence:
                var existing = e.Properties.ContainsKey(propertyName);

                //set value
                switch (targetType)
                {
                case EdmType.String:
                    if (existing)
                    {
                        e.Properties[propertyName].StringValue = newItemValue.ToString();
                    }
                    else
                    {
                        var value = new EntityProperty(newItemValue.ToString());
                        e.Properties.Add(propertyName, value);
                    }
                    break;

                case EdmType.Binary:
                    var bytes = newItemValue as byte[];
                    if (existing)
                    {
                        if (bytes != null)
                        {
                            e.Properties[propertyName].BinaryValue = bytes;
                        }
                        else
                        {
                            e.Properties[propertyName].BinaryValue = Utils.FromBase64(newItemValue.ToString());
                        }
                    }
                    else
                    {
                        if (bytes != null)
                        {
                            var value = new EntityProperty(bytes);
                            e.Properties.Add(propertyName, value);
                        }
                        else
                        {
                            var value = new EntityProperty(newItemValue.ToString());
                            e.Properties.Add(propertyName, value);
                        }
                    }
                    break;

                case EdmType.Boolean:
                    var boolValue = true as bool?;


                    // Check target value:
                    // 1. the input value is a bool
                    // 2. the input value is a string, can be parsed to be a bool
                    if (newItemValue is bool)
                    {
                        boolValue = (bool)newItemValue;
                    }
                    else if (newItemValue is string)
                    {
                        var boolString = newItemValue as string;
                        var tempValue  = true;
                        if (Boolean.TryParse(boolString, out tempValue))
                        {
                            boolValue = tempValue;
                        }
                        else
                        {
                            throw new Exception("Failed to parse boolean value " + boolString);
                        }
                    }

                    //set value
                    if (existing)
                    {
                        e.Properties[propertyName].BooleanValue = boolValue;
                    }
                    else
                    {
                        var value = new EntityProperty(boolValue);
                        e.Properties.Add(propertyName, value);
                    }

                    break;

                case EdmType.DateTime:
                    var dateTime = null as DateTime?;

                    // Check target value:
                    // 1. the input value is a DateTime
                    // 2. the input value is a string, can be parsed to be a DateTime
                    if (newItemValue is DateTime)
                    {
                        dateTime = (DateTime)newItemValue;
                    }
                    else if (newItemValue is string)
                    {
                        var dateTimeString = newItemValue as string;
                        var tempDateTime   = DateTime.Now;
                        if (DateTime.TryParse(dateTimeString, out tempDateTime))
                        {
                            dateTime = tempDateTime;
                        }
                        else
                        {
                            throw new Exception("Failed to parse DateTime value " + dateTimeString);
                        }
                    }

                    //set value
                    if (existing)
                    {
                        e.Properties[propertyName].DateTime = dateTime;
                    }
                    else
                    {
                        var value = new EntityProperty(dateTime);
                        e.Properties.Add(propertyName, value);
                    }

                    break;

                case EdmType.Double:
                    var doubleValue = null as double?;

                    if (newItemValue is double)
                    {
                        doubleValue = (double)newItemValue;
                    }
                    else if (newItemValue is string)
                    {
                        var doubleString = newItemValue as string;
                        var tempValue    = 0.0;
                        if (Double.TryParse(doubleString, out tempValue))
                        {
                            doubleValue = tempValue;
                        }
                        else
                        {
                            throw new Exception("Failed to parse double value " + doubleString);
                        }
                    }

                    //set value
                    if (existing)
                    {
                        e.Properties[propertyName].DoubleValue = doubleValue;
                    }
                    else
                    {
                        var value = new EntityProperty(doubleValue);
                        e.Properties.Add(propertyName, value);
                    }

                    break;

                case EdmType.Guid:
                    var guidValue = null as Guid?;

                    if (newItemValue is Guid)
                    {
                        guidValue = (Guid)newItemValue;
                    }
                    else
                    {
                        var guidString = newItemValue as string;
                        var tempValue  = Guid.NewGuid();
                        if (Guid.TryParse(guidString, out tempValue))
                        {
                            guidValue = tempValue;
                        }
                        else
                        {
                            throw new Exception("Failed to parse Guid value " + guidString);
                        }
                    }

                    //set value
                    if (existing)
                    {
                        e.Properties[propertyName].GuidValue = guidValue;
                    }
                    else
                    {
                        var value = new EntityProperty(guidValue);
                        e.Properties.Add(propertyName, value);
                    }
                    break;

                case EdmType.Int32:
                    var int32Value = null as int?;

                    if (newItemValue is int)
                    {
                        int32Value = (int)newItemValue;
                    }
                    else
                    {
                        var int32String = newItemValue as string;
                        var tempValue   = 0;
                        if (int.TryParse(int32String, out tempValue))
                        {
                            int32Value = tempValue;
                        }
                        else
                        {
                            throw new Exception("Failed to parse int32 value " + int32String);
                        }
                    }

                    //set value
                    if (existing)
                    {
                        e.Properties[propertyName].Int32Value = int32Value;
                    }
                    else
                    {
                        var value = new EntityProperty(int32Value);
                        e.Properties.Add(propertyName, value);
                    }
                    break;

                case EdmType.Int64:
                    var int64Value = null as Int64?;

                    if (newItemValue is Int64)
                    {
                        int64Value = (Int64)newItemValue;
                    }
                    else
                    {
                        var int64String = newItemValue as string;
                        var tempValue   = (Int64)0;
                        if (Int64.TryParse(int64String, out tempValue))
                        {
                            int64Value = tempValue;
                        }
                        else
                        {
                            throw new Exception("Failed to parse int64 value " + int64String);
                        }
                    }

                    //set value
                    if (existing)
                    {
                        e.Properties[propertyName].Int64Value = int64Value;
                    }
                    else
                    {
                        var value = new EntityProperty(int64Value);
                        e.Properties.Add(propertyName, value);
                    }
                    break;
                } //end of switch

                var o = TableOperation.Merge(e);
                r.Table.Execute(o);
                this.RootProvider.WriteWarning(string.Format("Entity {0} # {1} is merged.", e.PartitionKey, e.RowKey));
            }
        }