/*
 *
 *  Copyright (C) 1996-2002, OFFIS
 *
 *  This software and supporting documentation were developed by
 *
 *    Kuratorium OFFIS e.V.
 *    Healthcare Information and Communication Systems
 *    Escherweg 2
 *    D-26121 Oldenburg, Germany
 *
 *  THIS SOFTWARE IS MADE AVAILABLE,  AS IS,  AND OFFIS MAKES NO  WARRANTY
 *  REGARDING  THE  SOFTWARE,  ITS  PERFORMANCE,  ITS  MERCHANTABILITY  OR
 *  FITNESS FOR ANY PARTICULAR USE, FREEDOM FROM ANY COMPUTER DISEASES  OR
 *  ITS CONFORMITY TO ANY SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND
 *  PERFORMANCE OF THE SOFTWARE IS WITH THE USER.
 *
 *  Module:  dcmimgle
 *
 *  Author:  Joerg Riesmeier
 *
 *  Purpose: DicomOverlayPlane (Header) - Multiframe Overlays UNTESTED !
 *
 */


#ifndef __DIOVPLN_H
#define __DIOVPLN_H

#include "osconfig.h"
#include "dctypes.h"
#include "ofstring.h"
#include "diutils.h"
#include "ofstream.h"

#define INCLUDE_CSTDDEF
#include "ofstdinc.h"


/*------------------------*
 *  forward declarations  *
 *------------------------*/

class DcmOverlayData;
class DcmLongString;

class DiDocument;


/*---------------------*
 *  class declaration  *
 *---------------------*/

/** Class to handle a single overlay plane
 */
class DiOverlayPlane
{
 public:

    /** constructor
     *
     ** @param  docu   pointer to dataset (encapsulated)
     *  @param  group  group number of the overlay plane
     *  @param  alloc  value for bits allocated of the surrounding image
     */
    DiOverlayPlane(const DiDocument *docu,
                   const unsigned int group,
                   Uint16 alloc);

    /** constructor, additional
     *
     ** @param  group        group number of the overlay plane
     *  @param  left_pos     x-coordinate of the plane origin
     *  @param  top_pos      y-coordinate of the plane origin
     *  @param  columns      width of the overlay plane
     *  @param  rows         height of the overlay plane
     *  @param  data         element containing the plane data
     *  @param  label        element containing the plane label
     *  @param  description  element containing the plane description
     *  @param  mode         overlay plane mode
     */
    DiOverlayPlane(const unsigned int group,
                   const Sint16 left_pos,
                   const Sint16 top_pos,
                   const Uint16 columns,
                   const Uint16 rows,
                   const DcmOverlayData &data,
                   const DcmLongString &label,
                   const DcmLongString &description,
                   const EM_Overlay mode);

    /** constructor, copy
     *
     ** @param  plane    reference overlay plane to be copied
     *  @param  bit      position of the plane bit
     *  @param  data     pointer to buffer for plane data
     *  @param  temp     temporary buffer used to extract plane information
     *  @param  width    width of the array where the plane is stored
     *  @param  height   height of the array where the plane is stored
     *  @param  columns  width of the overlay plane
     *  @param  rows     height of the overlay plane
     */
    DiOverlayPlane(DiOverlayPlane *plane,
                   const unsigned int bit,
                   Uint16 *data,
                   Uint16 *temp,
                   const Uint16 width,
                   const Uint16 height,
                   const Uint16 columns,
                   const Uint16 rows);

    /** destructor
     */
    ~DiOverlayPlane();

    /** get x-coordinate of overlay plane origin
     *
     ** @param  left_pos  offset to be subtracted from the actual value (optional)
     *
     ** @return x-coordinate of overlay plane origin
     */
    inline Sint16 getLeft(const Sint32 left_pos = 0) const
    {
        return (Sint16)((Sint32)Left - left_pos);
    }

