using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Security.Policy;
using System.Text;
using System.Threading.Tasks;
using Microsoft.InformationProtection;
using Microsoft.InformationProtection.File;
using Microsoft.InformationProtection.Protection;

namespace AipGateway.AIP
{
    // public struct ProtectionDetails
    // {
    //     public List<UserRoles> UserRoles;
    //     public List<UserRights> UserRights;
    //     public string TemplateId;
    //     public bool IsProtected;
    // }
    
    public class FileManager : AbstractManager
    {
        private IFileProfile _profile = null;
        private IFileEngine _engine = null;

        public FileManager()
        {
        }
        ~FileManager() => this.Dispose(false);
        public override void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize((object)this);
            
        }
        protected virtual void Dispose(bool disposing)
        {
            lock (this)
            {
                if (_profile != null & _engine != null)
                {
                    //_profile.UnloadEngineAsync(_engine.Settings.EngineId).Wait();
                }
                _engine = null;
                _profile = null;
            }
        }
        public override bool CreateProfile(ref MipContext mipContext)
        {
            try
            {
                var profileSettings = new FileProfileSettings(mipContext,
                    CacheStorageType.OnDiskEncrypted,
                    // CacheStorageType.InMemory,
                    new ConsentDelegateImplementation());

                // IFileProfile은 특정 애플리케이션에 대한 모든 SDK 작업의 루트입니다.
                _profile = Task.Run(async () => await MIP.LoadFileProfileAsync(profileSettings)).Result;
            }
            catch (Exception e)
            {
                SetError(1, "FileManager::CreateProfile Failed.", e.Message);
                return false;
            }
            return _profile != null;
        }

        public override bool CreateEngine(ref Identity identity, ref AuthDelegateImplementation authDelegate)
        {
            try
            {
                authDelegate.ResetError();

                //CultureInfo.CurrentCulture.Name;

                // 보호 엔진 설정 개체를 만듭니다. 첫 번째 매개변수인 엔진 ID에 빈 문자열을 전달하면 SDK가 GUID를 생성합니다.
                // 이메일 주소나 기타 고유한 값을 전달하면 동일한 사용자에 대해 캐시된 엔진이 매번 로드되도록 하는 데 도움이 됩니다.
                // 로캘 설정은 지원되며 특히 클라이언트 응용 프로그램의 경우 컴퓨터 로캘을 기반으로 제공되어야 합니다.
                var engineSettings = new FileEngineSettings(identity.Email, authDelegate, string.Empty, "en-US")
                {
                    // Provide the identity for service discovery.
                    Identity = identity,
                    // Set ProtectionOnlyEngine to true for AD RMS as labeling isn't supported
                    //ProtectionOnlyEngine = true
                };

                // Enable DKE
                // var functionsDict = engineSettings.ConfiguredFunctionality ?? new Dictionary<FunctionalityFilterType, bool>();
                // functionsDict[FunctionalityFilterType.DoubleKeyProtection] = true;
                // functionsDict[FunctionalityFilterType.DoubleKeyUserDefinedProtection] = true;
                // engineSettings.ConfiguredFunctionality = functionsDict;

                _engine = Task.Run(async () => await _profile.AddEngineAsync(engineSettings)).Result;

                //Console.WriteLine("File Engine Sensitivity Labels ======================================================");
                //var labels = _engine.SensitivityLabels;
                //for (int ii = 0; ii < labels.Count; ii++)
                //{
                    //Console.WriteLine("{0}: {1}, {2}", ii.ToString(), labels[ii].Id + " : " + labels[ii].Name, labels[ii].IsActive);
                //    Label label = _engine.GetLabelById(labels[ii].Id);
                //    if (label.Children.Count > 0)
                //    {
                //        for (int jj = 0; jj < label.Children.Count; jj++)
                //        {
                //            Console.WriteLine("\t{0}: {1}, {2}", jj.ToString(), label.Children[jj].Id + " : " + label.Children[jj].Name, label.Children[jj].IsActive);
                //        }
                //    }
                    // Console.WriteLine("{0}: {1}, {2}, {3}, {4}, {5}", ii.ToString(), label.Id + " : " + label.Name, label.IsActive, 
                    //     label.Sensitivity, label.ActionSource, label.Description);
                //}

                //Console.WriteLine("=======================================================================");
            }
            catch (Exception e)
            {
                if (authDelegate.LastErrNo != 0)
                {
                    SetError(authDelegate.LastErrNo, "FileManager::CreateEngine Failed.", authDelegate.LastErrMsg);
                }
                else
                {
                    SetError(2, "FileManager::CreateEngine Failed.", e.Message);
                }
                return false;
            }
            return _engine != null;
        }
        public IEnumerable<Label> SensitivityLabels()
        {
            return _engine.SensitivityLabels;
        }
        private IFileHandler CreateFileHandler(Stream inputStream, string outputFile)
        {
            if (inputStream == null)
            {
                SetError(91, "FileManager::CreateFileHandler Failed.", "요청한 스트림의 정보가 없습니다.");
                return null;
            }

            if (outputFile == null ||  outputFile.Length == 0)
            {
                SetError(91, "FileManager::CreateFileHandler Failed.", "요청한 출력 파일 이릅이 존재하지 않습니다.");
                return null;
            }

            try
            {
                var handler = Task.Run(async () => await _engine.CreateFileHandlerAsync(inputStream, outputFile, true))
                    .Result;
                return handler;
            }
            catch (Exception ex)
            {
                SetError(91, "FileManager::CreateFileHandler Failed.", ex.Message);
            }
            return null;
        }

