/// <summary>
        /// Creates an action result with a thumbnail image of a file in the storage.
        /// </summary>
        /// <param name="originalMetadata">Metadata of the original image file.</param>
        /// <param name="storage">The storage service used to store files.</param>
        /// <param name="dateTimeService">Date time service used to get current date and time.</param>
        /// <param name="maxWidth">Maximum width of the thumbnail image.</param>
        /// <param name="maxHeight">Maximum height of the thumbnail image.</param>
        /// <param name="useCache">Whether to use a cached thumbnail or not.</param>
        /// <returns>The ActionResult containing the thumbnail image.</returns>
        protected ActionResult GetOrCreateThumb(
            FileMetadata originalMetadata,
            IBlobStorageManager storage,
            IDateTimeService dateTimeService,
            int maxWidth,
            int maxHeight,
            bool useCache = true)
        {
            if (originalMetadata == null)
            {
                throw new ArgumentNullException("originalMetadata");
            }

            if (originalMetadata.OwnerUserId == this.DbUser.Id)
            {
                var fileNamePrefix = Path.GetDirectoryName(originalMetadata.BlobName) + "\\";
                var normalFileName = StringHelper.NormalizeFileName(originalMetadata.SourceFileName);

                var thumbName = string.Format(
                    "{0}\\{1}file-{2}-thumb-{4}x{5}-{3}",
                    originalMetadata.ContainerName,
                    fileNamePrefix,
                    originalMetadata.Id,
                    normalFileName,
                    maxWidth,
                    maxHeight);

                var fileName = string.Format("{0}\\{1}", originalMetadata.ContainerName, originalMetadata.BlobName);

                int originalMetadataId = originalMetadata.Id;
                var metadataProvider   = new DbFileMetadataProvider(this.db, dateTimeService, this.DbUser.PracticeId);

                var thumbResult = ImageHelper.TryGetOrCreateThumb(
                    originalMetadataId,
                    maxWidth,
                    maxHeight,
                    fileName,
                    thumbName,
                    useCache,
                    storage,
                    metadataProvider);

                switch (thumbResult.Status)
                {
                case CreateThumbStatus.Ok: return(this.File(thumbResult.Data, thumbResult.ContentType));

                case CreateThumbStatus.SourceFileNotFound: return(new StatusCodeResult(HttpStatusCode.NotFound));

                case CreateThumbStatus.SourceIsNotImage: return(this.Redirect(this.Url.Content("~/Content/Images/App/FileIcons/generic-outline.png")));

                case CreateThumbStatus.SourceImageTooLarge: return(this.Redirect(this.Url.Content("~/Content/Images/App/FileIcons/generic-outline.png")));

                default: throw new NotImplementedException();
                }
            }

            return(new StatusCodeResult(HttpStatusCode.NotFound));
        }
        public FilesStatus GetFilesStatus(PatientFileViewModel fileModel, string prefix)
        {
            var fileName = fileModel.SourceFileName;

            var containerName = fileModel.ContainerName;
            var sourceFileName = Path.GetFileName(fileModel.SourceFileName ?? "") ?? "";
            var normalFileName = StringHelper.RemoveDiacritics(sourceFileName.ToLowerInvariant());
            var fileNamePrefix = Path.GetDirectoryName(fileModel.BlobName) + "\\";

            var fullStoragePath = string.Format("{0}\\{1}file-{2}-{3}", containerName, fileNamePrefix, fileModel.Id, normalFileName);

            var fileStatus = new FilesStatus(fileModel.Id, fileModel.MetadataId, fileName, fileModel.FileLength, prefix, fileModel.FileTitle);

            var isPatientFiles = Regex.IsMatch(fileModel.ContainerName, @"^patient-files-\d+$");

            // Validating each file location... otherwise this could be a security hole.
            if (!isPatientFiles)
                throw new Exception("Invalid file location for patient files.");

            var fileMetadataProvider = new DbFileMetadataProvider(this.db, this.datetimeService, this.DbUser.PracticeId);

            bool imageThumbOk = false;
            try
            {
                var thumbName = string.Format("{0}\\{1}file-{2}-thumb-{4}x{5}-{3}", containerName, fileNamePrefix, fileModel.MetadataId, normalFileName, 120, 120);
                var thumbResult = ImageHelper.TryGetOrCreateThumb(fileModel.MetadataId, 120, 120, fullStoragePath, thumbName, true, storage, fileMetadataProvider);
                if (thumbResult.Status == CreateThumbStatus.Ok)
                {
                    fileStatus.ThumbnailUrl = @"data:" + thumbResult.ContentType + ";base64," + Convert.ToBase64String(thumbResult.Data);
                    fileStatus.IsInGallery = true;
                    imageThumbOk = true;
                }
            }
            // ReSharper disable EmptyGeneralCatchClause
            catch
            // ReSharper restore EmptyGeneralCatchClause
            {
            }

            if (!imageThumbOk)
            {
                if (StringHelper.IsDocumentFileName(fileName))
                {
                    fileStatus.IconClass = "document-file-icon";
                }
                else
                {
                    fileStatus.IconClass = "generic-file-icon";
                }
            }

            bool isTemp = fileModel.Id == null;
            if (isTemp)
            {
                var location = string.Format("{0}\\{1}", fileModel.ContainerName, fileModel.BlobName);
                if (imageThumbOk)
                    fileStatus.UrlLarge = this.Url.Action("Image", "TempFile", new { w = 1024, h = 768, id = fileModel.MetadataId, location });

                fileStatus.UrlFull = this.Url.Action("File", "TempFile", new { id = fileModel.MetadataId, location });
            }
            else
            {
                if (imageThumbOk)
                    fileStatus.UrlLarge = this.Url.Action("Image", "PatientFiles", new { w = 1024, h = 768, id = fileModel.Id });

                fileStatus.UrlFull = this.Url.Action("File", "PatientFiles", new { id = fileModel.Id });
            }

            return fileStatus;
        }
        public ActionResult Edit(Dictionary<string, PatientFilesGroupViewModel> patientFilesGroups)
        {
            var kv = patientFilesGroups.Single();
            var formModel = kv.Value;

            PatientFileGroup dbFileGroup;

            if (formModel.Id == null)
            {
                Debug.Assert(formModel.PatientId != null, "formModel.PatientId != null");
                dbFileGroup = new PatientFileGroup
                    {
                        PatientId = formModel.PatientId.Value,
                        PracticeId = this.DbUser.PracticeId,
                        CreatedOn = this.datetimeService.UtcNow,
                    };

                this.db.PatientFileGroups.AddObject(dbFileGroup);
            }
            else
            {
                dbFileGroup = this.db.PatientFileGroups
                    .Include("PatientFiles")
                    .Include("PatientFiles.FileMetadata")
                    .FirstOrDefault(pe => pe.Id == formModel.Id);
            }

            Debug.Assert(dbFileGroup != null, "dbFileGroup != null");
            var allExistingFilesInGroup = dbFileGroup.PatientFiles.ToDictionary(pf => pf.Id);

            var idsToKeep = new HashSet<int>(formModel.Files.Where(f => f.Id != null).Select(f => f.Id.Value));

            var storageActions = new List<Action>(formModel.Files.Count);

            var metadataProvider = new DbFileMetadataProvider(this.db, this.datetimeService, this.DbUser.PracticeId);
            var metadataDic = metadataProvider.GetByIds(formModel.Files.Select(f => f.MetadataId).ToArray()).ToDictionary(f => f.Id);

            foreach (var eachFile in formModel.Files)
            {
                // Validating each file location... otherwise this could be a security hole.
                FileMetadata metadata;
                metadataDic.TryGetValue(eachFile.MetadataId, out metadata);

                if (metadata == null)
                    return new StatusCodeResult(HttpStatusCode.NotFound, "Arquivo não encontrado. Outra pessoa deve ter removido esse arquivo neste instante.");

                var validContainer = string.Format("patient-files-{0}", this.DbUser.Id);

                if (metadata.ContainerName != validContainer)
                    throw new Exception("Invalid file location.");

                PatientFile patientFile;

                if (eachFile.Id == null)
                {
                    // creating and adding the new patient file
                    Debug.Assert(formModel.PatientId != null, "formModel.PatientId != null");

                    patientFile = new PatientFile
                    {
                        FileMetadataId = metadata.Id,
                        PatientId = formModel.PatientId.Value,
                        PracticeId = this.DbUser.PracticeId,
                    };

                    dbFileGroup.PatientFiles.Add(patientFile);

                    // changing file metadata:
                    // - it is not temporary anymore
                    // - tag is free for another operation
                    metadata.ExpirationDate = null;
                    metadata.Tag = null;
                }
                else if (!allExistingFilesInGroup.TryGetValue(eachFile.Id.Value, out patientFile))
                {
                    return new StatusCodeResult(HttpStatusCode.NotFound, "Arquivo não encontrado. Outra pessoa deve ter removido esse arquivo neste instante.");
                }

                Debug.Assert(patientFile != null, "patientFile != null");

                patientFile.Title = eachFile.FileTitle;
            }

            // deleting files that were removed
            foreach (var patientFileKv in allExistingFilesInGroup)
            {
                if (!idsToKeep.Contains(patientFileKv.Key))
                {
                    // create delegate to kill the file metadata and the storage blob
                    // this is going to be called latter
                    var metadata = patientFileKv.Value.FileMetadata;
                    Action removeFile = () => TempFileController.DeleteFileByMetadata(metadata, this.db, this.storage);
                    storageActions.Add(removeFile);

                    // delete patient file (note that changes are not being saved yet)
                    this.db.PatientFiles.DeleteObject(patientFileKv.Value);
                }
            }

            if (formModel.Files.Count == 0)
            {
                this.ModelState.AddModelError(string.Format("PatientFilesGroups[{0}].Files", kv.Key), "Deve haver pelo menos um arquivo na lista.");
            }

            if (this.ModelState.IsValid)
            {
                dbFileGroup.GroupTitle = formModel.Title;
                dbFileGroup.GroupNotes = formModel.Notes;
                Debug.Assert(formModel.FileGroupDate != null, "formModel.FileGroupDate != null");
                dbFileGroup.FileGroupDate = this.ConvertToUtcDateTime(formModel.FileGroupDate.Value);
                Debug.Assert(formModel.ReceiveDate != null, "formModel.ReceiveDate != null");
                dbFileGroup.ReceiveDate = this.ConvertToUtcDateTime(formModel.ReceiveDate.Value);

                dbFileGroup.Patient.IsBackedUp = false;
                this.db.SaveChanges();

                // moving files that are stored in a temporary location
                foreach (var moveAction in storageActions)
                    moveAction();

                return this.View("Details", GetViewModel(this.storage, dbFileGroup, this.DbUser.Id, this.GetToLocalDateTimeConverter()));
            }

            FillMissingInfos(formModel, this.db.FileMetadatas);
            FillFileLengths(this.storage, formModel, this.DbUser.Id);

            this.ViewBag.FilesStatusGetter = (FilesStatusGetter)this.GetFilesStatus;

            return this.View("Edit", formModel);
        }
        /// <summary>
        /// Creates an action result with a thumbnail image of a file in the storage.
        /// </summary>
        /// <param name="originalMetadata">Metadata of the original image file.</param>
        /// <param name="storage">The storage service used to store files.</param>
        /// <param name="dateTimeService">Date time service used to get current date and time.</param>
        /// <param name="maxWidth">Maximum width of the thumbnail image.</param>
        /// <param name="maxHeight">Maximum height of the thumbnail image.</param>
        /// <param name="useCache">Whether to use a cached thumbnail or not.</param>
        /// <returns>The ActionResult containing the thumbnail image.</returns>
        protected ActionResult GetOrCreateThumb(
            FileMetadata originalMetadata,
            IBlobStorageManager storage,
            IDateTimeService dateTimeService,
            int maxWidth,
            int maxHeight,
            bool useCache = true)
        {
            if (originalMetadata == null)
                throw new ArgumentNullException("originalMetadata");

            if (originalMetadata.OwnerUserId == this.DbUser.Id)
            {
                var fileNamePrefix = Path.GetDirectoryName(originalMetadata.BlobName) + "\\";
                var normalFileName = StringHelper.NormalizeFileName(originalMetadata.SourceFileName);

                var thumbName = string.Format(
                    "{0}\\{1}file-{2}-thumb-{4}x{5}-{3}",
                    originalMetadata.ContainerName,
                    fileNamePrefix,
                    originalMetadata.Id,
                    normalFileName,
                    maxWidth,
                    maxHeight);

                var fileName = string.Format("{0}\\{1}", originalMetadata.ContainerName, originalMetadata.BlobName);

                int originalMetadataId = originalMetadata.Id;
                var metadataProvider = new DbFileMetadataProvider(this.db, dateTimeService, this.DbUser.PracticeId);

                var thumbResult = ImageHelper.TryGetOrCreateThumb(
                    originalMetadataId,
                    maxWidth,
                    maxHeight,
                    fileName,
                    thumbName,
                    useCache,
                    storage,
                    metadataProvider);

                switch (thumbResult.Status)
                {
                    case CreateThumbStatus.Ok: return this.File(thumbResult.Data, thumbResult.ContentType);
                    case CreateThumbStatus.SourceFileNotFound: return new StatusCodeResult(HttpStatusCode.NotFound);
                    case CreateThumbStatus.SourceIsNotImage: return this.Redirect(this.Url.Content("~/Content/Images/App/FileIcons/generic-outline.png"));
                    case CreateThumbStatus.SourceImageTooLarge: return this.Redirect(this.Url.Content("~/Content/Images/App/FileIcons/generic-outline.png"));
                    default: throw new NotImplementedException();
                }
            }

            return new StatusCodeResult(HttpStatusCode.NotFound);
        }
        /// <summary>
        /// Upload whole file.
        /// </summary>
        /// <param name="prefix"> The prefix of the fields to be placed in the HTML. </param>
        /// <param name="location"> The location where the temporary file should be stored. </param>
        /// <returns> The <see cref="ActionResult"/> containing information about execution of the upload. </returns>
        private ActionResult UploadWholeFile(string prefix, string location, string tag)
        {
            var statuses = new List<FilesStatus>();

            for (int i = 0; i < this.Request.Files.Count; i++)
            {
                var file = this.Request.Files[i];

                Debug.Assert(file != null, "file != null");

                var containerName = location.Split("\\".ToCharArray(), 2).FirstOrDefault();
                var sourceFileName = Path.GetFileName(file.FileName ?? "") ?? "";
                var normalFileName = StringHelper.NormalizeFileName(sourceFileName);
                var fileNamePrefix = location.Split("\\".ToCharArray(), 2).Skip(1).FirstOrDefault();
                var fileExpirationDate = this.datetimeService.UtcNow + TimeSpan.FromDays(file.ContentLength < 10 * 1024000 ? 2 : 10);

                Debug.Assert(sourceFileName != null, "sourceFileName != null");

                var metadataProvider = new DbFileMetadataProvider(this.db, this.datetimeService, this.DbUser.PracticeId);

                // creating the metadata entry for the main file
                FileMetadata metadata = metadataProvider.CreateTemporary(
                    containerName,
                    sourceFileName,
                    string.Format("{0}file-{1}-{2}", fileNamePrefix, "{id}", normalFileName),
                    fileExpirationDate,
                    this.DbUser.Id,
                    tag,
                    formatWithId: true);

                metadata.OwnerUserId = this.DbUser.Id;

                metadataProvider.SaveChanges();

                // saving the file to the storage
                this.storage.UploadFileToStorage(file.InputStream, containerName, metadata.BlobName);

                // returning information to the client
                var fileStatus = new FilesStatus(metadata.Id, sourceFileName, file.ContentLength, prefix);

                bool imageThumbOk = false;
                try
                {
                    var fullStoragePath = string.Format("{0}\\{1}", containerName, metadata.BlobName);
                    var thumbName = string.Format("{0}\\{1}file-{2}-thumb-{4}x{5}-{3}", containerName, fileNamePrefix, metadata.Id, normalFileName, 120, 120);
                    var thumbResult = ImageHelper.TryGetOrCreateThumb(metadata.Id, 120, 120, fullStoragePath, thumbName, true, this.storage, metadataProvider);
                    if (thumbResult.Status == CreateThumbStatus.Ok)
                    {
                        fileStatus.ThumbnailUrl = @"data:" + thumbResult.ContentType + ";base64," + Convert.ToBase64String(thumbResult.Data);
                        fileStatus.IsInGallery = true;
                        imageThumbOk = true;
                    }
                }
                // ReSharper disable EmptyGeneralCatchClause
                catch
                // ReSharper restore EmptyGeneralCatchClause
                {
                }

                if (!imageThumbOk)
                {
                    if (StringHelper.IsDocumentFileName(sourceFileName))
                    {
                        fileStatus.IconClass = "document-file-icon";
                    }
                    else
                    {
                        fileStatus.IconClass = "generic-file-icon";
                    }
                }
                else
                {
                    fileStatus.UrlLarge = this.Url.Action("Image", new { w = 1024, h = 768, location, metadata.Id });
                }

                fileStatus.UrlFull = this.Url.Action("File", new { location, metadata.Id });

                fileStatus.DeleteUrl = this.Url.Action("Index", new { location, metadata.Id });

                statuses.Add(fileStatus);
            }

            return this.JsonIframeSafe(new { files = statuses });
        }