    /** get y-coordinate of overlay plane origin
     *
     ** @param  top_pos  offset to be subtracted from the actual value (optional)
     *
     ** @return y-coordinate of overlay plane origin
     */
    inline Sint16 getTop(const Sint32 top_pos = 0) const
    {
        return (Sint16)((Sint32)Top - top_pos);
    }

    /** get width of overlay plane
     *
     ** @return width of overlay plane
     */
    inline Uint16 getWidth() const
    {
        return Width;
    }

    /** get height of overlay plane
     *
     ** @return height of overlay plane
     */
    inline Uint16 getHeight() const
    {
        return Height;
    }

    /** get right border of overlay plane origin
     *
     ** @param  left_pos  offset to be subtracted from the actual value (optional).
     *
     ** @return right border of overlay plane origin. Negative values are set to 0.
     */
    inline Uint16 getRight(const Sint32 left_pos = 0) const
    {
        return ((Sint32)Left + (Sint32)Width - left_pos > 0) ? (Uint16)((Sint32)Left + (Sint32)Width - left_pos) : 0;
    }

    /** get bottom border of overlay plane origin
     *
     ** @param  top_pos  offset to be subtracted from the actual value (optional).
     *
     ** @return bottom border of overlay plane origin. Negative values are set to 0.
     */
    inline Uint16 getBottom(const Sint32 top_pos = 0) const
    {
        return ((Sint32)Top + (Sint32)Height - top_pos > 0) ? (Uint16)((Sint32)Top + (Sint32)Height - top_pos) : 0;
    }

    /** check whether overlay plane is valid
     *
     ** @return true if plane is valid, false otherwise
     */
    inline int isValid() const
    {
        return Valid;
    }

    /** check whether overlay plane is visible
     *
     ** @return true if plane is visible, false otherwise
     */
    inline int isVisible() const
    {
        return Visible;
    }

    /** make overlay plane visible
     */
    inline void show()
    {
        Visible = 1;
    }

    /** make overlay plane invisible
     */
    inline void hide()
    {
        Visible = 0;
    }

    /** move overlay plane to a new place
     *
     ** @param  left_pos  x-coordinate of the new plane origin (maybe negative)
     *  @param  top_pos   y-coordinate of the new plane origin (maybe negative)
     */
    inline void place(const signed int left_pos,
                      const signed int top_pos)
    {
        Left = left_pos; Top = top_pos;
    }

    /** set scaling factor in x- and y-direction
     *
     ** @param  xfactor  scaling factor in x-direction
     *  @param  yfactor  scaling factor in y-direction
     */
    void setScaling(const double xfactor,
                    const double yfactor);

    /** set flipping
     *
     ** @param  horz     flip horizontally if true
     *  @param  vert     flip vertically if true
     *  @param  columns  width of surrounding image (incl. origin offset)
     *  @param  rows     height of surrounding image (incl. origin offset)
     */
    void setFlipping(const int horz,
                     const int vert,
                     const signed long columns,
                     const signed long rows);

    /** set rotation
     *
     ** @param  degree    angle by which the plane should be rotated
     *  @param  left_pos  x-coordinate of the origin for all overlay planes
     *  @param  top_pos   y-coordinate of the origin for all overlay planes
     *  @param  columns   width of surrounding image (already rotated)
     *  @param  rows      height of surrounding image (already rotated)
     */
    void setRotation(const int degree,
                     const signed long left_pos,
                     const signed long top_pos,
                     const Uint16 columns,
                     const Uint16 rows);

    /** make overlay plane visible and set parameters
     *
     ** @param  fore    foreground color of the plane (in percent: 0.0-1.0)
     *  @param  thresh  threshold value for 'threshold replace' (0.0-1.0)
     *  @param  mode    new overlay plane mode (EMO_Default for stored mode)
     */
    void show(const double fore,
              const double thresh,
              const EM_Overlay mode);

    /** make overlay plane visible and set p-value.
     *  Only applicable for bitmap shutters.
     *
     ** @param  pvalue  p-value to be used for the overlay plane (0..65535)
     *
     ** @return status, true if successful, false otherwise
     */
    int show(const Uint16 pvalue);