        private Int64 GetFileSize(string fileName)
        {
            try
            {
                return new FileInfo(fileName).Length;
            }
            catch { return 0; }
        }
        private IFileHandler CreateFileHandler(string inputFile, string outputFile)
        {
            if (!File.Exists(inputFile))
            {
                SetError(91, "FileManager::CreateFileHandler Failed.", "요청한 파일이 존재하지 않습니다. " + inputFile);
                return null;
            }

            try
            {
                var handler = Task.Run(async () => await _engine.CreateFileHandlerAsync(inputFile, outputFile, true))
                    .Result;
                return handler;
            }
            catch (Exception ex)
            {
                SetError(91, "FileManager::CreateFileHandler Failed.", ex.Message);
            }
            return null;
        }

        
        public AipFileInfo GetFileInfo(Stream fileStream, string outputFileName)
        {
            //string outputFile = "c:\\data\\samplexxxxxx.pptx";// System.IO.Path.GetTempFileName();
            Console.WriteLine("FileManager::GetFileInfo: Create Template File, {0}", outputFileName);
            var handler = CreateFileHandler(fileStream, outputFileName);
            if (handler == null)
            {
                File.Delete(outputFileName);
                return null;
            }
            var result = GetFileInfo(handler);
            try
            {
                result.FileSize = fileStream.Length;
                File.Delete(outputFileName);
            }
            catch (Exception ex)
            {
                result.FileSize = 0;
                LastErrMsg = ex.Message;
            }
            return result;
        }

        public AipFileInfo GetFileInfo(string fileName)
        {
            var handler = CreateFileHandler(fileName, fileName);
            if (handler == null)
            {
                return null;
            }
            var result = GetFileInfo(handler);
            try
            {
                result.FileSize = GetFileSize(fileName);
            }
            catch(Exception ex)
            {
                result.FileSize = 0;
                LastErrMsg = ex.Message;
            }
            return result;
        }
        
