/// <summary>
        /// подготавливает строку к хешированию
        /// </summary>
        /// <param name="data">входной набор символов</param>
        /// <returns>StringBuilder or null</returns>
        private StringBuilder CleanString(string data)
        {
            if (string.IsNullOrEmpty(data)) return null;

            HtmlParser parser = new HtmlParser();
            var result = new StringBuilder(data.ToLower());
            parser.ClearContent(result);
            for (int i = 0; i < this.keywords.Length; i++)
            {
                if (this.keywords[i] != "")
                {
                    while (result.Contains(this.keywords[i]) >= 0)
                        result.Replace(this.keywords[i], string.Empty);
                }
            }
            parser.ClearContent(result);//еще раз зачищаем строку
            return result;
        }
        public string CleanString2(string data)
        {
            if (string.IsNullOrEmpty(data)) return null;

            HtmlParser parser = new HtmlParser();
            //var result = new StringBuilder(data.ToLower());
            data = data.ToLower();
            var tmpData = parser.ClearContent(data).Split(' ').ToList<string>();

            for (int i = 0; i < this.keywords.Length; i++)
            {
                if (this.keywords[i] != "")
                {
                    int j = 0;
                    while (j < tmpData.Count())
                    {
                        if (this.keywords[i].Length == 1 && !Char.IsLetter(this.keywords[i][0]))
                        {
                            tmpData[j] = tmpData[j].Replace(this.keywords[i], " ");
                            if(tmpData[j].Length==0)
                                tmpData.RemoveAt(j);
                            j++;
                        }
                        else if (tmpData[j] == this.keywords[i])
                        {
                            tmpData.RemoveAt(j);
                        }
                        else { j++; }

                    }
                }
            }

            StringBuilder sb = new StringBuilder(100);
            for (int i = 0; i < tmpData.Count(); i++)
            {
                sb.Append(tmpData[i] + " ");
            }
            string result = parser.ClearContent(sb.ToString().Trim());//еще раз зачищаем строку
            return result;
        }
        private void CollectEntities(Object o)
        {
            lock (collectEntityLock)//лочим текущий поток чтобы не обгонять поток получения ссылок на объекты
            {
                Monitor.Wait(collectEntityLock);
            }

            NetFetcher net = new NetFetcher();
            bool stopLoop = false;
            Template template = o as Template;
            if (template == null)
                return;
            HtmlParser parser = new HtmlParser();
            DataExtactor extractor = new DataExtactor();
            Instruction currentUrl = null;

            var sha = new System.Security.Cryptography.SHA256Managed();
            var uEncode = new UnicodeEncoding();
            List<ulong> h1 = null;

            int countLinksToObject = 0;

            try
            {
                do
                {
                    lock (linksToObjectLocker)
                    {
                        if (linksToObjects.Count > 0)
                            currentUrl = linksToObjects.Dequeue();//пытаемся получить ссылку на объект
                        countLinksToObject = linksToObjects.Count();
                    }

                    if (countLinksToObject <= minLimitList)
                    {
                        lock (linksToObjectLimitLocker)
                        {
                            Monitor.PulseAll(linksToObjectLimitLocker);
                        }
                    }

                    if (currentUrl == null)//если ссылку получить не удалось
                    {
                        if (!t2.IsAlive)//пришло время останавливаться
                        {
                            eventLog.AddEventToLog("CollectEntities- Нет больше ссылок на объекты,  поток собиратель ссылок- завршился- завершаем работу и мы");
                            break;//останавливаем главный цикл
                        }
                        else//поток собирающий ссылки еще живой
                        {
                            lock (linksToObjectLimitLocker)
                            {
                                Monitor.PulseAll(linksToObjectLimitLocker);
                            }


                            //eventLog.AddEventToLog("CollectEntities- Нет ссылок на объекты,  поток собиратель еще живой- зысыпаем");

                            lock (collectEntityLock)//останавливаемся и ждем когда нас опять позовут
                            {
                                Monitor.Wait(collectEntityLock);
                            }
                            continue;//начинаем  с начала цикла
                        }
                    }
                    else//если ссылку получили
                    {
                        if (string.IsNullOrEmpty(currentUrl.link))//если урл ссылка пустая
                        {
                            eventLog.AddEventToLog("CollectEntities- ОШИБКА - пришла пустая ссылка");
                            continue;// начинаем цикл по новой
                        }

                        //если добрались сюда- значит ссылку получили и  можем с ней работать

                        #region проверяем линк на дубликаты
                        bool dublicateLink = false;
                        currentUrl.link = currentUrl.link.ToLower();
                        lock (processedLinksLocker)
                        {
                            if (processedLinks.ContainsKey(currentUrl.link))
                            {
                                dublicateLink = true;
                                currentUrl = null;//обнуляем текущую  ссылку т.к. найден дубликат
                                Console.WriteLine("dublicat found");
                            }
                        }
                        if (dublicateLink)//если нашли дубликат- начнаем с начала  цикла
                            continue;
                        else//если дубликата не найден- добавлеям ссылку в список обработанных
                        {
                            lock (processedLinksLocker)
                            {
                                processedLinks.Add(currentUrl.link, true);
                                linkLogger.AddLinkToLog(currentUrl.link);
                            }
                        }
                        #endregion

                        string content = net.DownloadWebPage(currentUrl.link, Encoding.UTF8);//скачиваем страницу
                        Template tmpTemplate = Template.DeepClone<Template>(template);//делаем дубликат шаблона

                        Entity ent = extractor.Extract(content, template.HOST, tmpTemplate);//template);//извлекаем объект со страницы

                        if (ent != null)//если объект найден
                        {

                            #region проверяем текст объявления на дубликаты

                            string clearContent = parser.ClearContent(ent.description);

                            if (string.IsNullOrEmpty(clearContent))//если текст  объявления после очистки пустой- пропускаем такое объявление
                            {
                                eventLog.AddEventToLog("ВНИМАНИЕ!!!Пустое объявление по ссылке " + ent.linkToOriginalObject);
                                continue;
                            }

                            h1 = hash.ComputeHash(clearContent);//считаем хеши
                            if (h1 == null)
                            {
                                eventLog.AddEventToLog("ВНИМАНИЕ!!!Ошибка получения хеша для  " + clearContent);
                                continue;
                            }
                            float percentage = hash.IsExist(h1);//проверяем на наличие похожих хешей
                            if (percentage < 90.0)
                            {
                                hash.AddNewHash(h1);//добавляем если предел не превышен
                            }
                            else// найден дублика объявления
                            {
                                Console.WriteLine("Text Dublicate found");
                                ent = null;
                                tmpTemplate = null;
                                content = null;
                                currentUrl = null;
                                continue;
                            }
                            #endregion

                            ent.linkToOriginalObject = currentUrl.link;//сохраняем линк на оригинал объявления

                            if (string.IsNullOrEmpty(ent.phone1))//если  телефон1 не заполнен еще- пытаемся его получить
                            {
                                //пытаемся получить телефоны
                                foreach (var item in parser.GetLinks(content, template.HOST, template.phone[0]))
                                {
                                    content = net.DownloadWebPage(item, Encoding.UTF8);//скачиваем указанную страницу для получения телефона
                                    var newPhoneTemplate = new string[1];
                                    newPhoneTemplate[0] = template.phone[1];
                                    extractor.ExtractPhone(content, ent, newPhoneTemplate);
                                    break;
                                }
                            }

                            #region получаем фотографии
                            if (ent.LinkToPhotos != null)
                            {
                                ent.photos = new List<byte[]>();
                                for (int i = 0; i < ent.LinkToPhotos.Count; i++)
                                {
                                    if (!string.IsNullOrEmpty(ent.LinkToPhotos[i]))
                                        ent.photos.Add(
                                            net.getDataAsByteArray(ent.LinkToPhotos[i])
                                            );
                                }
                            }
                            #endregion

                            //дописываем вспомогательную информацию
                            ent.propertyType = currentUrl.propertyType;
                            ent.propertyAction = currentUrl.propertyAction;
                            ent.City = currentUrl.city;
                            ent.District = currentUrl.district;

                            int countEntities = 0;
                            lock (entitiesLocker)//добавляем полученый объект в очередь на сохранение
                            {
                                entities.Enqueue(ent);
                                countEntities = entities.Count();
                            }
                            ent = null;


                            lock (dbLoaderLock)
                            {
                                Monitor.PulseAll(dbLoaderLock);
                            }

                            if (countEntities > LimitList)//если  превысили лимит  объектов в списке лочим текущий поток
                            {


                                lock (collectEntityLock)
                                {
                                    Monitor.Wait(collectEntityLock);
                                }
                            }
                        }
                        else
                        {
                            eventLog.AddEventToLog("ОШИБКА объект по сслыке не найден: " + currentUrl.link);
                        }
                    }


                    if (!t1.IsAlive && countLinksToObject == 0)
                        stopLoop = true;




                } while (!stopLoop);//пока все условия соблюдаются
            }
            catch (Exception ex)
            {
                eventLog.AddEventToLog("ИСКЛЮЧЕНИЕ!!! CollectEntities " + ex.Message);
                hash.StoreCache();//сохряняем хеши
            }
            finally
            {

                lock (dbLoaderLock)//разлочиваем поток загрузки объектов в БД на прощание
                {
                    Monitor.PulseAll(dbLoaderLock);
                }

                Console.WriteLine("CollectEntities terminated");
            }
            return;

        }