/// <summary>
        /// SendFreehandLine sends a free hand line annotation to the handler.
        /// </summary>
        /// <param name="handler">The handler.</param>
        /// <param name="properties">The properties.</param>
        /// <returns>true if the operation succeeded otherwise returns false.</returns>
        private static bool SendFreehandLine(IWangAnnotationHandler handler, WangAnnotationProperties properties)
        {
            /*
             * Freehand Line
             * Definition: A series of lines such that the starting point of line n+1 is the same as the ending point of line n.
             * Attributes: rgbColor1, bHighlighting, uLineSize
             * Named Blocks and Associated Structures:
             * - OiAnoDat       AN_POINTS
             * - OiFilNam       Not used
             * - OiDIB          Not used
             * - OiGroup        STR
             * - OiIndex        STR
             * - OiAnText       Not used
             */

            if (properties.HasPoints)
            {
                SendFreehandLine(handler, properties.OiGroup, properties.OiIndex, properties.MarkAttributes.Bounds,
                                 properties.Points,
                                 properties.MarkAttributes.Color1, properties.MarkAttributes.Highlighting,
                                 properties.MarkAttributes.LineSize);
                return(true);
            }
            return(false);
        }
        /// <summary>
        /// ReadAnoDatBlock reads an "OiAnoDat" block.
        /// </summary>
        /// <param name="properties">The properties to be updated with the data.</param>
        /// <param name="stream">The stream to read the data in.</param>
        /// <param name="dataSize">The size of the data</param>
        private static bool ReadAnoDatBlock(WangAnnotationProperties properties, IWangStream stream, int dataSize)
        {
#if DEBUG
            Debug.Assert(stream.AvailableBytes() >= dataSize);
#endif // DEBUG
            if (properties.HasMarkAttributes)
            {
                switch (properties.MarkAttributes.Type)
                {
                case WangMarkType.StraightLine:
                case WangMarkType.FreehandLine:
                case WangMarkType.HollowPolygon:
                case WangMarkType.FilledPolygon:
                    int [] points = WangAnnotationStructureReader.ReadPoints(stream, dataSize);
                    properties.SetPoints(points);
                    return(true);

                case WangMarkType.ImageEmbedded:
                    WangRotation rotation = WangAnnotationStructureReader.ReadRotation(stream, dataSize);
                    properties.SetRotation(rotation);
                    return(true);

                default:
                    // TODO - David Ometto - 2016-11-22 - Add support for all types
                    break;
                }
            }
            return(false);
        }
        /// <summary>
        /// SendFilledPolygon sends a "Filled polygon" annotation to the handler.
        /// </summary>
        /// <param name="handler">The handler.</param>
        /// <param name="properties">The properties.</param>
        /// <returns>true if the operation succeeded otherwise returns false.</returns>
        private static bool SendFilledPolygon(IWangAnnotationHandler handler, WangAnnotationProperties properties)
        {
            /*
             * Filled Polygon
             * Please note this type was not mentionned within the documentation. The implementation
             * of this type is kind of reverse engineering. It's a mix between rectangles and free hand lines.
             *
             * Definition: A polygon with a filled center.
             * Attributes: rgbColor1, bHighlighting
             * Named Blocks and Associated Structures
             * - OiAnoDat       AN_POINTS
             * - OiFilNam       Not used
             * - OiDIB          Not used
             * - OiGroup        STR
             * - OiIndex        STR
             * - OiAnText       Not used
             */

            if (properties.HasPoints)
            {
                SendFilledPolygon(handler, properties.OiGroup, properties.OiIndex, properties.MarkAttributes.Bounds,
                                  properties.Points,
                                  properties.MarkAttributes.Color1, properties.MarkAttributes.Highlighting);
                return(true);
            }
            return(false);
        }
 /// <summary>
 /// SendTextFromFile sends a text from file annotation to the handler.
 /// </summary>
 /// <param name="handler">The handler.</param>
 /// <param name="properties">The properties.</param>
 /// <returns>true if the operation succeeded otherwise returns false.</returns>
 private static bool SendTextFromFile(IWangAnnotationHandler handler, WangAnnotationProperties properties)
 {
     /*
      * Text From File
      * Definition: Text supplied from a file. The file format is Text Only, which is only ASCII with carriage returns, line feeds, and tabs.
      * Attributes: rgbColor1, lfFont
      * Named Blocks and Associated Structures:
      * - OiAnoDat       Not used
      * - OiFilNam       Not used
      * - OiDIB          Not used
      * - OiGroup        STR
      * - OiIndex        STR
      * - OiAnText       OIAN_TEXTPRIVDATA
      */
     if (properties.HasDisplayText)
     {
         // TODO - David Ometto - 2016-11-24 - We miss the time_t read for the moment
         SendTextFromFile(handler, properties.OiGroup, properties.OiIndex, properties.MarkAttributes.Bounds,
                          properties.DisplayText.Orientation, properties.DisplayText.CreationScale,
                          properties.DisplayText.Text,
                          properties.MarkAttributes.Color1, properties.MarkAttributes.LogFont);
         return(true);
     }
     return(false);
 }
 /// <summary>
 /// SendOcrRegion sends an ocr region annotation to the handler.
 /// </summary>
 /// <param name="handler">The handler.</param>
 /// <param name="properties">The properties.</param>
 /// <returns>true if the operation succeeded otherwise returns false.</returns>
 private static bool SendOcrRegion(IWangAnnotationHandler handler, WangAnnotationProperties properties)
 {
     /*
      * OCR region
      * Definition: A rectangular region in which to perform OCR.
      * Attributes: rgbColor1, lfFont
      * Named Blocks and Associated Structures:
      * - OiAnoDat       Not used
      * - OiFilNam       Not used
      * - OiDIB          Not used
      * - OiGroup        STR
      * - OiIndex        STR
      * - OiAnText       OIAN_TEXTPRIVDATA (This will contain a sequential number string).
      */
     if (properties.HasDisplayText)
     {
         // TODO - David Ometto - 2016-11-24 - We miss the time_t read for the moment
         SendTextFromFile(handler, properties.OiGroup, properties.OiIndex, properties.MarkAttributes.Bounds,
                          properties.DisplayText.Orientation, properties.DisplayText.CreationScale,
                          properties.DisplayText.Text,
                          properties.MarkAttributes.Color1, properties.MarkAttributes.LogFont);
         return(true);
     }
     return(false);
 }
 /// <summary>
 /// SendTextStamp sends a text stamp annotation to the handler.
 /// </summary>
 /// <param name="handler">The handler.</param>
 /// <param name="properties">The properties.</param>
 /// <returns>true if the operation succeeded otherwise returns false.</returns>
 private static bool SendTextStamp(IWangAnnotationHandler handler, WangAnnotationProperties properties)
 {
     /*
      * Text Stamp
      * Definition: Text that contains a pre-defined string which may include, for example, the date and/or time when the mark was applied.
      * Attributes: rgbColor1, lfFont
      * Named Blocks and Associated Structures:
      * - OiAnoDat       Not used
      * - OiFilNam       Not used
      * - OiDIB          Not used
      * - OiGroup        STR
      * - OiIndex        STR
      * - OiAnText       OIAN_TEXTPRIVDATA
      *
      */
     if (properties.HasDisplayText)
     {
         // TODO - David Ometto - 2016-11-24 - We miss the time_t read for the moment
         SendTextStamp(handler, properties.OiGroup, properties.OiIndex, properties.MarkAttributes.Bounds,
                       properties.DisplayText.Orientation, properties.DisplayText.CreationScale,
                       properties.DisplayText.Text,
                       properties.MarkAttributes.Color1, properties.MarkAttributes.LogFont);
         return(true);
     }
     return(false);
 }
 /// <summary>
 /// SendAttachANote sends an "attach a note" annotation to the handler.
 /// </summary>
 /// <param name="handler">The handler.</param>
 /// <param name="properties">The properties.</param>
 /// <returns>true if the operation succeeded otherwise returns false.</returns>
 private static bool SendAttachANote(IWangAnnotationHandler handler, WangAnnotationProperties properties)
 {
     /*
      * Attach-a-Note
      * Definition: A colored rectangle that contains text.
      * Attributes: rgbColor1, rgbColor2, lfFont
      * Named Blocks and Associated Structures:
      * - OiAnoDat       Not used
      * - OiFilNam       Not used
      * - OiDIB          Not used
      * - OiGroup        STR
      * - OiIndex        STR
      * - OiAnText       OIAN_TEXTPRIVDATA
      */
     if (properties.HasDisplayText)
     {
         SendAttachANote(handler, properties.OiGroup, properties.OiIndex, properties.MarkAttributes.Bounds,
                         properties.DisplayText.Orientation, properties.DisplayText.CreationScale,
                         properties.DisplayText.Text,
                         properties.MarkAttributes.Color1, properties.MarkAttributes.Color2,
                         properties.MarkAttributes.LogFont);
         return(true);
     }
     return(false);
 }
 /// <summary>
 /// OnDone has to be called when the whole data have been read.
 /// </summary>
 /// <remarks>
 /// The previous mark is sent to the handler if necessary.
 /// </remarks>
 /// <param name="handler">The Wang annotation handler.</param>
 /// <param name="propertiesCurrent">The current properties.</param>
 private static bool OnDone(IWangAnnotationHandler handler, WangAnnotationProperties propertiesCurrent)
 {
     if (propertiesCurrent.HasMarkAttributes)
     {
         return(WangAnnotationTranslator.Send(handler, propertiesCurrent));
     }
     return(true);
 }
        /// <summary>
        /// Send sends the annotation with the current properties to the handler.
        /// </summary>
        /// <param name="handler">The handler.</param>
        /// <param name="properties">The properties.</param>
        /// <returns>true if the operation succeeded otherwise returns false.</returns>
        public static bool Send(IWangAnnotationHandler handler, WangAnnotationProperties properties)
        {
            // TODO - David Ometto - 2016-11-23 - Study the best way to deal with the Visible property for each and every mark type.
            // Preconditions
#if DEBUG
            Debug.Assert(properties.HasMarkAttributes);
#endif //DEBUG
            switch (properties.MarkAttributes.Type)
            {
            case WangMarkType.StraightLine:
                return(SendStraightLine(handler, properties));

            case WangMarkType.TypedText:
                return(SendTypedText(handler, properties));

            case WangMarkType.AttachANote:
                return(SendAttachANote(handler, properties));

            case WangMarkType.FilledRectangle:
                return(SendFilledRectangle(handler, properties));

            case WangMarkType.HollowRectangle:
                return(SendHollowRectangle(handler, properties));

            case WangMarkType.FilledPolygon:
                return(SendFilledPolygon(handler, properties));

            case WangMarkType.HollowPolygon:
                return(SendHollowPolygon(handler, properties));

            case WangMarkType.FreehandLine:
                return(SendFreehandLine(handler, properties));

            case WangMarkType.ImageEmbedded:
                return(SendImageEmbeded(handler, properties));

            case WangMarkType.TextStamp:
                return(SendTextStamp(handler, properties));

            case WangMarkType.TextFromFile:
                return(SendTextFromFile(handler, properties));

            case WangMarkType.OcrRegion:
                return(SendOcrRegion(handler, properties));

            case WangMarkType.ImageReference:
            case WangMarkType.Form:
            case WangMarkType.Invalid:
            default:
                // TODO - David Ometto - 2016-11-22 - We have to develop the support for this annotation type
                return(false);

                break;
            }
        }
        /// <summary>
        /// Read reads the Wang annotations within the provided tag data and calls the handler accordingly.
        /// </summary>
        /// <param name="handler">The Wang annotation handler.</param>
        /// <param name="tagData">The tag data.</param>
        /// <returns>true if the operation succeeded otherwise returns false.</returns>
        public static bool Read(IWangAnnotationHandler handler, byte[] tagData)
        {
            WangStream wangStream = new WangStream(tagData);

            if (!WangAnnotationsReader.ReadHeader(wangStream))
            {
                return(false);
            }
            WangAnnotationProperties propertiesDefault = new WangAnnotationProperties();
            WangAnnotationProperties propertiesCurrent = new WangAnnotationProperties();

            while (!wangStream.IsEnd())
            {
                WangDataType dataType;
                Int32        dataSize;
                bool         blockRead = false;
                if (ReadDataType(out dataType, out dataSize, wangStream) && wangStream.AvailableBytes() >= dataSize)
                {
                    switch (dataType)
                    {
                    case WangDataType.DefaultNamedBlock:
                        // Data in this block will be part of each newly-created mark.
                        blockRead = OnUpdateDefaultProperties(propertiesDefault, wangStream, dataSize);
                        break;

                    case WangDataType.Attributes:
                        // The attribute structure of the next annotation mark.
                        // This type also implies the end of the previous mark’s data, erefore the beginning of an annotation mark.
                        blockRead = OnNewMark(handler, propertiesCurrent, wangStream, dataSize, propertiesDefault);
                        break;

                    case WangDataType.NamedBlock:
                        // A named block that is part of the preceding annotation mark.
                        blockRead = OnUpdateProperties(propertiesCurrent, wangStream, dataSize);
                        break;
                    }
                }

                if (!blockRead)
                {
                    return(false);
                }
            }

            return(OnDone(handler, propertiesCurrent));
        }
        /// <summary>
        /// SendFilledRectangle sends a "Filled rectangle" annotation to the handler.
        /// </summary>
        /// <param name="handler">The handler.</param>
        /// <param name="properties">The properties.</param>
        /// <returns>true if the operation succeeded otherwise returns false.</returns>
        private static bool SendFilledRectangle(IWangAnnotationHandler handler, WangAnnotationProperties properties)
        {
            /*
             * Filled Rectangle
             * Definition: A rectangle with a filled center.
             * Attributes: rgbColor1, bHighlighting
             * Named Blocks and Associated Structures
             * - OiAnoDat       Not used
             * - OiFilNam       Not used
             * - OiDIB          Not used
             * - OiGroup        STR
             * - OiIndex        STR
             * - OiAnText       Not used
             */

            SendFilledRectangle(handler, properties.OiGroup, properties.OiIndex, properties.MarkAttributes.Bounds,
                                properties.MarkAttributes.Color1, properties.MarkAttributes.Highlighting);
            return(true);
        }
        /// <summary>
        /// OnNewMark has to be called when a new mark starts.
        /// </summary>
        /// <remarks>
        /// The previous mark is sent to the handler and the properties are initialized with default properties and the mark attributes.
        /// </remarks>
        /// <param name="handler">The Wang annotation handler.</param>
        /// <param name="propertiesCurrent">The current properties.</param>
        /// <param name="stream">The stream to read the data in.</param>
        /// <param name="dataSize">The size of the block.</param>
        /// <param name="propertiesDefault">The default properties.</param>
        /// <returns>true if the operation succeeded otherwise returns false.</returns>
        private static bool OnNewMark(IWangAnnotationHandler handler, WangAnnotationProperties propertiesCurrent,
                                      IWangStream stream, int dataSize, WangAnnotationProperties propertiesDefault)
        {
            if (propertiesCurrent.HasMarkAttributes && !WangAnnotationTranslator.Send(handler, propertiesCurrent))
            {
                return(false);
            }

            propertiesCurrent.CopyFrom(propertiesDefault);

            WangMarkAttributes markAttributes = WangAnnotationStructureReader.ReadMarkAttributes(stream, dataSize);

            if (markAttributes == null)
            {
                return(false);
            }
            propertiesCurrent.SetMarkAttributes(markAttributes);
            return(true);
        }
        /// <summary>
        /// SendImageEmbeded sends an "Image Embedded" annotation to the handler.
        /// </summary>
        /// <param name="handler">The handler.</param>
        /// <param name="properties">The properties.</param>
        /// <returns>true if the operation succeeded otherwise returns false.</returns>
        private static bool SendImageEmbeded(IWangAnnotationHandler handler, WangAnnotationProperties properties)
        {
            /*
             * Image Embedded
             * Definition: An embedded image.
             * Attributes: bTransparent
             * Named Blocks and Associated Stuctures
             * - OiAnoDat       AN_NEW_ROTATE_STRUCT
             * - OiFilNam       AN_NAME_STRUCT
             * - OiDIB          AN_IMAGE_STRUCT
             * - OiGroup        STR
             * - OiIndex        STR
             * - OiAnText       Not used
             */

            if (properties.HasDib && properties.HasFilename && properties.HasDib)
            {
                SendImageEmbeded(handler, properties.OiGroup, properties.OiIndex, properties.MarkAttributes.Bounds,
                                 properties.MarkAttributes.Transparent, properties.Rotation, properties.Filename, properties.DibInfo);
                return(true);
            }
            return(false);
        }
        /// <summary>
        /// SendStraightLine sends a straight line annotation to the handler.
        /// </summary>
        /// <param name="handler">The handler.</param>
        /// <param name="properties">The properties.</param>
        /// <returns>true if the operation succeeded otherwise returns false.</returns>
        private static bool SendStraightLine(IWangAnnotationHandler handler, WangAnnotationProperties properties)
        {
            /*
             * Straight Line
             * Definition: A line with a defined starting and ending point.
             * Attributes: rgbColor1, bHighlighting, uLineSize
             * Named Blocks and Associated Structures:
             * - OiAnoDat       AN_POINTS
             * - OiFilNam       Not used
             * - OiDIB          Not used
             * - OiGroup        STR
             * - OiIndex        STR
             * - OiAnText       Not used
             */

            if (properties.HasPoints && WangAnnotationTranslation.PointsLength(properties.Points) == 2)
            {
                SendStraightLine(handler, properties.OiGroup, properties.OiIndex, properties.MarkAttributes.Bounds, properties.Points, properties.MarkAttributes.Color1, properties.MarkAttributes.Highlighting, properties.MarkAttributes.LineSize);
                return(true);
            }

            return(false);
        }
 /// <summary>
 /// SendTypedText sends a typed text annotation to the handler.
 /// </summary>
 /// <param name="handler">The handler.</param>
 /// <param name="properties">The properties.</param>
 /// <returns>true if the operation succeeded otherwise returns false.</returns>
 private static bool SendTypedText(IWangAnnotationHandler handler, WangAnnotationProperties properties)
 {
     /*
      * Typed Text
      * Definition: A series of characters entered from the keyboard.
      * Attributes: rgbColor1, lfFont
      * Named Blocks and Associated Structures:
      * - OiAnoDat       Not used
      * - OiFilNam       Not used
      * - OiDIB          Not used
      * - OiGroup        STR
      * - OiIndex        STR
      * - OiAnText       OIAN_TEXTPRIVDATA
      */
     if (properties.HasDisplayText)
     {
         if (properties.HasHyperlink)
         {
             SendLink(handler, properties.OiGroup, properties.OiIndex, properties.MarkAttributes.Bounds,
                      properties.DisplayText.Orientation, properties.DisplayText.CreationScale,
                      properties.DisplayText.Text,
                      properties.Hyperlink.InternalLink, properties.Hyperlink.Link,
                      properties.Hyperlink.WorkingDirectory, properties.Hyperlink.Location,
                      properties.MarkAttributes.Color1, properties.MarkAttributes.LogFont);
         }
         else
         {
             SendTypedText(handler, properties.OiGroup, properties.OiIndex, properties.MarkAttributes.Bounds,
                           properties.DisplayText.Orientation, properties.DisplayText.CreationScale,
                           properties.DisplayText.Text,
                           properties.MarkAttributes.Color1, properties.MarkAttributes.LogFont);
         }
         return(true);
     }
     return(false);
 }
        /// <summary>
        /// ReadBlock reads the block and updates the properties accordingly.
        /// </summary>
        /// <param name="properties">The properties to update.</param>
        /// <param name="stream">The stream to read the data in.</param>
        /// <param name="dataSize">The size of the block.</param>
        /// <returns>true if the operation succeeded otherwise returns false.</returns>
        public static bool ReadBlock(WangAnnotationProperties properties, IWangStream stream, int dataSize)
        {
#if DEBUG
            Debug.Assert(stream.AvailableBytes() >= dataSize);
#endif // DEBUG
            WangNamedBlockHeader header = WangAnnotationStructureReader.ReadNamedBlockHeader(stream, dataSize);
            if (header == null || header.Size > stream.AvailableBytes())
            {
                return(false);
            }

            /*
             * Named Block          Associated Structure            Usage
             * OiAnoDat             For lines: AN_POINTS            List coordinates for lines and freehand marks.
             *                      For images:AN_NEW_ROTATE_STRUCT Hold scaling and resolution information for image marks.
             * OiFilNam             AN_NAME_STRUCT                  Hold file name for image marks.
             * OiDIB                AN_IMAGE_STRUCT                 Store DIB data.
             * OiGroup (required)   STR                             Create sets of marks (required).
             * OiIndex (required)   STR                             Assign unique number, originating at 0, for each mark.
             *                                                      To facilitate easy application control, the next available number is generated by incrementing by 1 the number just assigned and storing it in the default OiIndex mark.
             * OiAnText             OIAN_TEXTPRIVDATA               Display text annotation marks.
             * OiHypLnk             HYPERLINK_NB                    Turn mark into a hyperlink.
             */
            if (header.Name == "OiAnoDat")
            {
                // TODO - David Ometto - 2016-11-24 - Unit test this method
                return(ReadAnoDatBlock(properties, stream, header.Size));
            }
            else if (header.Name == "OiFilNam")
            {
                properties.SetFilename(WangAnnotationStructureReader.ReadCharString(stream, header.Size));
                return(true);
            }
            else if (header.Name == "OiDIB")
            {
                properties.SetDibInfo(WangAnnotationStructureReader.ReadDib(stream, header.Size));
                return(true);
            }
            else if (header.Name == "OiGroup")
            {
                properties.OiGroup = WangAnnotationStructureReader.ReadCharString(stream, header.Size);
                return(true);
            }
            else if (header.Name == "OiIndex")
            {
                properties.OiIndex = WangAnnotationStructureReader.ReadCharString(stream, header.Size);
                return(true);
            }
            else if (header.Name == "OiAnText")
            {
                WangDisplayText displayText = WangAnnotationStructureReader.ReadDisplayText(stream, header.Size);
                if (displayText == null)
                {
                    return(false);
                }
                properties.SetDisplayText(displayText);
                return(true);
            }
            else if (header.Name == "OiHypLnk")
            {
                WangHyperlink hyperlink = WangAnnotationStructureReader.ReadHyperlink(stream, header.Size);
                if (hyperlink == null)
                {
                    return(false);
                }
                properties.SetHyperlink(hyperlink);
                return(true);
            }
            else
            {
                // We just skip unknown data
                stream.SkipBytes(header.Size);
                return(true);
            }
        }
 /// <summary>
 /// OnUpdateProperties updates the properties with the upcoming block.
 /// </summary>
 /// <param name="properties">The properties to update.</param>
 /// <param name="stream">The stream to read the data in.</param>
 /// <param name="dataSize">The size of the block.</param>
 /// <returns>true if the operation succeeded otherwise returns false.</returns>
 private static bool OnUpdateProperties(WangAnnotationProperties properties, IWangStream stream, int dataSize)
 {
     return(ReadBlock(properties, stream, dataSize));
 }