        private AipFileInfo GetFileInfo(IFileHandler handler) 
        {
            if (handler == null)
            {
                return null;
            }

            AipFileInfo fileInfo = new AipFileInfo
            {
                Content = null,
                Label = null,
                Protection = null,
                OutputFileName = null,
                FileSize = 0,
            };
            fileInfo.OutputFileName = handler.OutputFileName;
            
            if (handler.Label != null)
            {
                fileInfo.Content = new AipContentLabel()
                {
                    //Label = Utilities.LabelToAip(handler.Label.Label),
                    CreationTime = handler.Label.CreationTime,
                    AssignmentMethod = (AipAssignmentMethod)handler.Label.AssignmentMethod,
                    IsProtectionAppliedFromLabel = handler.Label.IsProtectionAppliedFromLabel,
                };
                fileInfo.Label = Utilities.LabelToAip(handler.Label.Label);
            }

            if (handler.Protection != null)
            {
                fileInfo.Protection = new AipProtection()
                {
                    Owner = handler.Protection.Owner,
                    IssuedTo = handler.Protection.IssuedTo,
                    IsIssuedToOwner = handler.Protection.IsIssuedToOwner,
                    ContentId = handler.Protection.ContentId,
                    AuditedExtractAllowed = handler.Protection.AuditedExtractAllowed,
                    BlockSize = handler.Protection.BlockSize,
                    ProtectionDescriptor = null,
                };
                if (handler.Protection.ProtectionDescriptor != null)
                {
                    fileInfo.Protection.ProtectionDescriptor = new AipProtectionDescriptor()
                    {
                        ProtectionType = (AipProtectionType)handler.Protection.ProtectionDescriptor.ProtectionType,
                        TemplateId = handler.Protection.ProtectionDescriptor.TemplateId,
                        LabelInformation = new AipLabelInfo(),
                        LabelId = handler.Protection.ProtectionDescriptor.LabelId,
                        Owner = handler.Protection.ProtectionDescriptor.Owner,
                        ContentId = handler.Protection.ProtectionDescriptor.ContentId,
                        Name = handler.Protection.ProtectionDescriptor.Name,
                        Description = handler.Protection.ProtectionDescriptor.Description,
                        AllowOfflineAccess = handler.Protection.ProtectionDescriptor.AllowOfflineAccess,
                        Referrer = handler.Protection.ProtectionDescriptor.Referrer,
                        ContentValidUntil = handler.Protection.ProtectionDescriptor.ContentValidUntil,
                        DoubleKeyUrl = handler.Protection.ProtectionDescriptor.DoubleKeyUrl,
                    };
                    if (handler.Protection.ProtectionDescriptor.LabelInformation != null)
                    {
                        fileInfo.Protection.ProtectionDescriptor.LabelInformation.LabelId =
                            handler.Protection.ProtectionDescriptor.LabelInformation.LabelId;
                        fileInfo.Protection.ProtectionDescriptor.LabelInformation.TenantId =
                            handler.Protection.ProtectionDescriptor.LabelInformation.TenantId;
                    }
                }
            }
            return fileInfo;
        }
        public Label GetLabelById(string labelId)
        {
            Label label;
            try
            {
                label = _engine.GetLabelById(labelId);
            }
            catch (Exception ex)
            {
                SetError(99, "FileManager::GetLabel Failed. Request Label Id: " + labelId, ex.Message);
                return null;
            }

            return label;
        }