    /** get number of frames
     *
     ** @return number of frames
     */
    inline unsigned long getNumberOfFrames() const
    {
        return NumberOfFrames;
    }

    /** get foreground color of the plane
     *
     ** @return foreground color (in percent: 0.0-1.0)
     */
    inline double getForeground() const
    {
        return Foreground;
    }

    /** get threshold value of the plane
     *
     ** @return threshold value (in percent: 0.0-1.0)
     */
    inline double getThreshold() const
    {
        return Threshold;
    }

    /** get p-value of the plane.
     *  Only valid for bitmap shutters.
     *
     ** @return p-value (0..65535)
     */
    inline Uint16 getPValue() const
    {
        return PValue;
    }

    /** get overlay plane mode
     *
     ** @return overlay plane mode
     */
    inline EM_Overlay getMode() const
    {
        return Mode;
    }

    /** check whether overlay plane is embedded in the pixel data
     *
     ** @return true if plane is embedded, false otherwise
     */
    inline int isEmbedded() const
    {
        return EmbeddedData;
    }

    /** get label of overlay plane
     *
     ** @return label if successful, NULL otherwise
     */
    const char *getLabel() const
    {
        return (Label.empty()) ? (const char *)NULL : Label.c_str();
    }

    /** get description of overlay plane
     *
     ** @return description if successful, NULL otherwise
     */
    const char *getDescription() const
    {
        return (Description.empty()) ? (const char *)NULL : Description.c_str();
    }

    /** get group number of overlay plane
     *
     ** @return group number (0x6000-0x60ff)
     */
    Uint16 getGroupNumber() const
    {
        return GroupNumber;
    }

    /** get overlay plane data as an array of 1/8/16 bit values.
     *  Overlay plane is clipped to the area specified by the four min/max coordinates.
     *  Memory isn't handled internally and must therefore be deleted from calling program.
     *
     ** @param  frame  number of frame
     *  @param  xmin   x-coordinate of the top left hand corner
     *  @param  ymin   y-coordinate of the top left hand corner
     *  @param  xmax   x-coordinate of the bottom right hand corner
     *  @param  ymax   y-coordinate of the bottom right hand corner
     *  @param  bits   number of bits (stored) in the resulting array
     *  @param  fore   foreground color used for the plane (0x00-0xff)
     *  @param  back   transparent background color (0x00-0xff)
     *
     ** @return pointer to pixel data if successful, NULL otherwise
     */
    void *getData(const unsigned long frame,
                  const Uint16 xmin,
                  const Uint16 ymin,
                  const Uint16 xmax,
                  const Uint16 ymax,
                  const int bits,
                  const Uint16 fore,
                  const Uint16 back);

    /** create overlay plane data in (6xxx,3000) format.
     *  (1 bit allocated and stored, foreground color is 1, background color is 0,
     *   data is 16 bit padded - even length)
     *  Memory isn't handled internally and must therefore be deleted from calling program.
     *
     ** @param  buffer  stores pointer to overlay data (memory is allocated internally)
     *  @param  width   returns width of overlay plane (in pixels)
     *  @param  height  returns height of overlay plane (in pixels)
     *  @param  frame   returns number of frames (multiple overlay frames possible!)
     *
     ** @return number of bytes allocated for the 'buffer' if successful, 0 otherwise
     */
    unsigned long create6xxx3000Data(Uint8 *&buffer,
                                     unsigned int &width,
                                     unsigned int &height,
                                     unsigned long &frames);

    /** reset internal 'cursor' to the beginning of the specified frame
     *
     ** @param  frame  number of current frame
     *
     ** @return status, true if successful, false otherwise
     */
    inline int reset(const unsigned long frame);

    /** get value of the current overlay plane bit and move 'cursor' to the next position
     *
     ** @return true if plane bit is set, false otherwise
     */
    inline int getNextBit();

