/// <summary>
        /// Lists a directory.
        /// </summary>
        /// <param name="dir">The path of the directory.</param>
        /// <returns>The result.</returns>
        /// <exception cref="DirectoryNotFoundException">
        /// <paramref name="dir" /> does not exist.
        /// </exception>
        public ListCloudDirectoryResult ListDirectory(IEnumerable <char> dir)
        {
            string path = (StringHelper.AsString(dir) ?? string.Empty).Trim();

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

            HttpWebRequest httpRequest = this.Server.CreateHttpRequest(this.GetBaseUri() + "?action=list");

            httpRequest.Method = "GET";

            if (path != null)
            {
                httpRequest.Headers["X-MJKTM-CloudNET-Directory"] = path;
            }

            HttpWebResponse httpResponse;

            try
            {
                httpResponse = (HttpWebResponse)httpRequest.GetResponse();
            }
            catch (WebException wex)
            {
                HttpWebResponse resp = wex.Response as HttpWebResponse;
                if (resp != null)
                {
                    if (resp.StatusCode == HttpStatusCode.NotFound)
                    {
                        throw new DirectoryNotFoundException(path ?? string.Empty);
                    }
                }

                throw;
            }

            using (Stream stream = httpResponse.GetResponseStream())
            {
                using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
                {
                    string json = reader.ReadToEnd().Trim();
                    if (json != string.Empty &&
                        json != "null")
                    {
                        JsonSerializer serializer = new JsonSerializer();

                        using (StringReader strReader = new StringReader(json))
                        {
                            using (JsonTextReader jsonReader = new JsonTextReader(strReader))
                            {
                                ListCloudDirectoryResult result = serializer.Deserialize <ListCloudDirectoryResult>(jsonReader);
                                result.Server = this.Server;

                                // link that server instance with directory items
                                CloudDirectoryCollection dirs = result.Directories;
                                if (dirs != null)
                                {
                                    foreach (CloudDirectory d in dirs)
                                    {
                                        if (d == null)
                                        {
                                            continue;
                                        }

                                        d.Server = this.Server;
                                    }
                                }

                                // link that server instance with file items
                                CloudFileCollection files = result.Files;
                                if (files != null)
                                {
                                    foreach (CloudFile f in files)
                                    {
                                        if (f == null)
                                        {
                                            continue;
                                        }

                                        f.Server = this.Server;
                                    }
                                }

                                return(result);
                            }
                        }
                    }
                }
            }

            // no data availables
            return(null);
        }
            public void Start()
            {
                try
                {
                    if (this.IsRunning)
                    {
                        return;
                    }

                    this.IsRunning = true;
                    this.Errors    = null;

                    this.RaiseEventHandler(this.Started);

                    DirectoryInfo dir = new DirectoryInfo(this.LocalDirectory);

                    CloudDirectoryCollection remoteDirList = this.RemoteDirectory.Directories;
                    DirectoryInfo[]          localDirList  = dir.GetDirectories();

                    CloudFileCollection remoteFileList = this.RemoteDirectory.Files;
                    FileInfo[]          localFileList  = dir.GetFiles();

                    long allItemCount = remoteDirList.Count + localDirList.Length +
                                        remoteFileList.Count + localFileList.Length;
                    long currentItemIndex = -1;

                    Action <string> invokeNextProgressEvent =
                        delegate(string statusText)
                    {
                        double?progress;

                        ++currentItemIndex;
                        if (allItemCount < 1)
                        {
                            progress = 0;
                        }
                        else
                        {
                            progress = (double)currentItemIndex / (double)allItemCount;
                        }

                        this.OnLocalDirectorySyncProgress(progress, statusText);
                    };

                    // directories
                    if (remoteDirList != null)
                    {
                        // check for EXTRA directories
                        foreach (CloudDirectory remoteDir in remoteDirList)
                        {
                            if (this.IsCancelling)
                            {
                                this.OnCanceled();
                                return;
                            }

                            if (remoteDir == null)
                            {
                                invokeNextProgressEvent(null);
                                continue;
                            }

                            invokeNextProgressEvent(string.Format("Check if '{0}' is an EXTRA directory...",
                                                                  remoteDir.Path));

                            // try find matching local directory
                            string        remoteDirName = (remoteDir.Name ?? string.Empty).ToLower().Trim();
                            DirectoryInfo matchingDir   = CollectionHelper.FirstOrDefault(localDirList,
                                                                                          delegate(DirectoryInfo d)
                            {
                                return(d.Name.ToLower().Trim() ==
                                       remoteDirName);
                            });

                            if (matchingDir == null)
                            {
                                // does not exist in source anymore
                                remoteDir.Delete();
                            }
                        }

                        // sync directories
                        foreach (DirectoryInfo localDir in localDirList)
                        {
                            if (this.IsCancelling)
                            {
                                this.OnCanceled();
                                return;
                            }

                            invokeNextProgressEvent(string.Format("Sync directory '{0}'...",
                                                                  localDir.Name));

                            string remotePath = (this.RemoteDirectory.Path ?? string.Empty).Trim();
                            if (remotePath.EndsWith("/") == false)
                            {
                                remotePath += "/";
                            }

                            remotePath += localDir.Name + "/";

                            // create directory if needed
                            {
                                bool doUpdateTimeStamps = false;

                                CloudDirectory matchingDir = remoteDirList[localDir.Name];
                                if (matchingDir == null)
                                {
                                    doUpdateTimeStamps = true;

                                    this.RemoteDirectory
                                    .CreateDirectory(localDir.Name);
                                }
                                else
                                {
                                    if (AreEqual(localDir.CreationTimeUtc, matchingDir.CreationTime) == false ||
                                        AreEqual(localDir.LastWriteTimeUtc, matchingDir.WriteTime) == false)
                                    {
                                        doUpdateTimeStamps = true;
                                    }
                                }

                                // update timestamps
                                if (doUpdateTimeStamps)
                                {
                                    this.RemoteDirectory
                                    .Server
                                    .FileSystem
                                    .UpdateDirectoryCreationTime(remotePath, localDir.CreationTimeUtc);

                                    this.RemoteDirectory
                                    .Server
                                    .FileSystem
                                    .UpdateDirectoryWriteTime(remotePath, localDir.LastWriteTimeUtc);
                                }
                            }

                            if (this.SyncRecursively)
                            {
                                try
                                {
                                    this.RemoteDirectory
                                    .Server
                                    .FileSystem
                                    .ListDirectory(remotePath)
                                    .SyncWithLocalDirectory(localDir, true);
                                }
                                catch (WebException wex)
                                {
                                    bool rethrowException = true;

                                    HttpWebResponse resp = wex.Response as HttpWebResponse;
                                    if (resp != null)
                                    {
                                        if (resp.StatusCode == HttpStatusCode.NotFound)
                                        {
                                            // does not exist => needs to be created

                                            rethrowException = false;
                                            this.RemoteDirectory.CreateDirectory(dir.Name);
                                        }
                                    }

                                    if (rethrowException)
                                    {
                                        throw;
                                    }
                                }
                            }
                        }
                    }

                    // files
                    if (remoteFileList != null)
                    {
                        // check for EXTRA files
                        foreach (CloudFile remoteFile in remoteFileList)
                        {
                            if (this.IsCancelling)
                            {
                                this.OnCanceled();
                                return;
                            }

                            if (remoteFile == null)
                            {
                                invokeNextProgressEvent(null);
                                continue;
                            }

                            invokeNextProgressEvent(string.Format("Check if '{0}' is an EXTRA file...",
                                                                  remoteFile.Path));
                            // try find matching local file
                            string   remoteFileName = (remoteFile.Name ?? string.Empty).ToLower().Trim();
                            FileInfo matchingFile   = CollectionHelper.FirstOrDefault(localFileList,
                                                                                      delegate(FileInfo f)
                            {
                                return(f.Name.ToLower().Trim() ==
                                       remoteFileName);
                            });

                            if (matchingFile == null)
                            {
                                // does not exist in source anymore
                                remoteFile.Delete();
                            }
                        }

                        // sync files
                        foreach (FileInfo localFile in localFileList)
                        {
                            if (this.IsCancelling)
                            {
                                this.OnCanceled();
                                return;
                            }

                            invokeNextProgressEvent(string.Format("Sync file '{0}'...",
                                                                  localFile.Name));

                            string remotePath = (this.RemoteDirectory.Path ?? string.Empty).Trim();
                            if (remotePath.EndsWith("/") == false)
                            {
                                remotePath += "/";
                            }

                            remotePath += localFile.Name;

                            try
                            {
                                bool doUploadFile       = true;
                                bool doUpdateTimeStamps = false;

                                CloudFile matchingFile = remoteFileList[localFile.Name];
                                if (matchingFile != null)
                                {
                                    if (AreEqual(localFile.LastWriteTimeUtc, matchingFile.WriteTime) &&
                                        localFile.Length == matchingFile.Size)
                                    {
                                        // same file, no need to upload

                                        doUploadFile = false;
                                    }
                                    else
                                    {
                                    }

                                    if (AreEqual(localFile.CreationTimeUtc, matchingFile.CreationTime) == false ||
                                        AreEqual(localFile.LastWriteTimeUtc, matchingFile.WriteTime) == false)
                                    {
                                        doUpdateTimeStamps = true;
                                    }
                                }

                                if (doUploadFile)
                                {
                                    doUpdateTimeStamps = true;

                                    using (FileStream stream = localFile.OpenRead())
                                    {
                                        this.RemoteDirectory
                                        .UploadFile(localFile.Name,
                                                    stream);
                                    }
                                }

                                // update timestamps
                                if (doUpdateTimeStamps)
                                {
                                    this.RemoteDirectory
                                    .Server
                                    .FileSystem
                                    .UpdateFileCreationTime(remotePath, localFile.CreationTimeUtc);

                                    this.RemoteDirectory
                                    .Server
                                    .FileSystem
                                    .UpdateFileWriteTime(remotePath, localFile.LastWriteTimeUtc);
                                }
                            }
                            catch (WebException wex)
                            {
                                bool rethrowException = true;

                                HttpWebResponse resp = wex.Response as HttpWebResponse;
                                if (resp != null)
                                {
                                    if (resp.StatusCode == HttpStatusCode.NotFound)
                                    {
                                        // does not exist => needs to be created

                                        rethrowException = false;
                                        this.RemoteDirectory.CreateDirectory(dir.Name);
                                    }
                                }

                                if (rethrowException)
                                {
                                    throw;
                                }
                            }
                        }
                    }

                    this.OnLocalDirectorySyncProgress(1, "Synchronization completed");

                    this.Errors = new Exception[0];
                }
                catch (Exception ex)
                {
                    this.Errors = new Exception[] { ex };
                }
                finally
                {
                    this.IsRunning    = false;
                    this.IsCancelling = false;
                }
            }