        /// <summary>
        /// ///////////////////////////////////////////////////////////////
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="actualFileName"></param>
        /// <param name="email"></param>
        /// <param name="labelId"></param>
        /// <param name="templateId"></param>
        /// <param name="comments"></param>
        /// <returns></returns>
        public SetFileInfo SetLabel(string fileName, string actualFileName, string email, string labelId, string templateId, string comments)
        {
            SetFileInfo result = new SetFileInfo()
            {
                errorNo = 0,
                errorMsg = "Success",
            };

            var handler = CreateFileHandler(fileName, actualFileName);
            if (handler == null)
            {
                result.errorNo = 201;
                result.errorMsg = LastErrMsg;
                return result;
            }
            result.fileSize = GetFileSize(fileName);
            return SetLabel(handler, actualFileName, email, labelId, templateId, comments, result);
        }
        public SetFileInfo SetLabel(Stream fileStream, string actualFileName, string email, string labelId, string templateId, string comments)
        {
            SetFileInfo result = new SetFileInfo()
            {
                errorNo = 0,
                errorMsg = "Success",
            };

            var handler = CreateFileHandler(fileStream, actualFileName);
            if (handler == null)
            {
                result.errorNo = 201;
                result.errorMsg = LastErrMsg;
                return result;
            }
            result.fileSize = fileStream.Length;
            return SetLabel(handler, actualFileName, email, labelId, templateId, comments, result);
        }
        public SetFileInfo SetLabel(IFileHandler handler, string actualFileName, string email, string labelId, string templateId, string comments, SetFileInfo result)
        {
            Label label = GetLabelById(labelId);
            if (label == null)
            {
                result.errorNo = 202;
                result.errorMsg = LastErrMsg;
                return result;
            }

            if (comments == "")
            {
                comments = "SetLabel";
            }
            LabelingOptions labelingOptions = new LabelingOptions()
            {
                AssignmentMethod = AssignmentMethod.Auto, //Standard,
                JustificationMessage = comments,
                IsDowngradeJustified = true
            };

            string ownerEmail = email;
            if (handler.Label != null && handler.Label.Label != null)
            {
                result.lableGuid = handler.Label.Label.Id;
            }
            if (handler.Protection != null)
            {
                ownerEmail = handler.Protection.Owner;
                result.fileOwner = handler.Protection.Owner;
                if (handler.Protection.ProtectionDescriptor != null)
                {
                    result.templateGuid = handler.Protection.ProtectionDescriptor.TemplateId;
                }
            }

            var protectionSettings = new ProtectionSettings
            {
                 PFileExtensionBehavior = PFileExtensionBehavior.Default,
            };
            if (ownerEmail != "")
            {
                protectionSettings.DelegatedUserEmail = ownerEmail;
            }

            try
            {
                handler.SetLabel(label, labelingOptions, protectionSettings);
                if (templateId != "")
                {
                    ProtectionDescriptor protectionDescriptor = new ProtectionDescriptor(templateId);
                    handler.SetProtection(protectionDescriptor, protectionSettings);
                }
            }
            catch (Exception ex)
            {
                result.errorNo = 203;
                result.errorMsg = ex.Message;
                SetError(53, "FileManager::SetLabel Failed.", ex.Message);
                return result;
            }

            bool isCommited = false;
            if (handler.IsModified())
            {
                isCommited = Task.Run(async () => await handler.CommitAsync(actualFileName)).Result;

            }
            if (isCommited)
            {
                //handler.NotifyCommitSuccessful(fileName);
                result.newFileSize = GetFileSize(actualFileName);
                result.newFileLabelGuid = labelId;
                result.newFileName = actualFileName;
                result.newFileOwner = ownerEmail;
                result.newFileTemplateGuid = labelId;
            }
            else
            {
                result.errorNo = 204;
                result.errorMsg = "AIP File CommitAsync Failed.";
                SetError(53, "FileManager::SetLabel Failed.", "Label Id: " + labelId + ", SetLabel Failed.");
            }
            AipFileInfo info = GetFileInfo(actualFileName);
            if (info != null)
            {
                if (info.Label != null)
                {
                    result.newFileLabelGuid = info.Label.Id;
                }
                if (info.Protection != null)
                {
                    result.newFileOwner = info.Protection.Owner;
                    if (info.Protection.ProtectionDescriptor != null)
                    {
                        result.newFileTemplateGuid = info.Protection.ProtectionDescriptor.TemplateId;
                    }
                }
            }
            return result;
        }