    /** set internal 'cursor' to a specific position
     *
     ** @param  x  new x-coordinate to start from
     *  @param  y  new y-coordinate to start from
     */
    inline void setStart(const Uint16 x,
                         const Uint16 y);


 protected:

    /// number of frames
    Uint32 NumberOfFrames;
    /// number of starting frame
    Uint16 ImageFrameOrigin;

    /// y-coordinate of overlay plane's origin
    Sint16 Top;
    /// x-coordinate of overlay plane's origin
    Sint16 Left;
    /// visible height
    Uint16 Height;
    /// visible width
    Uint16 Width;
    /// number of (stored) rows
    Uint16 Rows;
    /// number of (stored) columns
    Uint16 Columns;
    /// number of allocated bits per pixel
    Uint16 BitsAllocated;
    /// position of overlay plane bit
    Uint16 BitPosition;

    /// "color" of overlay plane (in percent: '0.0' = dark, '1.0' = bright)
    double Foreground;
    /// threshold value used for "threshold replace"
    double Threshold;
    /// P-value used for bitmap shutters
    Uint16 PValue;

    /// current overlay mode
    EM_Overlay Mode;
    /// default (stored) overlay mode
    EM_Overlay DefaultMode;

    /// label of overlay plane
    OFString Label;
    /// textual description of overlay plane
    OFString Description;

    /// group number of overlay plane
    Uint16 GroupNumber;

    /// validity status
    int Valid;
    /// visibility status
    int Visible;


 private:

    /// current bit position
    unsigned long BitPos;
    /// starting bit position of current frame
    unsigned long StartBitPos;

    /// x-coordinate of first pixel in surrounding memory buffer
    unsigned int StartLeft;
    /// y-coordinate of first pixel in surrounding memory buffer
    unsigned int StartTop;

    /// true, if overlay data in embedded in pixel data
    int EmbeddedData;

    /// pointer to current element of 'Data'
    const Uint16 *Ptr;
    /// pointer to starting element of current frame
    const Uint16 *StartPtr;
    /// pointer to overlay data (standalone) or pixel data (embedded)
    const Uint16 *Data;

 // --- declarations to avoid compiler warnings

    DiOverlayPlane(const DiOverlayPlane &);
    DiOverlayPlane &operator=(const DiOverlayPlane &);
};


/********************************************************************/


inline int DiOverlayPlane::reset(const unsigned long frame)
{
    int result = 0;
    if (Valid && (Data != NULL) && (frame >= ImageFrameOrigin) && (frame < ImageFrameOrigin + NumberOfFrames))
    {
        const unsigned long bits = ((unsigned long)StartLeft + (unsigned long)StartTop * (unsigned long)Columns +
            frame * (unsigned long)Rows * (unsigned long)Columns) * (unsigned long)BitsAllocated;
        StartBitPos = BitPos = (unsigned long)BitPosition + bits;
        StartPtr = Ptr = Data + (bits >> 4);
        result = (getRight() > 0) && (getBottom() > 0);
    }
    return result;
}


inline int DiOverlayPlane::getNextBit()
{
    int result;
    if (BitsAllocated == 16)                                    // optimization
        result = (int)(*(Ptr++) & (1 << BitPosition));
    else
    {
       Ptr = StartPtr + (BitPos >> 4);                          // div 16
       result = (int)(*Ptr & (1 << (BitPos & 0xf)));            // mod 16
       BitPos += BitsAllocated;                                 // next bit
    }
    return result;
}


inline void DiOverlayPlane::setStart(const Uint16 x,
                                     const Uint16 y)
{
    if (BitsAllocated == 16)
        Ptr = StartPtr + (unsigned long)(y - Top) * (unsigned long)Columns + (unsigned long)(x - Left);
    else
        BitPos = StartBitPos + ((unsigned long)(y - Top) * (unsigned long)Columns + (unsigned long)(x - Left)) * (unsigned long)BitsAllocated;
}


#endif
