Save and load UITextView with Image to file using RTFD.

protocol RichTextManagable {}

extension RichTextManagable {

    func insertAttachment(image: UIImage, using textView: UITextView) {
        let font = textView.font
        let attachment = NSTextAttachment()
        var ratioSize = AVMakeRect(aspectRatio: image.size, insideRect: textView.bounds).size
        ratioSize.width -= 10
        attachment.image = image.size(ratioSize)

        let mAttr = NSMutableAttributedString(string: "\n")
        mAttr.append(NSAttributedString(attachment: attachment))
        mAttr.append(NSAttributedString(string: "\n"))

        textView.textStorage.insert(mAttr, at: textView.selectedRange.location)
        textView.selectedRange = NSMakeRange(textView.selectedRange.location + 3, 0)
        textView.font = font

        /*
         화면이 빠르게 전환되서 키보드 높이를 인식하지 못할 경우,
         inset 맞지 않을 수 있는데 그럴때 responder를 재설정하면 도움이 될 수 있음.
        */
        // textView.resignFirstResponder()
        // textView.becomeFirstResponder()
    }

    func save(file url: URL, using textView: UITextView) throws {
        let fileWrapper = try textView.attributedText.fileWrapper(from: NSMakeRange(0, textView.attributedText.length), documentAttributes: [.documentType : NSAttributedString.DocumentType.rtfd])
        try? FileManager().removeItem(at: url)
        try fileWrapper.write(to: url, options: .atomic, originalContentsURL: nil)
    }

    func load(file url: URL, using textView: UITextView) throws {
        let mAttr = try NSMutableAttributedString(url: url, options: [.documentType : NSAttributedString.DocumentType.rtfd], documentAttributes: nil)
        mAttr.enumerateAttribute(.attachment, in: NSMakeRange(0, mAttr.length), options: [], using: { (data, _, _) in
            guard let attachment = data as? NSTextAttachment else {return}
            guard let content = attachment.fileWrapper?.regularFileContents, let image = UIImage(data: content) else {return}
            var ratioSize = AVMakeRect(aspectRatio: image.size, insideRect: textView.bounds).size
            ratioSize.width -= 10
            attachment.image = image.size(ratioSize)
        })
        textView.attributedText = mAttr
    }

    func showDetail(_ context: UIViewController, using attachment: NSTextAttachment) {
        // 참고: https://jangdorios.github.io/swift/2018/08/23/01.html
        guard let content = attachment.fileWrapper?.regularFileContents, let image = UIImage(data: content) else {return}
        let imageDetailVC = ImageDetailVC.instance
        imageDetailVC.image = image
        context.navigationController?.pushViewController(imageDetailVC, animated: true)
    }

}