        /// <summary>
        /// //////////////////////////////////////////////////////////////
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="actualFileName"></param>
        /// <param name="email"></param>
        /// <param name="comments"></param>
        /// <param name="isDelProtection"></param>
        /// <returns></returns>
        public SetFileInfo DeleteLabel(string fileName, string actualFileName, string email, string comments, bool isDelProtection)
        {
            SetFileInfo result = new SetFileInfo()
            {
                errorNo = 0,
                errorMsg = "Success",
            };

            var outFileName = actualFileName == string.Empty ? fileName : actualFileName;
            var handler = CreateFileHandler(fileName, outFileName);
            if (handler == null)
            {
                result.errorNo = 201;
                result.errorMsg = LastErrMsg;
                return result;
            }
            result.fileSize = GetFileSize(fileName);
            return DeleteLabel(handler, actualFileName, email, comments, isDelProtection, result);
        }
        public SetFileInfo DeleteLabel(Stream fileStream, string actualFileName, string email, string comments, bool isDelProtection)
        {
            SetFileInfo result = new SetFileInfo()
            {
                errorNo = 0,
                errorMsg = "Success",
            };

            var handler = CreateFileHandler(fileStream, actualFileName);
            if (handler == null)
            {
                result.errorNo = 201;
                result.errorMsg = LastErrMsg;
                return result;
            }
            result.fileSize = fileStream.Length;
            return DeleteLabel(handler, actualFileName, email, comments, isDelProtection, result);
        }
        public SetFileInfo DeleteLabel(IFileHandler handler, string actualFileName, string email, string comments, bool isDelProtection, SetFileInfo result)
        {
            if (comments == "")
            {
                comments = "Delete Label by " + email;
            }
            LabelingOptions invokeLabelingOptions = new LabelingOptions()
            {
                AssignmentMethod = AssignmentMethod.Privileged, //because we are removing a high priority label
                JustificationMessage = comments,
                IsDowngradeJustified = true
            };

            string ownerEmail = email;
            if (handler.Label != null && handler.Label.Label != null)
            {
                result.lableGuid = handler.Label.Label.Id;
            }
            if (handler.Protection != null)
            {
                ownerEmail = handler.Protection.Owner;
                result.fileOwner = handler.Protection.Owner;
                if (handler.Protection.ProtectionDescriptor != null)
                {
                    result.templateGuid = handler.Protection.ProtectionDescriptor.TemplateId;
                }
            }

            var protectionSettings = new ProtectionSettings
            {
                PFileExtensionBehavior = PFileExtensionBehavior.Default,
            };
            if (ownerEmail != "")
            {
                protectionSettings.DelegatedUserEmail = ownerEmail;
            }

            try
            {
                if (isDelProtection && handler.Protection != null)
                {
                    if (handler.Protection.AccessCheck(Rights.Extract) || handler.Protection.AccessCheck(Rights.Owner))
                    {
                        handler.RemoveProtection();
                    }
                }
                handler.DeleteLabel(invokeLabelingOptions);
            }
            catch (Exception ex)
            {
                result.errorNo = 203;
                result.errorMsg = ex.Message;
                SetError(53, "FileManager::DeleteLabel Failed.", ex.Message);
                return result;
            }

            bool isCommited = false;
            if (handler.IsModified())
            {
                isCommited = Task.Run(async () => await handler.CommitAsync(actualFileName)).Result;
            }

            if (isCommited)
            {
                //handler.NotifyCommitSuccessful(fileName);
                result.newFileSize = GetFileSize(actualFileName);
                result.newFileLabelGuid = "";
                result.newFileName = actualFileName;
                result.newFileOwner = ownerEmail;
                result.newFileTemplateGuid = "";
            }
            else
            {
                result.errorNo = 204;
                result.errorMsg = "AIP File CommitAsync Failed.";
                SetError(54, "FileManager::DeleteLabel Failed.", "DeleteLabel Failed by " + ownerEmail);
            }
            AipFileInfo info = GetFileInfo(actualFileName);
            if (info != null)
            {
                if (info.Label != null)
                {
                    result.newFileLabelGuid = info.Label.Id;
                }
                if (info.Protection != null)
                {
                    result.newFileOwner = info.Protection.Owner;
                    if (info.Protection.ProtectionDescriptor != null)
                    {
                        result.newFileTemplateGuid = info.Protection.ProtectionDescriptor.TemplateId;
                    }
                }
            }
            return result;
        }

