/// <summary>
        ///		Write data item to repository
        /// </summary>
        /// <param name="dataItem">
        ///		Data item to write. Must be serializable.
        /// </param>
        /// <remarks>
        ///		The <paramref name="dataItem"/> needs to be serializable employing either automatic or custom serialization. Automatic serialization
        ///		requires only <see cref="SerializableAttribute"/>, but it may be difficult to implement versioning. With custom serialization
        ///		the class has to implement the <see cref="ISerializable"/> interface and a special constructor. Note that no immediate check is performed
        ///		in this method and if the <paramref name="dataItem"/> is not serializable the subsequent flushing of the data to disk may fail.
        ///		Not thread safe, must not be used in more than 1 thread at once.
        /// </remarks>
        public void Write(IDataItem dataItem)
        {
            CheckNotDisposed();
            Check.DoRequireArgumentNotNull(dataItem, "dataItem");

            Check.DoRequire(dataItem.RelativePath != null, "RelativePath must not be null");

            Check.Invariant(_activeDataRouter != null);

            // if new transaction scope is created for ambient managed here and the transaction gets disposed
            using (var scope = _transactionManager.GetLazyTransactionScope())
            {
                DirectSingleFolderWriter targetWriter;
                // relative path as directed by active router
                string originalRelativePath = _activeDataRouter.GetRelativePath(dataItem);

                // have a look at exact match in the cache
                targetWriter = GetExistingWriterByRelativePath(originalRelativePath);
                if (null == targetWriter)
                {
                    // no exact match, let's normalise path
                    string normalizedRelativePath = RepositoryFolder.GetFolderPathKey(originalRelativePath);

                    if (!string.Equals(normalizedRelativePath, originalRelativePath, StringComparison.Ordinal))
                    {
                        targetWriter = GetExistingWriterByRelativePath(normalizedRelativePath);
                    }
                    // if normilised is the same as original  or not same but still there's no writer in cache
                    if (null == targetWriter)
                    {
                        // writing to the folder for the first time
                        // using original relative path to preserve casing when creating
                        IRepositoryFolder targetFolder = GetSubfolder(originalRelativePath, this.AllowSubfoldersCreation);

                        if (null == targetFolder)
                        {
                            throw FolderNotFoundExceptionHelper.GetForWriter(this.Folder, originalRelativePath);
                        }

                        targetWriter = CreateWriter(targetFolder, normalizedRelativePath);
                    }
                }

                Check.Ensure(targetWriter.TrackUnsavedItems == this.TrackUnsavedItems);

                targetWriter.Write(dataItem);

                OnDataItemAdded(targetWriter.Folder, targetWriter.CurrentFile, dataItem);

                scope.Complete();
            }
        }
        public void GetFolderPathKeyTest()
        {
            string relativePath = string.Empty;
            string expected     = string.Empty;
            string actual;

            actual = RepositoryFolder.GetFolderPathKey(relativePath);
            Assert.AreEqual(expected, actual);

            relativePath = @"\ara\para\";
            expected     = "ara/para";
            actual       = RepositoryFolder.GetFolderPathKey(relativePath);
            Assert.AreEqual(expected, actual);

            relativePath = @"/ara/para";
            actual       = RepositoryFolder.GetFolderPathKey(relativePath);
            Assert.AreEqual(expected, actual);
        }
 /// <summary>
 ///		Remove the specific folder reading position from this position.
 /// </summary>
 /// <param name="folderLogicalPath">
 ///		Target folder logical path (<see cref="IRepositoryFolder.LogicalPath"/>).
 /// </param>
 /// <returns>
 ///		true - the specific folder position was removed from this position
 ///		false - this position does not contain specific position for a folder with the specified logical path
 /// </returns>
 public bool Remove(string folderLogicalPath)
 {
     Check.DoRequireArgumentNotNull(folderLogicalPath, "folderLogicalPath");
     return(_positionsDictionary.Remove(RepositoryFolder.GetFolderPathKey(folderLogicalPath)));
 }
 /// <summary>
 ///		Check whether this position contains folder reading position for the specified repository folder.
 /// </summary>
 /// <param name="folderKey">
 ///		Repository folder key (<see cref="IRepositoryFolder.FolderKey"/>).
 /// </param>
 /// <returns>
 ///		bool
 /// </returns>
 public bool ContainsPosition(string folderKey)
 {
     Check.DoRequireArgumentNotNull(folderKey, "folderKey");
     return(_positionsDictionary.ContainsKey(RepositoryFolder.GetFolderPathKey(folderKey)));
 }