/// <summary>
        /// Handle custom Lucene indexing when the lucene document is writing
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public static void ProjectIndexer_DocumentWriting(object sender, DocumentWritingEventArgs e)
        {
            //if there is a "body" field, we'll strip the html but also store it's raw value
            if (e.Fields.ContainsKey("body"))
            {
                //store the raw value
                e.Document.Add(new Field(
                    string.Concat(LuceneIndexer.SpecialFieldPrefix, "body"),
                    e.Fields["body"],
                    Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS, Field.TermVector.NO));
                //remove the current version field from the lucene doc
                e.Document.RemoveField("body");
                //add a 'body' field with stripped html
                e.Document.Add(new Field("body", library.StripHtml(e.Fields["body"]), Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.YES));
            }

            //If there is a versions field, we'll split it and index the same field on each version
            if (e.Fields.ContainsKey("versions"))
            {
                //split into separate versions
                var versions = e.Fields["versions"].Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

                AddNumericalVersionValue(e, "num_versions", versions);

                //remove the current version field from the lucene doc
                e.Document.RemoveField("versions");

                foreach (var version in versions)
                {
                    //add a 'versions' field for each version (same field name but different values)
                    //not analyzed, we don't use this for searching
                    e.Document.Add(new Field("versions", version, Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS, Field.TermVector.NO));
                }
            }

            //If there is a compatVersions field, we'll split it and index the same field on each version
            if (e.Fields.ContainsKey("compatVersions"))
            {
                //split into separate versions
                var compatVersions = e.Fields["compatVersions"].Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

                AddNumericalVersionValue(e, "num_compatVersions", compatVersions);

                //remove the current compatVersions field from the lucene doc
                e.Document.RemoveField("compatVersions");

                foreach (var version in compatVersions)
                {
                    //add a 'compatVersions' field for each compatVersion (same field name but different values)
                    //not analyzed, we don't use this for searching
                    e.Document.Add(new Field("compatVersions", version, Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS, Field.TermVector.NO));
                }
            }
        }
    private void MotosIndexerExternalFields(object sender, DocumentWritingEventArgs e)
    {
        Field fld = null;
        fld = new Field(
            "xPath", GetNodeListValue(e.Fields["path"]),
            Field.Store.YES, Field.Index.ANALYZED_NO_NORMS, Field.TermVector.NO
        );
        e.Document.Add(fld);

        var contentService = ApplicationContext.Current.Services.ContentService;
        string vendorId = "-1";
        if (e.Fields.ContainsKey("modelPicker"))
        {
            vendorId = contentService.GetById(Int32.Parse(e.Fields["modelPicker"])).ParentId.ToString();
        }
        fld = new Field(
            "xVendor", vendorId,
            Field.Store.YES, Field.Index.ANALYZED_NO_NORMS, Field.TermVector.NO
            );
        e.Document.Add(fld);
        fld = new Field(
            "xProd", contentService.GetById(Int32.Parse(e.Fields["id"])).Parent().ContentType.Alias,
            Field.Store.YES, Field.Index.ANALYZED_NO_NORMS, Field.TermVector.NO
            );
        e.Document.Add(fld);
        //значение полей xValue и xPrice приводим к общему виду, янвно указывая разрядность, для корректного поиска в lucene по объему и цене соответственно.
        fld = new Field(
            "xValue", Regex.Replace(e.Fields["displacement"].Trim(), @"\D+.*$", "").Trim().PadLeft(4, '0'),
            Field.Store.YES, Field.Index.ANALYZED_NO_NORMS, Field.TermVector.NO
            );
        e.Document.Add(fld);

        fld = new Field(
            "xPrice", e.Fields.ContainsKey("price") ? e.Fields["price"].Trim().PadLeft(9, '0') : "000000000",
            Field.Store.YES, Field.Index.ANALYZED_NO_NORMS, Field.TermVector.NO
            );
        e.Document.Add(fld);

        fld = new Field(
            "xLocation", contentService.GetById(Int32.Parse(e.Fields["id"])).Ancestors().First(x => x.ContentType.Alias == "subCatalog").Name,
            Field.Store.YES, Field.Index.ANALYZED_NO_NORMS, Field.TermVector.NO
            );
        e.Document.Add(fld);
    }
        /// <summary>
        /// Handle custom Lucene indexing when the lucene document is writing
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public static void ProjectIndexer_DocumentWriting(object sender, DocumentWritingEventArgs e)
        {
            //TODO: This will be good to do but we need the bleeding edge version of examine v1.x which i haven't released yet

            ////If there is a versions field, we'll split it and index the same field on each version
            //if (e.Fields.ContainsKey("versions"))
            //{
            //    //split into separate versions
            //    var versions = e.Fields["versions"].Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries);

            //    //remove the current version field from the lucene doc
            //    e.Document.RemoveField("versions");

            //    foreach (var version in versions)
            //    {
            //        //add a 'versions' field for each version (same field name but different values)
            //        e.Document.Add(new Field("versions", version, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.YES));
            //    }
            //}
        }
 private void AgentsIndexerExternalFields(object sender, DocumentWritingEventArgs e)
 {
     if (!e.Fields.ContainsKey("agentNumber")) return;
     var agentNumber = e.Fields["agentNumber"];
     AgentView agent;
     try
     {
         agent = Gleaner.Core.GleanerContext.Current.Services.AgentService.GetAgent(agentNumber);
     }
     catch
     {
         return;
     }
     var nameField = new Field(
         "xName", agent.FirstName + " " + agent.LastName,
         Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.YES
     );
     var address = Gleaner.Web.Controllers.HomeController.MakeAgentAddress(agent.HomeStreet, agent.HomeCity, agent.HomeState, agent.HomeZip);
     var addressField = new Field(
         "xAddress", address,
         Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.YES
     );
     var agencyNameField = new Field(
         "xAgencyName", agent.AgencyName,
         Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.YES
     );
     var phoneField = new Field(
         "xPhone", agent.BusinessPhone1,
         Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.YES
     );
     var emailField = new Field(
         "xEmail", agent.EmailAddress,
         Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.YES
     );
     e.Document.Add(nameField);
     e.Document.Add(addressField);
     e.Document.Add(agencyNameField);
     e.Document.Add(phoneField);
     e.Document.Add(emailField);
 }
		private static void IndexerDocumentWriting(object sender, DocumentWritingEventArgs e)
		{
			if (e.Fields.Keys.Contains("nodeName"))
			{
				//add the lower cased version
				e.Document.Add(new Field("__nodeName",
										e.Fields["nodeName"].ToLower(),
										Field.Store.YES,
										Field.Index.ANALYZED,
										Field.TermVector.NO
										));
			}
		}
        protected override void OnDocumentWriting(DocumentWritingEventArgs docArgs)
        {
            var d = docArgs.Document;
            foreach (var f in docArgs.Fields.Where(x => x.Key.StartsWith(RawFieldPrefix)))
            {                
                d.Add(new Field(
                   f.Key,
                   f.Value,
                   Field.Store.YES,
                   Field.Index.NO, //don't index this field, we never want to search by it 
                   Field.TermVector.NO));   
            }            

            base.OnDocumentWriting(docArgs);
        }
        /// <summary>
        /// Given the string versions, this will put them into the index as numerical versions, this way we can compare/range query, etc... on versions
        /// </summary>
        /// <param name="e"></param>
        /// <param name="fieldName"></param>
        /// <param name="versions"></param>
        /// <remarks>
        /// This stores a numerical version as a Right padded 3 digit combined long number. Example:
        /// 7.5.0 would be:
        ///     007005000 = 7005000
        /// 4.11.0 would be:
        ///     004011000 = 4011000
        /// </remarks>
        private static void AddNumericalVersionValue(DocumentWritingEventArgs e, string fieldName, IEnumerable<string> versions)
        {
            var numericalVersions = versions.Select(x =>
                {
                    System.Version o;
                    return System.Version.TryParse(x, out o) ? o : null;
                })
                .Where(x => x != null)
                .Select(x => x.GetNumericalValue())
                .ToArray();

            foreach (var numericalVersion in numericalVersions)
            {
                //don't store, we're just using this to search
                var versionField = new NumericField(fieldName, Field.Store.NO, true).SetLongValue(numericalVersion);
                e.Document.Add(versionField);
            }
        }
		/// <summary>
		/// Event handler to create a lower cased version of the node name, this is so we can support case-insensitive searching and still
		/// use the Whitespace Analyzer
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		
		private static void IndexerDocumentWriting(object sender, DocumentWritingEventArgs e)
		{
			if (e.Fields.Keys.Contains("nodeName"))
			{
                //TODO: This logic should really be put into the content indexer instead of hidden here!!

				//add the lower cased version
				e.Document.Add(new Field("__nodeName",
										e.Fields["nodeName"].ToLower(),
										Field.Store.YES,
										Field.Index.ANALYZED,
										Field.TermVector.NO
										));
			}
		}