/// <summary>
        /// Add one contact to Outlook
        /// </summary>
        /// <param name="c">Google cotact to add</param>
        /// <returns>true if add success</returns>
        internal bool AddNewOutlookContact(OneContact c)
        {
            Outlook.ContactItem newContact;

            try
            {
                newContact = c.GetOutlook();
            }
            catch
            {
                /// Can't create Google Entity from OneContacs Class
                LoggerProvider.Instance.Logger.Error("Problem to read Outlook.ContactItem from GoogleSynchronizer.OneContact");
                return(false);
            }
            if (newContact == null)
            {
                LoggerProvider.Instance.Logger.Error("Can't insert NULL object");
                return(false);
            }
#if (!SIMULATE_SAVE)
            newContact.Save();
#endif
#if (!SIMULATE_SAVE)
            OneContact hlp = new OneContact(newContact);
            c.ReferenceID = newContact.EntryID;
            ouContacts.Add(newContact.EntryID, hlp);
            c.UpdateRefInGoogle(hlp.CreateReferenceID());
#endif
            LoggerProvider.Instance.Logger.Debug("Save update to Google");
            return(true);
        }
        /// <summary>
        /// Step 3 - add contact from Outlook to Google
        /// </summary>
        private void Step3AddToGoogle()
        {
            LoggerProvider.Instance.Logger.Debug("Start step 3 add new contact to Google");
            syncinfo.WorkOnMax = ouContacts.Count;
            int i        = 0;
            int inserted = 0;
            int deleted  = 0;

            syncinfo.WorkOnNextStep();

            ArrayList keys = new ArrayList(ouContacts.Keys);

            foreach (string s in keys)
            {
                syncinfo.WorkOn = ++i;
                syncinfo.WorkOnNextStep();
                OneContact c = ouContacts[s] as OneContact;
                if (!c.IsReferToOtherSide)
                {
                    if (SettingsProvider.Instance.IsAddToGoogle) // if not alow update this side need clear on second side
                    {
                        inserted += AddNewGoogleContact(c) ? 1 : 0;
                    }
                    else
                    {
                        deleted += DeleteFromOutlook(s) ? 1 : 0;
                    }
                }
            }
            _lastStatistic.goInsertContacts += inserted;
            _lastStatistic.ouDeleteContacts += deleted;
        }
 /// <summary>
 /// Update Google contact from outlook
 /// </summary>
 /// <param name="sourceGoogle">Source outlook contact</param>
 /// <param name="destinationOutlook">destination google contact</param>
 /// <returns>True if delete success</returns>
 internal static bool UpdateGoogleFromOutlook(OneContact sourceOutlook, OneContact destinationGoogle)
 {
     if ((!sourceOutlook.IsSourceOutlook) || destinationGoogle.IsSourceOutlook)
     {
         return(false);
     }
     destinationGoogle.UpdateFromOther(sourceOutlook);
     return(true);
 }
        /// <summary>
        /// Add one contact to Google
        /// </summary>
        /// <param name="c">Outlook contact to add</param>
        /// <returns>true if add success</returns>
        internal bool AddNewGoogleContact(OneContact c)
        {
            Google.Contacts.Contact goContact = null;
#warning There is a problem with add google contact with Image
#if (!SIMULATE_SAVE)
            Google.Contacts.Contact goContactNew = null;
            OneContact hlp = null;
#endif

            try
            {
                goContact = c.GetGoogle();
            }
            catch (Exception e)
            {
                /// Can't create Google Entity from OneContacs Class
                LoggerProvider.Instance.Logger.Error("Problem to read Google.Contacts.Contact from GoogleSynchronizer.OneContact");
                LoggerProvider.Instance.Logger.Error(e);
                return(false);;
            }
            if (goContact == null)
            {
                LoggerProvider.Instance.Logger.Error("Can't insert NULL object");
                return(false);
            }
#if (!SIMULATE_SAVE)
            goContactNew = GoogleProvider.GetProvider.Insert(goContact);
            // If don't insert new contact to Google need continue
            if (goContactNew == null)
            {
                return(false);
            }
#endif

#if (!SIMULATE_SAVE)
            hlp           = new OneContact(goContactNew);
            c.ReferenceID = hlp.ContactID;
            goContacts.Add(hlp.ContactID, hlp);
            c.UpdateRefInOutlook(hlp.CreateReferenceID());
#endif
            LoggerProvider.Instance.Logger.Debug("Save update to Outlook");

            #region DEBUG infos
#if (DEBUG1)
            LoggerProvider.Instance.Logger.Debug("Source contact MD5/Count MD5: {0}/{1}", c.MD5selfCount, Utils.CountMD5(c.SummAllData()));
            LoggerProvider.Instance.Logger.Debug(c.SummAllData());
            LoggerProvider.Instance.Logger.Debug("Destination contact MD5/Count MD5: {0}/{1}", hlp.MD5selfCount, Utils.CountMD5(hlp.SummAllData()));
            LoggerProvider.Instance.Logger.Debug(hlp.SummAllData());
            hlp = null;
#endif

            #endregion
            return(true);
        }
        /// <summary>
        /// Update Outlook contact from Google
        /// </summary>
        /// <param name="sourceGoogle">Source Google contact</param>
        /// <param name="destinationOutlook">destination Outlook contact</param>
        /// <returns>True if delete success</returns>
        internal static bool UpdateOutlookFromGoogle(OneContact sourceGoogle, OneContact destinationOutlook)
        {
            if (sourceGoogle.IsSourceOutlook || (!destinationOutlook.IsSourceOutlook))
            {
                return(false);
            }

#if (DUMP_CONTACTS)
            sourceGoogle.DumpActualDataToLog();
            destinationOutlook.DumpActualDataToLog();
#endif

            destinationOutlook.UpdateFromOther(sourceGoogle);
            return(true);
        }
        /// <summary>
        /// Update data in curent ContactItem
        /// </summary>
        /// <param name="newer"></param>
        public void UpdateFromOther(OneContact updater)
        {
            #region Personal data
            Title      = updater.Title;
            FirstName  = updater.FirstName;
            MiddleName = updater.MiddleName;
            LastName   = updater.LastName;
            Suffix     = updater.Suffix;
#if (!ANNIVESARY_NOT_WORK)
            Anniversary = updater.Anniversary;
#endif
            Birthday  = updater.Birthday;
            ImagePath = updater.ImagePath;

            Notes = updater.Notes;
            IM    = updater.IM;
            #endregion

            #region Telephone
            Telephone.Clear();
            if (updater.Telephone.Count > 0)
            {
                foreach (PhoneDetail s in updater.Telephone)
                {
                    Telephone.Add(s);
                }
            }
            #endregion

            #region Address
            Address.Clear();
            if (updater.Address.Count > 0)
            {
                foreach (AddressDetail s in updater.Address)
                {
                    Address.Add(s);
                }
            }
            #endregion

            #region Email address
            email1 = updater.email1;
            email2 = updater.email2;
            email3 = updater.email3;
            #endregion

            #region Company
            Company    = updater.Company;
            Department = updater.Department;
            JobTitle   = updater.JobTitle;
            #endregion

            #region Ostatni
            WebServer   = updater.WebServer;
            IsFromCache = false;
            Category.Clear();
            foreach (string cat in updater.Category)
            {
                Category.Add(cat);
            }
            #endregion

            LoggerProvider.Instance.Logger.Debug("Update current RefID from/to: {0} - {1}", _referenceID, updater._MyID);
            _referenceID = updater._MyID;

            MD5ReCountSelf();
        }
        private void Step7Update()
        {
            LoggerProvider.Instance.Logger.Debug("Start step 7 update contacts");
            syncinfo.WorkOnMax = goContacts.Count; // nastaveni prochazenych odkazu
            syncinfo.WorkOnNextStep();
            int updateGo  = 0;
            int updateOut = 0;
            int i         = 0;

            if (ouContacts.Count != goContacts.Count)
            {
                LoggerProvider.Instance.Logger.Error("Problem in check Update - number of contacts are different Outlook/Google: {0}/{1}",
                                                     ouContacts.Count, goContacts.Count);
                return;
            }
            OneContact    outItem = null;
            OneContact    goItem  = null;
            StringBuilder sb      = new StringBuilder();
            ArrayList     keys    = new ArrayList(goContacts.Keys);

            foreach (string s in keys)
            {
                syncinfo.WorkOn = ++i;
                syncinfo.WorkOnNextStep();
                goItem = (OneContact)goContacts[s];
                if (!ouContacts.ContainsKey(goItem.ReferenceID))
                {
                    LoggerProvider.Instance.Logger.Error("Contacts don't found in table");
                    continue;
                }
                outItem = (OneContact)ouContacts[goItem.ReferenceID];

                if (outItem.MD5selfCount != goItem.MD5selfCount)
                {
                    sb.Remove(0, sb.ToString().Length);
                    sb.AppendLine(string.Format("Update contact Outlook - Google: {0} - {1}", outItem._MyID, goItem._MyID));
                    sb.AppendLine(string.Format("User name: {0} {1}", outItem.FirstName, outItem.LastName));
                    sb.AppendLine(string.Format("MD5 Oulook/Google: {0} / {1}", outItem.MD5selfCount, goItem.MD5selfCount));
                    sb.AppendLine(string.Format("MD5 source:\r\n{0}\r\n{1}", outItem.SummAllData(), goItem.SummAllData()));
                    sb.AppendLine(string.Format("Last Update Outlook/Google:  {0} / {1}", outItem.UpdateTime, goItem.UpdateTime));
                    if (outItem.UpdateTime < goItem.UpdateTime) // What is olders
                    {
                        if (SettingsProvider.Instance.IsUpdateToOutlook)
                        {
                            sb.AppendLine("Update on Outlook");
                            updateOut += UpdateOutlookFromGoogle(goItem, outItem) ? 1 : 0;
                        }
                        else
                        {
                            sb.AppendLine("Update on Google thru configurate way to update");
                            updateGo += UpdateGoogleFromOutlook(outItem, goItem) ? 1 : 0;
                        }
                    }
                    else
                    {
                        if (SettingsProvider.Instance.IsUpdateToGoogle)
                        {
                            sb.AppendLine("Update on Google");
                            updateGo += UpdateGoogleFromOutlook(outItem, goItem) ? 1 : 0;
                        }
                        else
                        {
                            sb.AppendLine("Update on Outlook thru configurate way to update");
                            updateOut += UpdateOutlookFromGoogle(goItem, outItem) ? 1 : 0;
                        }
                    }
                    LoggerProvider.Instance.Logger.Debug(sb.ToString());
                }
            }
            _lastStatistic.goUpdateContacts += updateGo;
            _lastStatistic.ouUpdateContacts += updateOut;
        }
        /// <summary>
        /// Second step is read all google contacts
        /// </summary>
        private void Step2ReadGoogle()
        {
            bool          IsReadAllContact = true;                // use for reread all contact, When time diferences biggers that 20 days
            List <string> toread           = new List <string>(); /// list EntryID for reading
            List <string> todelete         = new List <string>(); /// list EntryID for delete

            if (SettingsProvider.Instance.IsUseGoogleCache)       // use cache system for Google contact
            {
                LoggerProvider.Instance.Logger.Debug("Read data from cache for Google");
                goCacheTime = Utils.LoadCacheDate(true);
                goContacts  = Utils.ReadGoogleFromCache(ref goCacheTime);
                if ((goCacheTime > DateTime.MinValue) && (goCacheTime < DateTime.Now) && DateTime.Now.AddDays(-20) < goCacheTime) // Data read from cache is good
                {
                    _lastStatistic.goReadContacts = goContacts.Count;
                    Feed <Google.Contacts.Contact> gochanged = gp.ContactItemsChangedAfter(goCacheTime);
                    IsReadAllContact = false;                                // data read
                    if ((gochanged != null) && (gochanged.TotalResults > 0)) // return data it's good
                    {
                        OneContact oc = null;
                        foreach (Google.Contacts.Contact gc in gochanged.Entries)
                        {
                            if (goContacts.ContainsKey(gc.Id))
                            {
                                if (gc.Deleted) /// it's deleted?
                                {
                                    goContacts.Remove(gc.Id);
                                    _lastStatistic.goReadContacts--;
                                    continue;
                                }
                                if (gc.Updated > ((OneContact)goContacts[gc.Id])._ModifyDateTime)
                                {
                                    goContacts.Remove(gc.Id);
                                    _lastStatistic.goReadContacts--;
                                }
                                else
                                {
                                    continue;
                                }
                            }
                            oc = new OneContact(gc);
                            if (SettingsProvider.Instance.IsFirstTime)
                            {
                                oc.ClearReference();
                            }
                            goContacts.Add(gc.Id, oc);
                            _lastStatistic.goReadContacts++;
                        }
                    }
                }
                else ///need clear cache read data
                {
                    goContacts.Clear();
                }
            }

            if (IsReadAllContact)
            {
                LoggerProvider.Instance.Logger.Debug("Read all data from Gmail");
                OneContact oc = null;
//                gp.ClearContactItems(); // need refresh before start next read, because ContactItems are cached in program
                _goMaxContacts          = gp.CountContact();
                syncinfo.GoogleContacts = _goMaxContacts;
                syncinfo.WorkOnMax      = _goMaxContacts;
                int i = 0;
                syncinfo.WorkOnNextStep();
                foreach (Google.Contacts.Contact gc in gp.ContactItems.Entries)
                {
                    syncinfo.WorkOn = ++i;
                    syncinfo.WorkOnNextStep();
                    oc = new OneContact(gc);
                    if (SettingsProvider.Instance.IsFirstTime)
                    {
                        oc.ClearReference();
                    }
                    goContacts.Add(gc.Id, oc);
                }
                _lastStatistic.goReadContacts += i;
                syncinfo.GoogleContacts        = goContacts.Count;
            }
        }
        /// <summary>
        /// Step first - read all outlook contacts
        /// </summary>
        private void Step1ReadOutlook()
        {
            bool          IsNeedReadAllData = true;
            bool          IsNeedReadNewData = false;
            List <string> toread            = new List <string>(); /// list EntryID for reading
            List <string> todelete          = new List <string>(); /// list EntryID for delete

            if (SettingsProvider.Instance.IsUseOutlookCache)
            {
                LoggerProvider.Instance.Logger.Debug("Read data from cache for Outlook");
                ouCacheTime = Utils.LoadCacheDate(true);
                ouContacts  = Utils.ReadOutlookFromCache(ref ouCacheTime);
                if ((ouCacheTime > DateTime.MinValue) && (ouCacheTime < DateTime.Now) && (ouContacts.Count > 0)) // Data read from cache is good
                {
                    //_lastStatistic.ouReadContacts = ouContacts.Count;
                    Dictionary <string, DateTime> ouall = OutlookProvider.Instance.GetTableFilter(ouCacheTime);
                    DateTime ouDate;

                    foreach (string s in ouContacts.Keys)
                    {
                        todelete.Add(s);
                    }

                    foreach (string EntID in ouall.Keys)
                    {
                        ouDate = ouall[EntID];
                        if (ouContacts.ContainsKey(EntID)) /// is EntID found in current cached data
                        {
                            todelete.Remove(EntID);
                            if (((OneContact)ouContacts[EntID])._ModifyDateTime < ouDate) //date from curent select is
                            {
                                ouContacts.Remove(EntID);
                                toread.Add(EntID);
                            }
                        }
                        else
                        {
                            toread.Add(EntID);
                        }
                    }
                    /// in toread now only new EntryID
                    /// in todelete now only contact deleted in outlook, this need clear from cache, because in last two steps it delete from google to
                    foreach (string s in todelete)
                    {
                        ouContacts.Remove(s);
                    }
                    IsNeedReadNewData = toread.Count > 0;
                }
                else
                {
                    LoggerProvider.Instance.Logger.Debug("Data from Outlook cache isn't valid");
                }
            }
            if (IsNeedReadNewData) // need read new contact data to cache
            {
                LoggerProvider.Instance.Logger.Debug("Read only new data from Outlook");
                Outlook.Items it = op.OutlookItems();
                //_ouMaxContacts = op.CountContact();
                syncinfo.OutlookContacts = toread.Count;
                syncinfo.WorkOnMax       = toread.Count;
                Outlook.ContactItem oci = null;
                OneContact          oc  = null;
                object works            = null;
                int    i    = 0;
                int    read = 0;

                syncinfo.WorkOnNextStep();
                for (; i < toread.Count; i++)
                {
                    syncinfo.WorkOn = i + 1;
                    syncinfo.WorkOnNextStep();

                    works = OutlookProvider.Instance.FindItemfromID(toread[i]);

                    //if (i == 0)
                    //    works = it.GetFirst();
                    //else
                    //    works = it.GetNext();
                    if (works is Outlook.DistListItem)
                    {
                        continue;
                    }
                    oci = works as Outlook.ContactItem;
                    if (works == null)
                    {
                        continue;
                    }
                    if (toread.Contains(oci.EntryID))
                    {
                        oc = new OneContact(oci);
                        if (SettingsProvider.Instance.IsFirstTime)
                        {
                            oc.ClearReference();
                        }
                        ouContacts.Add(oci.EntryID, oc);
                    }
                    read++;
                }
                _lastStatistic.ouReadContacts += read;
                syncinfo.OutlookContacts       = ouContacts.Count;
                IsNeedReadAllData              = false;
            }
            if (IsNeedReadAllData)
            {
                /// because need read all data. Before this need remove all cached data
                ouContacts.Clear();
                /// start read all data
                ouCacheTime = DateTime.MinValue;
                LoggerProvider.Instance.Logger.Debug("Read all data from Outlook");
                Outlook.Items it = op.OutlookItems();
                _ouMaxContacts           = op.CountContact();
                syncinfo.OutlookContacts = _ouMaxContacts;
                syncinfo.WorkOnMax       = _ouMaxContacts;
                Outlook.ContactItem oci = null;
                OneContact          oc  = null;
                object works            = null;
                int    i    = 0;
                int    read = 0;

                syncinfo.WorkOnNextStep();
                for (; i < _ouMaxContacts; i++)
                {
                    syncinfo.WorkOn = i + 1;
                    syncinfo.WorkOnNextStep();
                    if (i == 0)
                    {
                        works = it.GetFirst();
                    }
                    else
                    {
                        works = it.GetNext();
                    }
                    if (works is Outlook.DistListItem)
                    {
                        continue;
                    }
                    oci = works as Outlook.ContactItem;
                    if (works == null)
                    {
                        continue;
                    }
                    oc = new OneContact(oci);
                    if (SettingsProvider.Instance.IsFirstTime)
                    {
                        oc.ClearReference();
                    }
                    ouContacts.Add(oci.EntryID, oc);
                    read++;
                }
                _lastStatistic.ouReadContacts += read;
                syncinfo.OutlookContacts       = ouContacts.Count;
            }
        }