        /// <summary>
        /// /////////////////////////////////////////////////////////////////
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="actualFileName"></param>
        /// <param name="email"></param>
        /// <param name="templateId"></param>
        /// <param name="comments"></param>
        /// <returns></returns>
        public SetFileInfo SetProtection(string fileName, string actualFileName, string email, string templateId, string comments)
        {
            SetFileInfo result = new SetFileInfo()
            {
                errorNo = 0,
                errorMsg = "Success",
            };

            var handler = CreateFileHandler(fileName, actualFileName);
            if (handler == null)
            {
                result.errorNo = 201;
                result.errorMsg = LastErrMsg;
                return result;
            }
            result.fileSize = GetFileSize(fileName);
            return SetProtection(handler, actualFileName, email, templateId, comments, result);
        }
        public SetFileInfo SetProtection(Stream fileStream, string actualFileName, string email, string templateId, string comments)
        {
            SetFileInfo result = new SetFileInfo()
            {
                errorNo = 0,
                errorMsg = "Success",
            };

            var handler = CreateFileHandler(fileStream, actualFileName);
            if (handler == null)
            {
                result.errorNo = 201;
                result.errorMsg = LastErrMsg;
                return result;
            }
            result.fileSize = fileStream.Length;
            return SetProtection(handler, actualFileName, email, templateId, comments, result);
        }
        public SetFileInfo SetProtection(IFileHandler handler, string actualFileName, string email, string templateId, string comments, SetFileInfo result)
        {
            if (comments == "")
            {
                comments = "SetProtection";
            }

            string ownerEmail = email;
            if (handler.Label != null && handler.Label.Label != null)
            {
                result.lableGuid = handler.Label.Label.Id;
            }
            if (handler.Protection != null)
            {
                ownerEmail = handler.Protection.Owner;
                result.fileOwner = handler.Protection.Owner;
                if (handler.Protection.ProtectionDescriptor != null)
                {
                    result.templateGuid = handler.Protection.ProtectionDescriptor.TemplateId;
                }
            }

            try
            {
                ProtectionDescriptor protectionDescriptor = new ProtectionDescriptor(templateId);
                ProtectionSettings protectionSettings = new ProtectionSettings
                {
                    PFileExtensionBehavior = PFileExtensionBehavior.Default,
                };
                if (ownerEmail != "")
                {
                    protectionSettings.DelegatedUserEmail = ownerEmail;
                }
                handler.SetProtection(protectionDescriptor, protectionSettings);
            }
            catch (Exception ex)
            {
                result.errorNo = 204;
                result.errorMsg = ex.Message;
                SetError(54, "FileManager::SetProtect Failed.", ex.Message);
                return result;
            }

            bool isCommited = false;
            if (handler.IsModified())
            {
                try
                {
                    isCommited = Task.Run(async () => await handler.CommitAsync(actualFileName)).Result;
                }
                catch (Exception ex)
                {
                    // TODO: Exception catch 해야함.......... 여기서 캣치하면 정확한 오류 메시지를 확인 할 수 없음.
                    result.errorNo = 205;
                    result.errorMsg = "AIP File CommitAsync Failed." + ex.Message;
                    SetError(55, "FileManager::SetProtection CommitAsync Failed.", ex.Message);
                }
            }

            if (isCommited)
            {
                //handler.NotifyCommitSuccessful(fileName);
                result.newFileSize = GetFileSize(actualFileName);
                //result.newFileLabelGuid = string.Empty;
                result.newFileName = actualFileName;
                result.newFileOwner = ownerEmail;
                result.newFileTemplateGuid = string.Empty;
            }
            else
            {
                result.errorNo = 206;
                result.errorMsg = "AIP File CommitAsync Failed.";
                SetError(56, "FileManager::SetProtect Failed.", "Template Id: " + templateId + ", SetProtect Failed.");
            }
            AipFileInfo info = GetFileInfo(actualFileName);
            if (info != null)
            {
                if (info.Label != null)
                {
                    result.newFileLabelGuid = info.Label.Id;
                }
                if (info.Protection != null)
                {
                    result.newFileOwner = info.Protection.Owner;
                    if (info.Protection.ProtectionDescriptor != null)
                    {
                        result.newFileTemplateGuid = info.Protection.ProtectionDescriptor.TemplateId;
                    }
                }
            }
            return result;
        }

