using EnvelopeGenerator.Application.Common.Dto.Receiver; using EnvelopeGenerator.Domain.Constants; using EnvelopeGenerator.Domain.Interfaces; namespace EnvelopeGenerator.Application.Common.Dto; // TODO: Add the “Reason” property and integrate with UI and the digital signature process. /// /// Data Transfer Object representing a positioned element assigned to a document receiver. /// public class DocReceiverElementDto : IDocReceiverElement, ISignatureInkPayload { /// /// Gets or sets the unique identifier of the element. /// public int Id { get; set; } /// /// Gets or sets the identifier of the associated document. /// public int DocumentId { get; set; } /// /// /// public virtual DocumentDto? Document { get; set; } /// /// Gets or sets the identifier of the receiver. /// public int ReceiverId { get; set; } /// /// /// public virtual ReceiverDto? Receiver { get; set; } /// /// Gets or sets the type of the element. /// public int ElementType { get; set; } /// /// Gets or sets the X coordinate of the element. /// public double X { get; set; } /// /// Gets or sets the Y coordinate of the element. /// public double Y { get; set; } /// /// Gets or sets the width of the element. /// public double Width { get; set; } /// /// Gets or sets the height of the element. /// public double Height { get; set; } /// /// Gets or sets the page number where the element appears. /// public int Page { get; set; } /// /// Gets or sets a value indicating whether the element is required. /// public bool Required { get; set; } /// /// Gets or sets the tooltip text for the element. /// public string? Tooltip { get; set; } /// /// Gets or sets a value indicating whether the element is read-only. /// public bool ReadOnly { get; set; } /// /// Gets or sets the annotation index for ordering or reference. /// public int AnnotationIndex { get; set; } /// /// Gets or sets the timestamp when the element was added. /// public DateTime AddedWhen { get; set; } /// /// Gets or sets the timestamp when the element was last changed, if applicable. /// public DateTime? ChangedWhen { get; set; } /// /// Gets or sets the top position of the element (in layout terms). /// public double Top => Y; /// /// Gets or sets the left position of the element (in layout terms). /// public double Left => X; /// /// /// public IEnumerable? Annotations { get; set; } /// /// /// public SenderAppType SenderAppType { get; set; } = SenderAppType.LegacyFormApp; /// /// /// public string? FullName { get; set; } /// /// /// public string? Position { get; set; } /// /// /// public string? Place { get; set; } /// /// /// public byte[]? Ink { get; set; } /// /// Returns the stored signature bytes as an image payload with detected MIME type. /// /// Thrown when signature image bytes do not exist. public (byte[] Bytes, string ContentType, string FileExtension) ToImage() { if (Ink is not { Length: > 0 }) throw new InvalidOperationException("Signature image (Ink) does not exist."); if (HasPrefix(Ink, 0x89, 0x50, 0x4E, 0x47)) return (Ink, "image/png", ".png"); if (HasPrefix(Ink, 0xFF, 0xD8, 0xFF)) return (Ink, "image/jpeg", ".jpg"); if (HasPrefix(Ink, 0x52, 0x49, 0x46, 0x46) && Ink.Length >= 12 && Ink[8] == 0x57 && Ink[9] == 0x45 && Ink[10] == 0x42 && Ink[11] == 0x50) return (Ink, "image/webp", ".webp"); return (Ink, "application/octet-stream", ".bin"); } private static bool HasPrefix(byte[] data, params byte[] prefix) { if (data.Length < prefix.Length) return false; for (var i = 0; i < prefix.Length; i++) { if (data[i] != prefix[i]) return false; } return true; } }