public PicasaService GetPicasaService(bool recreate = false)
        {
            if (recreate)
            {
                //Recreate service
                _picasaService = null;
                //Get google drive about to sync autorization
                //Because unknown problems in picasa autorization
                var drive = new GoogleDriveClient();
                drive.GetAbout();
            }

            if (_picasaService == null)
            {
                var creditals = GoogleDriveClient.GetCreditals();

                var requestFactory = new GDataRequestFactory(null);
                requestFactory.CustomHeaders.Add("Authorization: Bearer " + creditals.Token.AccessToken);
                requestFactory.CustomHeaders.Add("Gdata-version: 2");
                _picasaService = new PicasaService("api-project");
                _picasaService.RequestFactory = requestFactory;
            }
            return _picasaService;
        }
        public static string GetGooglePhotoFolderId(Action<string> logText = null)
        {
            if (_googlePhotoFolderId != null)
                return _googlePhotoFolderId;

            
            List<string> sugestionNames = new List<string>() { "Google Photos", "Google Фото", "Google Photo" };
            var local = GetSavedName();
            if (!String.IsNullOrWhiteSpace(local))
                sugestionNames.Insert(0, local);
            

            var photoFolders = new List<Google.Apis.Drive.v2.Data.File>();
            while (true)
            {
                try
                {
                    if (logText != null)
                    {
                        logText("Login on google.");
                        if (!Directory.Exists(GoogleDriveClient.CredPath))
                            logText("New browser window will appear. You should click accept for work with app.");
                    }
                    var google = new GoogleDriveClient();
                    if (logText != null)
                        logText("Login Ok.");
                    foreach (var sg in sugestionNames)
                    {
                        photoFolders = google.GetDirectories(sg, "root");
                        if (photoFolders.Count > 0)
                            break;
                    }
                }
                catch (System.Threading.ThreadAbortException ex)
                {
                    return null;
                }
                catch (Exception ex)
                {
                    if (MessageBox.Show("Can't connect to google drive. Probably something wrong with your internet connection?\r\nTry again please.\r\n"+
                        "\r\nException Code:\r\n"+ex.ToString(),
                        "Warning", MessageBoxButtons.RetryCancel, MessageBoxIcon.Warning) ==
                        DialogResult.Retry)
                        continue;
                    else
                        return null;
                }
                break;
            }

            if (photoFolders.Count == 1)
                return photoFolders[0].Id;

            if (photoFolders.Count > 1)
            {
                MessageBox.Show("Unexpected error. Too many photo folders.\r\n Remove 'Google photos' folders, which is not needed.");
                return null;
            }

            //Can't found photo folder

            if (_thisForm == null || _thisForm.IsDisposed)
                _thisForm = new GetGooglePhotosFolder();

            _thisForm.FillGoogleDirs();

            _thisForm.ShowDialog();
            var result = _thisForm.result;
            var resultName = _thisForm.resultName;
            _thisForm.Dispose();
            if (!String.IsNullOrWhiteSpace(result))
            {
                if (!String.IsNullOrWhiteSpace(resultName))
                    SetSavedName(resultName);
                _googlePhotoFolderId = result;
            }
            return result;
        }
 public void FillGoogleDirs()
 {
     var google = new GoogleDriveClient();
     var folders = google.GetDirectories(null, "root");
     _dirs = new Dictionary<string, string>();
     radioListBox.Items.Clear();
     foreach (var folder in folders)
     {
         if (!_dirs.ContainsKey(folder.Title))
         {
             _dirs.Add(folder.Title, folder.Id);
             radioListBox.Items.Add(folder.Title);
         }
     } 
 }
        public void TrashAll(string drivePhotoDirId)
        {
            GoogleDriveClient drive = new GoogleDriveClient();
            
            LogText("Search for files already in Google Photos directory on Google Drive. It can take a long time...");
            var googleFilesLst = drive.GetFiles(null, null);
            if (googleFilesLst.Count == 0)
            {
                LogText("No files found");
                return;
            }
            else
                LogText("Found " + googleFilesLst.Count + " files");

            ResetProgress(googleFilesLst.Count);
            LogText("MOVE ALL FILES TO TRASH...");
            foreach (var file in googleFilesLst)
            {
                drive.TrashFile(file.Id);
                IncreaseProgress();                
            }
            ResetProgress(10);
            LogText("READY");
        }
        public void Organize(List<TreeNode> rootNodes, string drivePhotoDirId, bool driveOrg = true, bool albumOrg = true, bool useDateTag = true)
        {
            LogText("Search for files on local drive");
            localFiles = GetFilesFromNodes(rootNodes);
            if (localFiles.Count ==0)
            {
                LogText("No files found");
                return;
            }

            GoogleDriveClient drive = null;
            if (driveOrg)
                drive = new GoogleDriveClient();
            PicasaClient picasa = null;
            if (albumOrg)
                picasa = new PicasaClient();

            var filesForMoving = new HashSet<string>();
            
            LogText("Search for files already in Google Photos directory on Google Drive. It can take a long time...");
            var googleFilesLst = drive.GetFiles(null, drivePhotoDirId);
            googleFiles = new Dictionary<string, List<File>>();
            foreach (var file in googleFilesLst)
            {
                //Do not need trash files here
                //var x = file.ExplicitlyTrashed;
                if (!googleFiles.ContainsKey(file.OriginalFilename))
                    googleFiles.Add(file.OriginalFilename, new List<File>());
                googleFiles[file.OriginalFilename].Add(file);
            }
            if (googleFilesLst.Count == 0)
            {
                LogText("No files found");
                return;
            }
            else
                LogText("Found " + googleFilesLst.Count + " files");
                
            filesForMoving.UnionWith(googleFiles.Keys);

            //Search for picassa files 
            LogText("Search for exist photo albums");
            var picasaAlbumsLst = picasa.GetAlbums();
            //Album by name 
            picasaAlbumsByName = new Dictionary<string, AlbumAccessor>();
            foreach (var picasaAlbum in picasaAlbumsLst)
            {
                if (!picasaAlbumsByName.ContainsKey(picasaAlbum.AlbumTitle))
                    picasaAlbumsByName.Add(picasaAlbum.AlbumTitle, picasaAlbum);
            }
            LogText("Found " + picasaAlbumsLst.Count + " albums");

            
            picasaFiles = new Dictionary<string, List<PicasaEntry>>();
            picasaFilesId = new HashSet<string>();
            googleDirs = new Dictionary<string, string>();
            preferableDirs = new Dictionary<string, Tuple<string, string>>();


            /*
            LogText("Search for media files in Picasa api");
            var alreadyFoundExt = new HashSet<string>();
            
            foreach (var localFile in localFiles.Keys)
            {
                var ext = System.IO.Path.GetExtension(localFile).ToLower();
                if (alreadyFoundExt.Contains(ext) || !videoExt.Contains(ext))
                    continue;
                alreadyFoundExt.Add(ext);
                var foundAlbums = new HashSet<string>();
                var picasaFoundFiles = picasa.GetPhotos(null, ext);
                foreach (var file in picasaFoundFiles)
                {
                    AddPicasaFile(file, picasaFiles, picasaFilesId);
                    var picasaFoto = new PhotoAccessor(file);
                    foundAlbums.Add(picasaFoto.AlbumId);
                }
                //Also try to add any files from album of found files
                foreach (var albumId in foundAlbums)
                    AddPicasaFiles(picasa, picasaFiles, picasaFilesId, albumId);
            }
            LogText("Found " + picasaFiles.Count + " files");*/

            //filesForMoving.UnionWith(picasaFiles.Keys);

            //System.IO.File.WriteAllLines("localFiles", localFiles.Keys.ToList());

            LogText("MOVING FILES...");
            ResetProgress(filesForMoving.Count);
            bool hasError = false;

            var opt = new ParallelOptions() { MaxDegreeOfParallelism = 10 };
            //foreach (var googleFilePair in googleFiles)
            Parallel.ForEach(filesForMoving, opt, (googleFilePair) =>
            {
                if (!localFiles.ContainsKey(googleFilePair))
                {
                    IncreaseProgress();
                    return;
                }

                if (hasError)
                    return;

                for (int i = 0; i < 3; i++)
                {
                    try
                    {
                        MoveFile(googleFilePair, drivePhotoDirId);
                        if (i != 0)
                            LogText("Try succeeded.");
                        break;
                    }
                    catch (Exception ex)
                    {
                        if (i < 2)
                        {
                            LogText("Error moving " + googleFilePair + ". Try again...");
                            if (i==1)
                            {
                                lock (picasaFiles)
                                {
                                    //Sometimes picassa and all already found files creditals coul be expired
                                    //Will delete them all and reinit as usual.
                                    picasaFiles.Clear();
                                    picasaFilesId.Clear();
                                }
                            }
                        }
                        else
                        {
                            hasError = true;
                            throw ex;
                        }
                    }
                }
                IncreaseProgress();
            });
            LogText("\r\nREADY");
            ResetProgress(100);
        }
        public void FixVideoDates(List<TreeNode> rootNodes, string drivePhotoDirId)
        {
            LogText("Search for files on local drive");
            localFiles = GetFilesFromNodes(rootNodes);
            if (localFiles.Count == 0)
            {
                LogText("No files found");
                return;
            }

            GoogleDriveClient drive = new GoogleDriveClient();
            
            var filesForFixing = new HashSet<string>();

            LogText("Search for files already in Google Photos directory on Google Drive. It can take a long time...");
            var googleFilesLst = drive.GetFiles(null, drivePhotoDirId);
            googleFiles = new Dictionary<string, List<File>>();
            int hasVideoFiles = 0;
            foreach (var file in googleFilesLst)
            {
                if (!videoExt.Contains("."+file.FileExtension.ToLower()))
                    continue;
                //Do not need trash files here
                //var x = file.ExplicitlyTrashed;
                if (!googleFiles.ContainsKey(file.OriginalFilename))
                    googleFiles.Add(file.OriginalFilename, new List<File>());
                googleFiles[file.OriginalFilename].Add(file);
                hasVideoFiles++;
            }
            if (hasVideoFiles == 0)
            {
                LogText("No video files found");
                return;
            }
            else
                LogText("Found " + hasVideoFiles + " video files");

            filesForFixing.UnionWith(googleFiles.Keys);
            
            //filesForMoving.UnionWith(picasaFiles.Keys);

            //System.IO.File.WriteAllLines("localFiles", localFiles.Keys.ToList());

            LogText("FIXING VIDEO TIME..");
            ResetProgress(filesForFixing.Count);
            bool hasError = false;

            var opt = new ParallelOptions() { MaxDegreeOfParallelism = 1 };
            //foreach (var googleFilePair in googleFiles)
            Parallel.ForEach(filesForFixing, opt, (googleFilePair) =>
            {
                if (!localFiles.ContainsKey(googleFilePair))
                {
                    IncreaseProgress();
                    return;
                }

                if (hasError)
                    return;

                for (int i = 0; i < 3; i++)
                {
                    try
                    {
                        FixVideoFile(googleFilePair, drivePhotoDirId);
                        if (i != 0)
                            LogText("Try succeeded.");
                        break;
                    }
                    catch (Exception ex)
                    {
                        if (i < 2)
                        {
                            LogText("Error fixing " + googleFilePair + ". Try again...");
                            if (i == 1)
                            {
                                lock (picasaFiles)
                                {
                                    //Sometimes picassa and all already found files creditals coul be expired
                                    //Will delete them all and reinit as usual.
                                    picasaFiles.Clear();
                                    picasaFilesId.Clear();
                                }
                            }
                        }
                        else
                        {
                            hasError = true;
                            throw ex;
                        }
                    }
                }
                IncreaseProgress();
            });
            LogText("\r\nREADY");
            ResetProgress(100);
        }