        /// <summary>
        /// ///////////////////////////////////////////////////////////////////
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="actualFileName"></param>
        /// <param name="email"></param>
        /// <param name="comments"></param>
        /// <returns></returns>
        public SetFileInfo RemoveProtection(string fileName, string actualFileName, string email, string comments)
        {
            SetFileInfo result = new SetFileInfo()
            {
                errorNo = 0,
                errorMsg = "Success",
            };

            var handler = CreateFileHandler(fileName, actualFileName);
            if (handler == null)
            {
                result.errorNo = 201;
                result.errorMsg = LastErrMsg;
                return result;
            }
            result.fileSize = GetFileSize(fileName);
            return RemoveProtection(handler, actualFileName, email, comments, result);
        }
        public SetFileInfo RemoveProtection(Stream fileStream, string actualFileName, string email, string comments)
        {
            SetFileInfo result = new SetFileInfo()
            {
                errorNo = 0,
                errorMsg = "Success",
            };

            var handler = CreateFileHandler(fileStream, actualFileName);
            if (handler == null)
            {
                result.errorNo = 201;
                result.errorMsg = LastErrMsg;
                return result;
            }
            result.fileSize = fileStream.Length;
            return RemoveProtection(handler, actualFileName, email, comments, result);
        }
        public SetFileInfo RemoveProtection(IFileHandler handler, string actualFileName, string email, string comments, SetFileInfo result)
        {
            string ownerEmail = email;
            if (handler.Label != null && handler.Label.Label != null)
            {
                result.lableGuid = handler.Label.Label.Id;
            }
            if (handler.Protection != null)
            {
                ownerEmail = handler.Protection.Owner;
            }

            if (comments == "")
            {
                comments = "Delete Protection by " + ownerEmail;
            }
            LabelingOptions invokeLabelingOptions = new LabelingOptions()
            {
                AssignmentMethod = AssignmentMethod.Privileged, //because we are removing a high priority label
                JustificationMessage = comments,
                IsDowngradeJustified = true,
            };

            var protectionSettings = new ProtectionSettings
            {
                PFileExtensionBehavior = PFileExtensionBehavior.Default,
            };
            if (ownerEmail != "")
            {
                protectionSettings.DelegatedUserEmail = ownerEmail;
            }

            try
            {
                if (handler.Protection != null)
                {
                    // 원본 파일 형식이 레이블 지정을 지원하지 않는 경우 보호를 제거하면 레이블이 손실됩니다.
                    // 기본 형식이 레이블 지정을 지원하는 경우 레이블 메타데이터가 유지됩니다.
                    if (handler.Protection.AccessCheck(Rights.Extract) || handler.Protection.AccessCheck(Rights.Owner))
                    {
                        handler.RemoveProtection();
                    }
                    //Use the GetTemporaryDecryptedStream() or GetTemporaryDecryptedFile() API to create a temp decrypted output to render in your application.
                }
                else
                {
                    result.errorNo = 209;
                    result.errorMsg = "파일에 암호화 정보가 없습니다.";
                    return result;
                }
            }
            catch (Exception ex)
            {
                result.errorNo = 208;
                result.errorMsg = "FileManager::RemoveProtection Failed." + ex.Message;
                SetError(59, "FileManager::RemoveProtection Failed.", ex.Message);
                return result;
            }

            bool isCommited = false;
            if (handler.IsModified())
            {
                isCommited = Task.Run(async () => await handler.CommitAsync(actualFileName)).Result;
            }

            if (isCommited)
            {
                //handler.NotifyCommitSuccessful(fileName);
                result.newFileSize = GetFileSize(actualFileName);
                result.newFileLabelGuid = string.Empty;
                result.newFileName = actualFileName;
                result.newFileOwner = ownerEmail;
                result.newFileTemplateGuid = string.Empty;
            }
            else
            {
                result.errorNo = 204;
                result.errorMsg = "AIP File CommitAsync Failed.";
                SetError(53, "FileManager::RemoveProtection Failed.", "RemoveProtection Failed by " + ownerEmail);
            }
            AipFileInfo info = GetFileInfo(actualFileName);
            if (info != null)
            {
                if (info.Label != null)
                {
                    result.newFileLabelGuid = info.Label.Id;
                }
                if (info.Protection != null)
                {
                    result.newFileOwner = info.Protection.Owner;
                    if (info.Protection.ProtectionDescriptor != null)
                    {
                        result.newFileTemplateGuid = info.Protection.ProtectionDescriptor.TemplateId;
                    }
                }
            }
            return result;
        }

