/// <summary>
        /// Gets the result item list.
        /// </summary>
        /// <param name="cacheIndexInternal">The cache index internal.</param>
        /// <param name="itemPositionList">The item position list.</param>
        /// <returns>List of ResultItems</returns>
        internal static List<ResultItem> GetResultItemList(CacheIndexInternal cacheIndexInternal, IEnumerable<int> itemPositionList)
        {
            List<ResultItem> resultItemList = new List<ResultItem>();

            foreach (int itemPosition in itemPositionList)
            {
                resultItemList.Add(new ResultItem(cacheIndexInternal.InDeserializationContext.IndexId,
                    cacheIndexInternal.GetItem(itemPosition).ItemId,
                    null,
                    InternalItemAdapter.ConvertToTagDictionary(cacheIndexInternal.GetItem(itemPosition).TagList, cacheIndexInternal.InDeserializationContext)));
            }

            return resultItemList;
        }
        /// <summary>
        /// Gets the result item list.
        /// </summary>
        /// <param name="cacheIndexInternal">The cache index internal.</param>
        /// <param name="itemPositionList">The item position list.</param>
        /// <returns>List of ResultItems</returns>
        internal static List <ResultItem> GetResultItemList(CacheIndexInternal cacheIndexInternal, IEnumerable <int> itemPositionList)
        {
            List <ResultItem> resultItemList = new List <ResultItem>();

            foreach (int itemPosition in itemPositionList)
            {
                resultItemList.Add(new ResultItem(cacheIndexInternal.InDeserializationContext.IndexId,
                                                  cacheIndexInternal.GetItem(itemPosition).ItemId,
                                                  null,
                                                  InternalItemAdapter.ConvertToTagDictionary(cacheIndexInternal.GetItem(itemPosition).TagList, cacheIndexInternal.InDeserializationContext)));
            }

            return(resultItemList);
        }
        /// <summary>
        /// Gets the index data item list.
        /// </summary>
        /// <param name="cacheIndexInternal">The cache index internal.</param>
        /// <param name="offset">The offset.</param>
        /// <param name="itemNum">If 0 gets all items.</param>
        /// <returns>List of IndexDataItems</returns>
        internal static List<IndexDataItem> GetIndexDataItemList(CacheIndexInternal cacheIndexInternal, int offset, int itemNum)
        {
            if (itemNum == Int32.MaxValue)
            {
                itemNum = cacheIndexInternal.Count;
            }

            List<IndexDataItem> resultItemList = new List<IndexDataItem>(itemNum);

            if (cacheIndexInternal.Count >= offset)
            {
                for (int i = offset - 1; i < cacheIndexInternal.Count && resultItemList.Count < itemNum; i++)
                {
                    resultItemList.Add(new IndexDataItem(cacheIndexInternal.GetItem(i).ItemId,
                        InternalItemAdapter.ConvertToTagDictionary(cacheIndexInternal.GetItem(i).TagList, cacheIndexInternal.InDeserializationContext)));
                }
            }
            return resultItemList;
        }
        /// <summary>
        /// Gets the index data item list.
        /// </summary>
        /// <param name="cacheIndexInternal">The cache index internal.</param>
        /// <param name="offset">The offset.</param>
        /// <param name="itemNum">If 0 gets all items.</param>
        /// <returns>List of IndexDataItems</returns>
        internal static List <IndexDataItem> GetIndexDataItemList(CacheIndexInternal cacheIndexInternal, int offset, int itemNum)
        {
            if (itemNum == Int32.MaxValue)
            {
                itemNum = cacheIndexInternal.Count;
            }

            List <IndexDataItem> resultItemList = new List <IndexDataItem>(itemNum);

            if (cacheIndexInternal.Count >= offset)
            {
                for (int i = offset - 1; i < cacheIndexInternal.Count && resultItemList.Count < itemNum; i++)
                {
                    resultItemList.Add(new IndexDataItem(cacheIndexInternal.GetItem(i).ItemId,
                                                         InternalItemAdapter.ConvertToTagDictionary(cacheIndexInternal.GetItem(i).TagList, cacheIndexInternal.InDeserializationContext)));
                }
            }
            return(resultItemList);
        }
        /// <summary>
        /// Repositions the index item.
        /// </summary>
        /// <param name="cacheIndexInternal">The cache index internal.</param>
        /// <param name="indexInfo">The index info.</param>
        /// <param name="addItem">The add item.</param>
        /// <param name="searchIndex">Index of the search.</param>
        /// <param name="internalItem">The internal item.</param>
        /// <param name="comparer">The comparer.</param>
        private static void RepositionIndexItem(CacheIndexInternal cacheIndexInternal, Index indexInfo, IndexDataItem addItem, int searchIndex, InternalItem internalItem, InternalItemComparer comparer)
        {
            // Remove the Item from current position
            cacheIndexInternal.DeleteItem(searchIndex, false);

            // Determine where to insert the Item
            int newSearchIndex = cacheIndexInternal.GetInsertPosition(addItem, indexInfo.PrimarySortInfo.SortOrderList[0].SortBy, comparer);

            // insert the item at new position
            cacheIndexInternal.InsertItem(internalItem, newSearchIndex, false);
        }
        /// <summary>
        /// Updates the existing index item.
        /// </summary>
        /// <param name="clientIndex">Index from the client.</param>
        /// <param name="cacheIndexInternal">The cache index internal.</param>
        /// <param name="indexInfo">The index info.</param>
        /// <param name="addItem">The add item.</param>
        /// <param name="searchIndex">Index to search.</param>
        /// <param name="storeContext">The store context.</param>
        /// <param name="comparer">The comparer.</param>
        private static void UpdateExistingIndexItem(CacheIndex clientIndex, CacheIndexInternal cacheIndexInternal, Index indexInfo, IndexDataItem addItem, int searchIndex, IndexStoreContext storeContext, InternalItemComparer comparer)
        {
            InternalItem internalItem = cacheIndexInternal.InternalItemList[searchIndex];
            if (clientIndex.TargetIndexName != null) //Save to single index
            {
                if (addItem.Tags != null && addItem.Tags.Count > 0)
                {
                    bool reposition = IsRepositioningOfIndexItemRequired(indexInfo, addItem, internalItem);

                    // Update all tags on the internal item
                    foreach (KeyValuePair<string, byte[]> kvp in addItem.Tags)
                    {
                        storeContext.TagHashCollection.AddTag(cacheIndexInternal.InDeserializationContext.TypeId, kvp.Key);
                        internalItem.UpdateTag(TagHashCollection.GetTagHashCode(kvp.Key), kvp.Value);
                    }

                    // Reposition index item if required
                    if (reposition)
                    {
                        RepositionIndexItem(cacheIndexInternal, indexInfo, addItem, searchIndex, internalItem, comparer);
                    }
                }
            }
            else //Save to multiple indexes
            {
                if (addItem.Tags != null && addItem.Tags.Count > 0)
                {
                    List<string> tagNameList;
                    byte[] tagValue;
                    clientIndex.IndexTagMapping.TryGetValue(cacheIndexInternal.InDeserializationContext.IndexName, out tagNameList);

                    bool reposition = IsRepositioningOfIndexItemRequired(indexInfo, addItem, internalItem);

                    // Update all tags on the internal item
                    foreach (string tagName in tagNameList)
                    {
                        //Add to tagHashCollection
                        storeContext.TagHashCollection.AddTag(cacheIndexInternal.InDeserializationContext.TypeId, tagName);
                        addItem.TryGetTagValue(tagName, out tagValue);
                        internalItem.UpdateTag(TagHashCollection.GetTagHashCode(tagName), tagValue);
                    }

                    // Reposition index item if required
                    if (reposition)
                    {
                        RepositionIndexItem(cacheIndexInternal, indexInfo, addItem, searchIndex, internalItem, comparer);
                    }
                }
            }
        }
        /// <summary>
        /// Adds the new item.
        /// </summary>
        /// <param name="clientIndex">Index from the client.</param>
        /// <param name="cacheIndexInternal">The cache index internal.</param>
        /// <param name="indexInfo">The index info.</param>
        /// <param name="addItem">The add item.</param>
        /// <param name="storeContext">The store context.</param>
        /// <param name="comparer">The comparer.</param>
        private static void AddNewItem(CacheIndex clientIndex,
            CacheIndexInternal cacheIndexInternal,
            Index indexInfo, IndexDataItem addItem,
            IndexStoreContext storeContext,
            InternalItemComparer comparer)
        {
            int searchIndex;
            List<KeyValuePair<int, byte[]>> kvpList;
            searchIndex = cacheIndexInternal.GetInsertPosition(addItem, indexInfo.PrimarySortInfo.SortOrderList[0].SortBy, comparer);

            //Add item to CacheIndexInternal
            kvpList = null;
            if (addItem.Tags != null && addItem.Tags.Count > 0)
            {
                kvpList = new List<KeyValuePair<int, byte[]>>();

                if (clientIndex.TargetIndexName != null) //Save to single index
                {
                    foreach (KeyValuePair<string, byte[]> kvp in addItem.Tags)
                    {
                        //Add to tagHashCollection
                        storeContext.TagHashCollection.AddTag(cacheIndexInternal.InDeserializationContext.TypeId, kvp.Key);
                        kvpList.Add(new KeyValuePair<int, byte[]>(TagHashCollection.GetTagHashCode(kvp.Key), kvp.Value));
                    }
                }
                else //Save to multiple indexes
                {
                    List<string> tagNameList;
                    clientIndex.IndexTagMapping.TryGetValue(cacheIndexInternal.InDeserializationContext.IndexName, out tagNameList);
                    foreach (string tagName in tagNameList)
                    {
                        //Add to tagHashCollection
                        storeContext.TagHashCollection.AddTag(cacheIndexInternal.InDeserializationContext.TypeId, tagName);
                        kvpList.Add(new KeyValuePair<int, byte[]>(TagHashCollection.GetTagHashCode(tagName), addItem.Tags[tagName]));
                    }
                }
            }
            cacheIndexInternal.InsertItem(new InternalItem { ItemId = addItem.ItemId, TagList = kvpList }, searchIndex, true);
        }
        /// <summary>
        /// Processes the specified cache index.
        /// </summary>
        /// <param name="cacheIndex">Index of the cache.</param>
        /// <param name="messageContext">The message context.</param>
        /// <param name="storeContext">The store context.</param>
        internal static void Process(CacheIndex cacheIndex, MessageContext messageContext, IndexStoreContext storeContext)
        {
            lock (LockingUtil.Instance.GetLock(messageContext.PrimaryId))
            {
                try
                {
                    IndexTypeMapping indexTypeMapping =
                        storeContext.StorageConfiguration.CacheIndexV3StorageConfig.IndexTypeMappingCollection[messageContext.TypeId];

                    #region Extract CacheIndex and Validate from incoming message

                    ValidateSave(cacheIndex);

                    #endregion

                    #region Log CacheIndex before processing
                    StringBuilder dbgIndexInfo = null;
                    if (LoggingUtil.Log.IsDebugEnabled)
                    {
                        dbgIndexInfo = new StringBuilder();
                        dbgIndexInfo.Append("TypeId=").Append(messageContext.TypeId).Append(Environment.NewLine);
                        dbgIndexInfo.Append(IndexServerUtils.GetPrintableCacheIndex(cacheIndex,
                            storeContext.TagHashCollection,
                            messageContext.TypeId));
                    }
                    #endregion

                    #region Init vars

                    List<RelayMessage> indexStorageMessageList = new List<RelayMessage>();
                    List<RelayMessage> dataStorageMessageList = new List<RelayMessage>();
                    List<CacheIndexInternal> internalIndexList = new List<CacheIndexInternal>();
                    List<IndexItem> cappedDeleteItemList = new List<IndexItem>();
                    CacheIndexInternal internalIndex;

                    #endregion

                    if (cacheIndex.IndexVirtualCountMapping == null)
                    {
                        #region Save Items

                        #region Extract CacheIndexInternal from index storage

                        if (cacheIndex.TargetIndexName == null) //Save to multiple indexes
                        {
                            #region Get CacheIndexInternal for multiple indexes

                            foreach (KeyValuePair<string /*IndexName*/, List<string> /*TagNameList*/> kvp in cacheIndex.IndexTagMapping)
                            {
                                Index indexInfo = indexTypeMapping.IndexCollection[kvp.Key];
                                internalIndex = IndexServerUtils.GetCacheIndexInternal(storeContext,
                                    messageContext.TypeId,
                                    cacheIndex.PrimaryId,
                                    cacheIndex.IndexId,
                                    indexInfo.ExtendedIdSuffix,
                                    kvp.Key,
                                    0,
                                    null,
                                    true,
                                    null,
                                    false,
                                    false,
                                    indexInfo.PrimarySortInfo,
                                    indexInfo.LocalIdentityTagList,
                                    indexInfo.StringHashCodeDictionary,
                                    null);

                                if (internalIndex != null)
                                {
                                    // update performance counter
                                    PerformanceCounters.Instance.SetCounterValue(
                                        PerformanceCounterEnum.NumberOfItemsInIndexPerSave,
                                        messageContext.TypeId,
                                        internalIndex.OutDeserializationContext.TotalCount);
                                }

                                if (internalIndex == null || cacheIndex.ReplaceFullIndex) //CacheIndexInternal does not exists or is to be discarded
                                {
                                    internalIndex = new CacheIndexInternal
                                                        {
                                                            InDeserializationContext = new InDeserializationContext
                                                                                           {
                                                                                               TypeId = messageContext.TypeId,
                                                                                               TagHashCollection = storeContext.TagHashCollection,
                                                                                               IndexId = cacheIndex.IndexId,
                                                                                               IndexName = kvp.Key,
                                                                                               InclusiveFilter = true,
                                                                                               PrimarySortInfo = indexInfo.PrimarySortInfo,
                                                                                               LocalIdentityTagNames = indexInfo.LocalIdentityTagList,
                                                                                               StringHashCollection = storeContext.StringHashCollection,
                                                                                               StringHashCodeDictionary = indexInfo.StringHashCodeDictionary
                                                                                           }
                                                        };
                                }

                                internalIndexList.Add(internalIndex);
                            }

                            #endregion
                        }
                        else //Save to single index
                        {
                            #region Get CacheIndexInternal for TargetIndexName

                            Index indexInfo = indexTypeMapping.IndexCollection[cacheIndex.TargetIndexName];

                            internalIndex = IndexServerUtils.GetCacheIndexInternal(storeContext,
                                messageContext.TypeId,
                                cacheIndex.PrimaryId,
                                cacheIndex.IndexId,
                                indexInfo.ExtendedIdSuffix,
                                cacheIndex.TargetIndexName,
                                0,
                                null,
                                true,
                                null,
                                false,
                                false,
                                indexInfo.PrimarySortInfo,
                                indexInfo.LocalIdentityTagList,
                                indexInfo.StringHashCodeDictionary,
                                null);

                            if (internalIndex != null)
                            {
                                // update performance counter
                                PerformanceCounters.Instance.SetCounterValue(
                                    PerformanceCounterEnum.NumberOfItemsInIndexPerSave,
                                    messageContext.TypeId,
                                    internalIndex.OutDeserializationContext.TotalCount);
                            }

                            if (internalIndex == null || cacheIndex.ReplaceFullIndex) //CacheIndexInternal does not exists or is to be discarded
                            {
                                internalIndex = new CacheIndexInternal
                                {
                                    InDeserializationContext = new InDeserializationContext
                                                                             {
                                                                                 TypeId = messageContext.TypeId,
                                                                                 TagHashCollection = storeContext.TagHashCollection,
                                                                                 IndexId = cacheIndex.IndexId,
                                                                                 IndexName = cacheIndex.TargetIndexName,
                                                                                 InclusiveFilter = true,
                                                                                 PrimarySortInfo = indexInfo.PrimarySortInfo,
                                                                                 LocalIdentityTagNames = indexInfo.LocalIdentityTagList,
                                                                                 StringHashCollection = storeContext.StringHashCollection,
                                                                                 StringHashCodeDictionary = indexInfo.StringHashCodeDictionary
                                                                             }
                                };
                            }

                            internalIndexList.Add(internalIndex);

                            #endregion

                        }
                        #endregion

                        #region Log CacheIndexInternals before save
                        if (LoggingUtil.Log.IsDebugEnabled && dbgIndexInfo != null)
                        {
                            dbgIndexInfo.Append(Environment.NewLine).Append(string.Format("BEFORE SAVE {0}",
                                                        IndexServerUtils.GetPrintableCacheIndexInternalList(
                                                            internalIndexList,
                                                            storeContext.TagHashCollection,
                                                            messageContext.TypeId)));
                        }
                        #endregion

                        #region Process Delete and Add List
                        try
                        {
                            #region Process Delete List

                            if (cacheIndex.DeleteList.Count > 0 && !cacheIndex.ReplaceFullIndex)
                            {
                                ProcessDeleteList(internalIndexList, cacheIndex.DeleteList, messageContext.TypeId);
                            }

                            #endregion

                            #region Process Add List

                            if (cacheIndex.AddList.Count > 0 || cacheIndex.UpdateMetadata)
                            {
                                ProcessAddList(internalIndexList, cappedDeleteItemList, cacheIndex, storeContext, indexTypeMapping);
                            }

                            #endregion
                        }
                        catch
                        {
                            LoggingUtil.Log.Debug(IndexServerUtils.GetPrintableCacheIndexInternalList(internalIndexList, storeContext.TagHashCollection, messageContext.TypeId));
                            throw;
                        }
                        #endregion

                        #region Log CacheIndexInternals after save
                        if (LoggingUtil.Log.IsDebugEnabled && dbgIndexInfo != null)
                        {
                            dbgIndexInfo.Append(Environment.NewLine).Append(string.Format("AFTER SAVE {0}",
                                                        IndexServerUtils.GetPrintableCacheIndexInternalList(internalIndexList,
                                                            storeContext.TagHashCollection,
                                                            messageContext.TypeId)));
                        }
                        #endregion

                        #region Data store relay messages for deletes and saves

                        if (DataTierUtil.ShouldForwardToDataTier(messageContext.RelayTTL,
                            messageContext.SourceZone,
                            storeContext.MyZone,
                            indexTypeMapping.IndexServerMode) && !cacheIndex.PreserveData)
                        {
                            byte[] fullDataId;
                            short relatedTypeId;
                            if (!storeContext.TryGetRelatedIndexTypeId(messageContext.TypeId, out relatedTypeId))
                            {
                                LoggingUtil.Log.ErrorFormat("Invalid RelatedTypeId for TypeId - {0}", messageContext.TypeId);
                                throw new Exception("Invalid RelatedTypeId for TypeId - " + messageContext.TypeId);
                            }

                            #region Delete Messages

                            foreach (IndexItem indexItem in cacheIndex.DeleteList)
                            {
                                fullDataId = DataTierUtil.GetFullDataId(cacheIndex.IndexId, indexItem, indexTypeMapping.FullDataIdFieldList);
                                if (fullDataId != null)
                                {
                                    dataStorageMessageList.Add(new RelayMessage(relatedTypeId,
                                                                   IndexCacheUtils.GeneratePrimaryId(fullDataId),
                                                                   fullDataId,
                                                                   MessageType.Delete));
                                }
                            }

                            #endregion

                            #region Save Messages

                            foreach (IndexDataItem indexDataItem in cacheIndex.AddList)
                            {
                                fullDataId = DataTierUtil.GetFullDataId(cacheIndex.IndexId, indexDataItem, indexTypeMapping.FullDataIdFieldList);

                                if (fullDataId != null)
                                {
                                    dataStorageMessageList.Add(new RelayMessage(relatedTypeId,
                                                                    IndexCacheUtils.GeneratePrimaryId(fullDataId),
                                                                    fullDataId,
                                                                    DateTime.Now,
                                                                    indexDataItem.Data ?? new byte[0],
                                                                    storeContext.GetCompressOption(messageContext.TypeId),
                                                                    MessageType.Save));

                                    if (indexDataItem.Data == null || indexDataItem.Data.Length == 0)
                                    {

                                        LoggingUtil.Log.WarnFormat("Saving null data for TypeId: {0}, IndexId: {1}, ItemId: {2}, FullDataId: {3}, PrimaryId: {4}",
                                                                    relatedTypeId,
                                                                    IndexCacheUtils.GetReadableByteArray(cacheIndex.IndexId),
                                                                    IndexCacheUtils.GetReadableByteArray(indexDataItem.ItemId),
                                                                    IndexCacheUtils.GetReadableByteArray(fullDataId),
                                                                    IndexCacheUtils.GeneratePrimaryId(fullDataId));
                                    }

                                }
                            }

                            #endregion

                            #region Capped Item Delete Messages

                            foreach (IndexItem indexItem in cappedDeleteItemList)
                            {
                                fullDataId = DataTierUtil.GetFullDataId(cacheIndex.IndexId, indexItem, indexTypeMapping.FullDataIdFieldList);
                                if (fullDataId != null)
                                {
                                    dataStorageMessageList.Add(new RelayMessage(relatedTypeId,
                                                                   IndexCacheUtils.GeneratePrimaryId(fullDataId),
                                                                   fullDataId,
                                                                   MessageType.Delete));
                                }
                            }

                            #endregion

                            #region Send relay mesaages to data store

                            if (dataStorageMessageList.Count > 0)
                            {
                                storeContext.ForwarderComponent.HandleMessages(dataStorageMessageList);
                            }

                            #endregion
                        }

                        #endregion

                        #endregion

                        if (dbgIndexInfo != null)
                        {
                            LoggingUtil.Log.Debug(dbgIndexInfo.ToString());
                        }
                    }
                    else
                    {
                        #region Update Virtual Count

                        foreach (KeyValuePair<string /*IndexName*/, int /*VirtualCount*/> kvp in cacheIndex.IndexVirtualCountMapping)
                        {
                            Index indexInfo = indexTypeMapping.IndexCollection[kvp.Key];
                            internalIndex = IndexServerUtils.GetCacheIndexInternal(storeContext,
                                                                                   messageContext.TypeId,
                                                                                   cacheIndex.PrimaryId,
                                                                                   cacheIndex.IndexId,
                                                                                   indexInfo.ExtendedIdSuffix,
                                                                                   kvp.Key,
                                                                                   0,
                                                                                   null,
                                                                                   true,
                                                                                   null,
                                                                                   true,
                                                                                   false,
                                                                                   indexInfo.PrimarySortInfo,
                                                                                   indexInfo.LocalIdentityTagList,
                                                                                   indexInfo.StringHashCodeDictionary,
                                                                                   null);

                            if (internalIndex == null)
                            {
                                internalIndex = new CacheIndexInternal
                                                    {
                                                        InDeserializationContext = new InDeserializationContext
                                                                                            {
                                                                                                TypeId = messageContext.TypeId,
                                                                                                TagHashCollection = storeContext.TagHashCollection,
                                                                                                IndexId = cacheIndex.IndexId,
                                                                                                IndexName = kvp.Key,
                                                                                                InclusiveFilter = true,
                                                                                                DeserializeHeaderOnly = true,
                                                                                                PrimarySortInfo = indexInfo.PrimarySortInfo,
                                                                                                LocalIdentityTagNames = indexInfo.LocalIdentityTagList,
                                                                                                StringHashCollection = storeContext.StringHashCollection,
                                                                                                StringHashCodeDictionary = indexInfo.StringHashCodeDictionary
                                                                                            }
                                                    };
                            }
                            else
                            {
                                // update performance counter
                                PerformanceCounters.Instance.SetCounterValue(
                                    PerformanceCounterEnum.NumberOfItemsInIndexPerSave,
                                    messageContext.TypeId,
                                    internalIndex.OutDeserializationContext.TotalCount);
                            }

                            internalIndex.VirtualCount = kvp.Value;
                            internalIndexList.Add(internalIndex);
                        }
                        #endregion
                    }

                    #region Index storage relay messages for each CacheIndexInternal

                    #region Metadata

                    if (indexTypeMapping.MetadataStoredSeperately && cacheIndex.UpdateMetadata)
                    {
                        indexStorageMessageList.Add(new RelayMessage(messageContext.TypeId,
                                                         cacheIndex.PrimaryId,
                                                         cacheIndex.IndexId,
                                                         DateTime.Now,
                                                         cacheIndex.Metadata ?? new byte[0],
                                                         storeContext.GetCompressOption(messageContext.TypeId),
                                                         MessageType.Save));
                    }

                    #endregion

                    #region Index(es)

                    byte[] payload;
                    CompactBinaryWriter writer;
                    RelayMessage indexStorageMessage;
                    byte[] extendedId;

                    foreach (CacheIndexInternal cacheIndexInternal in internalIndexList)
                    {
                        extendedId = IndexServerUtils.FormExtendedId(
                            cacheIndex.IndexId,
                            indexTypeMapping.IndexCollection[cacheIndexInternal.InDeserializationContext.IndexName].ExtendedIdSuffix);

                        // This mess is required until Moods 2.0 migrated to have IVersionSerializable version of CacheIndexInternal
                        // ** TBD - Should be removed later
                        if (LegacySerializationUtil.Instance.IsSupported(messageContext.TypeId))
                        {
                            writer = new CompactBinaryWriter(new BinaryWriter(new MemoryStream()));
                            cacheIndexInternal.Serialize(writer);
                            payload = new byte[writer.BaseStream.Length];
                            writer.BaseStream.Position = 0;
                            writer.BaseStream.Read(payload, 0, payload.Length);

                            indexStorageMessage = new RelayMessage(messageContext.TypeId,
                                 cacheIndex.PrimaryId,
                                 extendedId,
                                 DateTime.Now,
                                 payload,
                                 storeContext.GetCompressOption(messageContext.TypeId),
                                 MessageType.Save);
                        }
                        else
                        {
                            indexStorageMessage = RelayMessage.GetSaveMessageForObject(messageContext.TypeId,
                                cacheIndex.PrimaryId,
                                extendedId,
                                DateTime.Now,
                                cacheIndexInternal,
                                storeContext.GetCompressOption(messageContext.TypeId));
                        }

                        indexStorageMessageList.Add(indexStorageMessage);
                    }

                    #endregion

                    #region Send relay mesaages to index storage

                    storeContext.IndexStorageComponent.HandleMessages(indexStorageMessageList);

                    #endregion

                    #endregion
                }
                catch (Exception ex)
                {
                    LoggingUtil.Log.DebugFormat("CacheIndex: {0}", IndexServerUtils.GetPrintableCacheIndex(cacheIndex, storeContext.TagHashCollection, messageContext.TypeId));
                    throw new Exception("TypeId " + messageContext.TypeId + " -- Error processing save message.", ex);
                }
            }

        }
        /// <summary>
        /// Gets the CacheIndexInternal.
        /// </summary>
        /// <param name="storeContext">The store context.</param>
        /// <param name="typeId">The type id.</param>
        /// <param name="primaryId">The primary id.</param>
        /// <param name="indexId">The index id.</param>
        /// <param name="extendedIdSuffix">The extended id suffix.</param>
        /// <param name="indexName">Name of the index.</param>
        /// <param name="count">The count.</param>
        /// <param name="filter">The filter.</param>
        /// <param name="inclusiveFilter">if set to <c>true</c> includes the items that pass the filter; otherwise , <c>false</c>.</param>
        /// <param name="indexCondition">The index condition.</param>
        /// <param name="deserializeHeaderOnly">if set to <c>true</c> if just CacheIndexInternal header is to be deserialized; otherwise, <c>false</c>.</param>
        /// <param name="getFilteredItems">if set to <c>true</c> get filtered items; otherwise, <c>false</c>.</param>
        /// <param name="primarySortInfo">The primary sort info.</param>
        /// <param name="localIdentityTagNames">The local identity tag names.</param>
        /// <param name="stringHashCodeDictionary">The string hash code dictionary.</param>
        /// <param name="capCondition">The cap condition.</param>
        /// <returns>CacheIndexInternal</returns>
        internal static CacheIndexInternal GetCacheIndexInternal(IndexStoreContext storeContext,
            short typeId,
            int primaryId,
            byte[] indexId,
            short extendedIdSuffix,
            string indexName,
            int count,
            Filter filter,
            bool inclusiveFilter,
            IndexCondition indexCondition,
            bool deserializeHeaderOnly,
            bool getFilteredItems,
            PrimarySortInfo primarySortInfo,
            List<string> localIdentityTagNames,
            Dictionary<int, bool> stringHashCodeDictionary,
            CapCondition capCondition)
        {
            CacheIndexInternal cacheIndexInternal = null;
            byte[] extendedId = FormExtendedId(indexId, extendedIdSuffix);
            RelayMessage getMsg = new RelayMessage(typeId, primaryId, extendedId, MessageType.Get);
            storeContext.IndexStorageComponent.HandleMessage(getMsg);

            if (getMsg.Payload != null) //CacheIndex exists
            {
                cacheIndexInternal = new CacheIndexInternal
                                         {
                                             InDeserializationContext = new InDeserializationContext
                                                                            {
                                                                                TypeId = getMsg.TypeId,
                                                                                TagHashCollection = storeContext.TagHashCollection,
                                                                                IndexId = indexId,
                                                                                IndexName = indexName,
                                                                                MaxItemsPerIndex = count,
                                                                                Filter = filter,
                                                                                InclusiveFilter = inclusiveFilter,
                                                                                IndexCondition = indexCondition,
                                                                                DeserializeHeaderOnly = deserializeHeaderOnly,
                                                                                CollectFilteredItems = getFilteredItems,
                                                                                PrimarySortInfo = primarySortInfo,
                                                                                LocalIdentityTagNames = localIdentityTagNames,
                                                                                StringHashCollection = storeContext.StringHashCollection,
                                                                                StringHashCodeDictionary = stringHashCodeDictionary,
                                                                                CapCondition = capCondition
                                                                            }
                                         };

                // This mess is required until Moods 2.0 migrated to have IVersionSerializable version of CacheIndexInternal
                // ** TBD - Should be removed later
                if (LegacySerializationUtil.Instance.IsSupported(getMsg.TypeId))
                {
                    MemoryStream stream = new MemoryStream(getMsg.Payload.ByteArray);
                    cacheIndexInternal.Deserialize(new CompactBinaryReader(stream));
                }
                else
                {
                    getMsg.GetObject(cacheIndexInternal);
                }
            }

            return cacheIndexInternal;
        }
        /// <summary>
        /// Gets the tags.
        /// </summary>
        /// <param name="cacheIndexInternal">The cache index internal.</param>
        /// <param name="searchItem">The search item.</param>
        /// <param name="resultItem">The result item.</param>
        internal static void GetTags(CacheIndexInternal cacheIndexInternal, IndexItem searchItem, IndexItem resultItem)
        {
            int searchIndex = cacheIndexInternal.Search(searchItem);
            if (searchIndex > -1)
            {
                IndexItem tempIndexItem = InternalItemAdapter.ConvertToIndexItem(cacheIndexInternal.GetItem(searchIndex), cacheIndexInternal.InDeserializationContext);

                foreach (KeyValuePair<string, byte[]> kvp in tempIndexItem.Tags)
                {
                    if (!resultItem.Tags.ContainsKey(kvp.Key))
                    {
                        resultItem.Tags.Add(kvp.Key, kvp.Value);
                    }
                }
            }
        }
        /// <summary>
        /// Gets the index header.
        /// </summary>
        /// <param name="targetIndex">Index of the target.</param>
        /// <param name="indexTypeMapping">The index type mapping.</param>
        /// <param name="typeId">The type id.</param>
        /// <param name="primaryId">The primary id.</param>
        /// <param name="storeContext">The store context.</param>
        /// <returns>IndexHeader</returns>
        private static IndexHeader GetIndexHeader(CacheIndexInternal targetIndex,
            IndexTypeMapping indexTypeMapping,
            short typeId,
            int primaryId,
            IndexStoreContext storeContext)
        {
            IndexHeader indexHeader = new IndexHeader();

            #region Metadata
            
            if (indexTypeMapping.MetadataStoredSeperately)
            {
                #region Check if metadata is stored seperately
                
                //Send a get message to local index storage and fetch seperately stored metadata
                RelayMessage getMsg = new RelayMessage(typeId, primaryId, targetIndex.InDeserializationContext.IndexId, MessageType.Get);
                storeContext.IndexStorageComponent.HandleMessage(getMsg);
                if (getMsg.Payload != null)
                {
                    indexHeader.Metadata = getMsg.Payload.ByteArray;
                }
                
                #endregion
            }
            else
            {
                #region Check metadata on targetIndex
                
                if (indexTypeMapping.IndexCollection[targetIndex.InDeserializationContext.IndexName].MetadataPresent)
                {
                    indexHeader.Metadata = targetIndex.Metadata;
                }
                
                #endregion
            }
            
            #endregion

            #region VirtualCount
            
            indexHeader.VirtualCount = targetIndex.VirtualCount;
            
            #endregion

            return indexHeader;
        }