        public async Task<Stream> GetDecryptedStreamAsync(Stream inputStream, string filename)
        {
            var handler = CreateFileHandler(inputStream, filename);
            return await handler.GetDecryptedTemporaryStreamAsync();
        }
        // Protect the input bytes. 
        public byte[] Protect(IProtectionHandler handler, byte[] data)
        {
            long buffersize = handler.GetProtectedContentLength(data.Length, true);
            byte[] outputBuffer = new byte[buffersize];

            handler.EncryptBuffer(0, data, outputBuffer, true);
            return outputBuffer;
        }

        public byte[] Unprotect(IProtectionHandler handler, byte[] data)
        {
            long buffersize = data.Length;
            byte[] clearBuffer = new byte[buffersize];

            var bytesDecrypted = handler.DecryptBuffer(0, data, clearBuffer, true);

            byte[] outputBuffer = new byte[bytesDecrypted];
            for (int i = 0; i < bytesDecrypted; i++)
            {
                outputBuffer[i] = clearBuffer[i];
            }

            return outputBuffer;
        }
    }

}

#if false
        public bool SetLabel(FileOptions options)
        {

            // LabelingOptions allows us to set the metadata associated with the labeling operations.
            // Review the API Spec at https://aka.ms/mipsdkdocs for details
            LabelingOptions labelingOptions = new LabelingOptions()
            {
                AssignmentMethod = options.AssignmentMethod
            };

            var handler = CreateFileHandler(options);

            // Use the SetLabel method on the handler, providing label ID and LabelingOptions
            // The handler already references a file, so those details aren't needed.

            try
            {
                handler.SetLabel(engine.GetLabelById(options.LabelId), labelingOptions, new ProtectionSettings());
            }

            catch (Microsoft.InformationProtection.Exceptions.JustificationRequiredException)
            {
                Console.Write("Please provide justification: ");
                string justification = Console.ReadLine();

                labelingOptions.IsDowngradeJustified = true;
                labelingOptions.JustificationMessage = justification;

                handler.SetLabel(engine.GetLabelById(options.LabelId), labelingOptions, new ProtectionSettings());
            }

            catch (Microsoft.InformationProtection.Exceptions.AdhocProtectionRequiredException)
            {
                List<string> users = new List<string>()
                {
                    "user1@contoso.com",
                    "user2@contoso.com"                    
                };

                List<string> roles = new List<string>()
                {
                    Microsoft.InformationProtection.Protection.Roles.Viewer
                };

                List<UserRoles> userroles = new List<UserRoles>()
                {
                    new UserRoles(users, roles)
                };

                ProtectionDescriptor protectionDescriptor = new ProtectionDescriptor(userroles);
                
                handler.SetProtection(protectionDescriptor, new ProtectionSettings());
                handler.SetLabel(engine.GetLabelById(options.LabelId), labelingOptions, new ProtectionSettings());
            }


            // The change isn't committed to the file referenced by the handler until CommitAsync() is called.
            // Pass the desired output file name in to the CommitAsync() function.
            bool result = false;
            
            // Only call commit if the handler has been modified.
            if(handler.IsModified())
            {
                result = Task.Run(async () => await handler.CommitAsync(options.OutputName)).Result;
            }

            // If the commit was successful and GenerateChangeAuditEvents is true, call NotifyCommitSuccessful()
            if (result && options.GenerateChangeAuditEvent)
            {
                // Submits and audit event about the labeling action to Azure Information Protection Analytics 
                handler.NotifyCommitSuccessful(options.FileName);
            }

            return result;
        }
#endif