//# PlotOptions.h: Customization classes for plotter objects.
//# Copyright (C) 2008
//# Associated Universities, Inc. Washington DC, USA.
//#
//# This library is free software; you can redistribute it and/or modify it
//# under the terms of the GNU Library General Public License as published by
//# the Free Software Foundation; either version 2 of the License, or (at your
//# option) any later version.
//#
//# This library is distributed in the hope that it will be useful, but WITHOUT
//# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
//# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
//# License for more details.
//#
//# You should have received a copy of the GNU Library General Public License
//# along with this library; if not, write to the Free Software Foundation,
//# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
//#
//# Correspondence concerning AIPS++ should be addressed as follows:
//#        Internet email: aips2-request@nrao.edu.
//#        Postal address: AIPS++ Project Office
//#                        National Radio Astronomy Observatory
//#                        520 Edgemont Road
//#                        Charlottesville, VA 22903-2475 USA
//#
//# $Id: $
#ifndef PLOTOPTIONS_H_
#define PLOTOPTIONS_H_

#include <utility>
#include <cctype>
#include <vector>

#include <casacore/casa/Utilities/CountedPtr.h>
#include <casacore/casa/Containers/Record.h>

namespace casa {


// Typedef for range, which is two doubles (min and max).
typedef std::pair<double, double> prange_t;

// Typedef for size, which is two doubles (width and height).
typedef std::pair<double, double> psize_t;



///////////
// ENUMS //
///////////

enum SortDirection {
	ASCENDING,
	DESCENDING
};


// Enum for the four plot axes.  If this enum is changed, PlotCanvas::allAxes()
// needs to be updated.
// Use this in contexts where one and only one side is specified.
// For combinations of sides, or none, use  PlotAxiBitset
enum PlotAxis {
    X_BOTTOM = 1, X_TOP = 2, Y_LEFT = 4, Y_RIGHT = 8
};


// Set of bit flags to indicate combinations of sides, 
// used (as of this writing) for indicating which axes have visible scales.
// The value of a PlotSideBitset is the bitwise OR of values of PlotSide.
typedef  unsigned int  PlotAxisBitset;

const PlotAxisBitset all_four_sides  = 0xF;
const PlotAxisBitset none_sides      = 0x0;



// Enum for possible axis scales.
enum PlotAxisScale {
    NORMAL,
    LOG10,        // logarithmic scale
    ANGLE,        // display scale values as formatted angles
    DATE_MJ_SEC,  // display scale values as dates (modified julian seconds)
    DATE_MJ_DAY   // display scale values as dates (modified julian days)
};

// Enum for angle formats
enum AngleFormat {
	DECIMAL,  // Decimal Number
	HMS,      // Hours Minutes Seconds
	DMS       // Degrees Arcminutes Arcseconds
};

// Enum for cursors.
enum PlotCursor {
    NORMAL_CURSOR,
    HAND_OPEN,
    HAND_CLOSED,
    CROSSHAIR,
    WAIT,
    TEXT
};

// The canvas is composed of multiple layers, where changing/adding items from
// one layer will not affect the others.  This is mainly used to separate items
// that are costly to draw (i.e. scatter plots with many points) from
// interaction-type items (i.e. annotations and selections).  The layers share
// axes and are otherwise transparent to the user.  If this enum is changed,
// PlotCanvas::allLayers() needs to be updated.
enum PlotCanvasLayer {
    MAIN       = 1, // "Main" or bottom layer.
    ANNOTATION = 2  // Annotations or top layer.
};


//////////////////////
// ABSTRACT CLASSES //
//////////////////////

// Abstract class for colors.  Any implementation of color should be able to
// provide a hexadecimal form of the color (i.e., "000000" for black) and, if
// applicable, a human-readable name (i.e. "black").  In many places throughout
// the plotter, color and Strings are interchangeable; however implementation
// classes should use PlotColors where possible for additional features such as
// alpha blending.
class PlotColor {
public:
    // Constructor.
    PlotColor();
    
    // Destructor.
    virtual ~PlotColor();
    
    
    // ABSTRACT METHODS //
    
    // Returns this color's value in a hexadecimal form, i.e. "000000".
    virtual casacore::String asHexadecimal() const = 0;
    
    // Returns this color's value as a human-readable name if applicable, or an
    // empty casacore::String if inapplicable.
    virtual casacore::String asName() const = 0;
    
    // If the given casacore::String is a hexadecimal value, sets the color to it.
    // Otherwise tries to set the color as a name.  If the given name is
    // invalid, the behavior is undefined but should probably default to a
    // sensible value.
    virtual void setAsHexadecimalOrName(const casacore::String& str) = 0;
    
    // Returns this color's alpha as a value between 0 (transparent) and 1
    // (opaque).
    virtual double alpha() const = 0;
    
    // Sets this color's alpha as a value between 0 (transparent) and 1
    // (opaque).
    virtual void setAlpha(double a) = 0;
    
    
    // CONVENIENCE METHODS //
    
    // Sets this color's value as a hexadecimal value.
    virtual void setAsHexadecimal(const casacore::String& hex);
    
    // Set's this color's value to the given named color.
    virtual void setAsName(const casacore::String& name);
    
    
    // RECORD METHODS //
    
    // Gets/Sets the color as a Record.
    // <group>
    virtual casacore::Record toRecord() const;
    virtual void fromRecord(const casacore::Record& record);
    // </group>
    
    
    // OPERATORS //
    
    // Assigns the value of the given PlotColor to this one.
    virtual PlotColor& operator=(const PlotColor& rh);
    
    // Returns true if this PlotColor is equal to the given; false otherwise.
    virtual bool operator==(const PlotColor& rh) const;

    // Returns true if this PlotColor is NOT equal to the given; false
    // otherwise.
    virtual bool operator!=(const PlotColor& rh) const;
    
protected:
    // casacore::Record key names.
    // <group>
    static const casacore::String REC_HEXADECIMAL; // String
    static const casacore::String REC_ALPHA;       // double
    // </group>
};
typedef casacore::CountedPtr<PlotColor> PlotColorPtr;


// Abstract class for fonts.  A font has a family, size, color, bold, italics,
// and underline properties.
class PlotFont {
public:
    // Constructor.
    PlotFont();
    
    // Destructor.
    virtual ~PlotFont();
    
    
    // ABSTRACT METHODS //
    
    // Returns the point size of this font, or -1 if the size was set in
    // pixels.
    virtual double pointSize() const = 0;
    
    // Sets the point size of this font to the given.
    virtual void setPointSize(double size) = 0;
    
    // Returns the pixel size of this font, or -1 if the size was set in
    // points.
    virtual int pixelSize() const = 0;
    
    // Sets the pixel size of this font to the given.
    virtual void setPixelSize(int size) = 0;
    
    // Returns the font family.
    virtual casacore::String fontFamily() const = 0;
    
    // Sets the font family to the given.
    virtual void setFontFamily(const casacore::String& font) = 0;
    
    // Returns a copy of the color for this font.
    virtual PlotColorPtr color() const = 0;
    
    // Sets the color of this font to the given.
    virtual void setColor(const PlotColor& color) = 0;
    
    // Gets/sets whether this font is italicized, bolded, and/or underlined,
    // respectively.
    // <group>
    virtual bool italics() const = 0;
    virtual void setItalics(bool i = true) = 0;
    virtual bool bold() const = 0;    
    virtual void setBold(bool b = true) = 0;    
    virtual bool underline() const = 0;    
    virtual void setUnderline(bool u = true) = 0;
    // </group>
    
    
    // CONVENIENCE METHODS //
    
    // Convenience methods for setting color.
    // <group>
    virtual void setColor(const PlotColorPtr c);
    virtual void setColor(const casacore::String& col);
    // </group>
    
    
    // RECORD METHODS //
    
    // Gets/Sets the color as a Record.
    // <group>
    virtual casacore::Record toRecord() const;
    virtual void fromRecord(const casacore::Record& record);
    // </group>
    
    
    // OPERATORS //
    
    // Assigns the value of the given PlotFont to this one.
    virtual PlotFont& operator=(const PlotFont& rh);
    
    // Returns true if this PlotFont is equal to the given; false otherwise.
    virtual bool operator==(const PlotFont& rh) const;

    // Returns true if this PlotFont is NOT equal to the given; false
    // otherwise.
    virtual bool operator!=(const PlotFont& rh) const;
    
protected:
    // casacore::Record key names.
    // <group>
    static const casacore::String REC_POINTSIZE; // double
    static const casacore::String REC_PIXELSIZE; // int
    static const casacore::String REC_FAMILY;    // String
    static const casacore::String REC_COLOR;     // Record
    static const casacore::String REC_ITALICS;   // bool
    static const casacore::String REC_BOLD;      // bool
    static const casacore::String REC_UNDERLINE; // bool
    // </group>
};
typedef casacore::CountedPtr<PlotFont> PlotFontPtr;


// Abstract class for area fill.  An area fill consists of a color and a
// pattern.
class PlotAreaFill {
public:
    // Pattern enum, similar in spirit to
    // http://doc.trolltech.com/4.3/qt.html#BrushStyle-enum .
    enum Pattern {
        FILL, MESH1, MESH2, MESH3, NOFILL
    };
    
    // Constructor
    PlotAreaFill();
    
    // Destructor
    virtual ~PlotAreaFill();
    
    
    // ABSTRACT METHODS //
    
    // Returns a copy of the color in this area fill.
    virtual PlotColorPtr color() const = 0;
    
    // Sets the area fill color to the given.
    virtual void setColor(const PlotColor& color) = 0;
    
    // Returns the pattern for this area fill.
    virtual Pattern pattern() const = 0;
    
    // Sets the pattern for this area fill to the given.
    virtual void setPattern(Pattern pattern) = 0;
    virtual void setPattern( const casacore::String& descriptor );
    
    // CONVENIENCE METHODS //
    
    // Convenience methods for setting color.
    // <group>
    virtual void setColor(const PlotColorPtr c);
    virtual void setColor(const casacore::String& co);
    // </group>
    
    
    // RECORD METHODS //
    
    // Gets/Sets the color as a Record.
    // <group>
    virtual casacore::Record toRecord() const;
    virtual void fromRecord(const casacore::Record& record);
    // </group>
    
    
    // OPERATORS //
    
    // Assigns the value of the given PlotAreaFill to this one.
    virtual PlotAreaFill& operator=(const PlotAreaFill& rh);
    
    // Returns true if this PlotAreaFill is equal to the given; false
    // otherwise.
    virtual bool operator==(const PlotAreaFill& rh) const;

    // Returns true if this PlotAreaFill is NOT equal to the given; false
    // otherwise.
    virtual bool operator!=(const PlotAreaFill& rh) const;
    
protected:
    // casacore::Record key names.
    // <group>
    static const casacore::String REC_COLOR;   // Record
    static const casacore::String REC_PATTERN; // int
    // </group>
};
typedef casacore::CountedPtr<PlotAreaFill> PlotAreaFillPtr;


// Abstract class for a line.  A line has a color, style, and width.
class PlotLine {
public:
    // Static //
    
    // Line styles.
    enum Style {
        SOLID, DASHED, DOTTED, NOLINE
    };
    
    
    // Non-Static //
    
    // Constructor.
    PlotLine();
    
    // Destructor.
    virtual ~PlotLine();
    
    
    // ABSTRACT METHODS // 
    
    // Returns this line's width.
    virtual double width() const = 0;
    
    // Sets the width to the given.
    virtual void setWidth(double width) = 0;
    
    // Returns this line's style.
    virtual Style style() const = 0;
    
    // Sets the style to the given.
    virtual void setStyle(Style style) = 0;
    
    // Returns a copy of the color used for this line.
    virtual PlotColorPtr color() const = 0;
    
    // Sets this line's color to the given.
    virtual void setColor(const PlotColor& color) = 0;
    
    
    // CONVENIENCE METHODS //
    
    // Convenience methods for setting color.
    // <group>
    virtual void setColor(const PlotColorPtr c);
    virtual void setColor(const casacore::String& col);
    // </group>
    
    
    // RECORD METHODS //
    
    // Gets/Sets the color as a Record.
    // <group>
    virtual casacore::Record toRecord() const;
    virtual void fromRecord(const casacore::Record& record);
    // </group>
    
    
    // OPERATORS //
    
    // Assigns the value of the given PlotLine to this one.
    virtual PlotLine& operator=(const PlotLine& rh);
    
    // Returns true if this PlotLine is equal to the given; false otherwise.
    virtual bool operator==(const PlotLine& rh) const;

    // Returns true if this PlotLine is NOT equal to the given; false
    // otherwise.
    virtual bool operator!=(const PlotLine& rh) const;
    
protected:
    // casacore::Record key names.
    // <group>
    static const casacore::String REC_WIDTH; // double
    static const casacore::String REC_STYLE; // int
    static const casacore::String REC_COLOR; // Record
    // </group>
};
typedef casacore::CountedPtr<PlotLine> PlotLinePtr;


// Abstract class for a symbol.  A symbol has a style, size, line, and area
// fill.
class PlotSymbol {
public:
    // Static //
    
    // Symbol style.
    enum Symbol {
        CHARACTER,               // for char symbols
        CIRCLE, SQUARE, DIAMOND, // standard shapes
        PIXEL,                   // draw a single pixel
        NOSYMBOL,                // don't show symbols
        AUTOSCALING              // autoscaling symbol
    };
    
    
    // Non-Static //
    
    // Constructor.
    PlotSymbol();
    
    //PlotSymbol(const PlotSymbol& copy);

    // Destructor.
    virtual ~PlotSymbol();
    
    
    // ABSTRACT METHODS //
    
    // Returns the size, in pixels, of this symbol.  If this symbol is a
    // character, the height corresponds to the font size (in either pixels or
    // points, see heightIsPixel()).
    virtual psize_t size() const = 0;
    
    // Sets the size of the symbol in pixels.  The heightIsPixel parameter is
    // used for character symbols and indicates whether the given height is in
    // points or pixels.
    virtual void setSize(double width, double height,
            bool heightIsPixel = true) = 0;
    
    // Gets/Sets whether the set height is in pixels or points, ONLY for
    // character symbols.
    // <group>
    virtual bool heightIsPixel() const = 0;    
    virtual void setHeightIsPixel(bool pixel = true) = 0;
    // </group>
    
    // Returns the symbol style.
    virtual Symbol symbol() const = 0;
    
    // Returns the character for this symbol.  Invalid if the style is not
    // CHARACTER.
    virtual char symbolChar() const = 0;
    
    // Returns the character unicode for this symbol.  Invalid if the style is
    // not CHARACTER.
    virtual unsigned short symbolUChar() const = 0;
    
    // Sets the symbol style to the given.
    virtual void setSymbol(Symbol symbol) = 0;
    virtual void setSymbol( const casacore::String& descriptor );
    
    // Sets the symbol character to the given.  Implies setSymbol(CHARACTER).
    virtual void setSymbol(char c) = 0;
    
    // Sets the symbol character unicode to the given.  Implies
    // setSymbol(CHARACTER).
    virtual void setUSymbol(unsigned short unicode) = 0;
    
    // Returns a copy of the line for the outline of this symbol.  Does not
    // apply to character or pixel symbols.
    virtual PlotLinePtr line() const = 0;
    
    // Sets the outline of this symbol to the given.  Does not apply to
    // character or pixel symbols.
    virtual void setLine(const PlotLine& color) = 0;
    
    // Returns a copy of the area fill for this symbol.  Does not apply to
    // character or pixel symbols.
    virtual PlotAreaFillPtr areaFill() const = 0;
    
    // Sets the area fill of this symbol to the given.  Does not apply to
    // character or pixel symbols.
    virtual void setAreaFill(const PlotAreaFill& fill) = 0;
    
    
    // CONVENIENCE METHODS //
    
    // Convenience method for setting size.
    virtual void setSize(psize_t size);
    
    // Returns true if this symbol is set to a character or not.
    virtual bool isCharacter() const;
    
    // Convenience methods for setting the line.
    // <group>
    virtual void setLine(const PlotLinePtr l);
    virtual void setLine(const casacore::String& color,
                         PlotLine::Style style = PlotLine::SOLID,
                         double width = 1.0);
    // </group>
    
    // Convenience methods for setting area fill.
    // <group>
    virtual void setAreaFill(const PlotAreaFillPtr a);
    virtual void setAreaFill(const casacore::String& color,
                 PlotAreaFill::Pattern pattern = PlotAreaFill::FILL);
    // </group>
    
    // Convenience method for setting color of both line and area fill.
    // <group>
    virtual void setColor(const PlotColor& color);
    virtual void setColor(const PlotColorPtr color);
    virtual void setColor(const casacore::String& color);
    casacore::String getColor() const;
    // </group>
    
    
    // RECORD METHODS //
    
    // Gets/Sets the color as a Record.
    // <group>
    virtual casacore::Record toRecord() const;
    virtual void fromRecord(const casacore::Record& record);
    // </group>
    
    // OPERATORS //
    
    // Assigns the value of the given PlotSymbol to this one.
    virtual PlotSymbol& operator=(const PlotSymbol& rh);
    
    // Returns true if this PlotSymbol is equal to the given; false otherwise.
    virtual bool operator==(const PlotSymbol& rh) const;

    // Returns true if this PlotSymbol is NOT equal to the given; false
    // otherwise.
    virtual bool operator!=(const PlotSymbol& rh) const;
    
protected:
    // casacore::Record key names.
    // <group>
    static const casacore::String REC_WIDTH;         // double
    static const casacore::String REC_HEIGHT;        // double
    static const casacore::String REC_HEIGHTISPIXEL; // bool
    static const casacore::String REC_SYMBOL;        // int
    static const casacore::String REC_UCHAR;         // int (no ushort in Records)
    static const casacore::String REC_LINE;          // Record
    static const casacore::String REC_AREAFILL;      // Record
    static const casacore::String REC_COLOR;			//String
    // </group>

private:
    const casacore::String DEFAULT_COLOR;
    casacore::String currentColor;
};
typedef casacore::CountedPtr<PlotSymbol> PlotSymbolPtr;


//////////////////////////////
// CONCRETE UTILITY CLASSES //
//////////////////////////////

// casacore::Coordinate on the canvas surface (i.e., the part where the actual plots
// are, which doesn't include things like axes, titles, etc.).  A coordinate
// has two values and a system.
class PlotCoordinate {
public:
    // Static //
    
    // casacore::Coordinate system.
    enum System {
        WORLD,            // in the units of the axes
        NORMALIZED_WORLD, // [0 ... 1] value that maps to a "percentage" of
                          // world units
        PIXEL             // pixels right and below the upper left corner of
                          // the canvas
    };
    
    
    // Non-Static //
    
    // Default constructor.
    PlotCoordinate();
    
    // Parameterized constructor.
    PlotCoordinate(double dx, double dy, System s = WORLD);
    
    // Copy constructor.
    PlotCoordinate(const PlotCoordinate& c);
    
    // Destructor.
    ~PlotCoordinate();
    
    
    // Accessors //
    
    // Returns the coordinate system.
    System system() const;
    
    // Returns the x value.
    double x() const;
    
    // Returns the y value.
    double y() const;
    
    
    // Operators //
    
    // Assigns the value of the given PlotCoordinate to this one.
    PlotCoordinate& operator=(const PlotCoordinate& rh);
    
    // Returns true if this PlotCoordinate is equal to the given; false
    // otherwise.
    bool operator==(const PlotCoordinate& rh) const;
    
    // Returns true if this PlotCoordinate is NOT equal to the given; false
    // otherwise.
    bool operator!=(const PlotCoordinate& rh) const;
    
private:
    // casacore::Coordinate system.
    System m_system;
    
    // X value.
    double m_x;
    
    // Y value.
    double m_y;
};


// A PlotRegion is basically just a wrapper for two PlotCoordinates: an upper
// left coordinate and a lower right coordinate.
class PlotRegion {
public:
    // Default constructor.
    PlotRegion();
    
    // Parameterized constructor.
    PlotRegion(const PlotCoordinate& upperLeft,
            const PlotCoordinate& lowerRight);
    
    // Copy constructor.
    PlotRegion(const PlotRegion& copy);
    
    // Destructor.
    ~PlotRegion();
    
    
    // Returns the upper left coordinate.
    const PlotCoordinate& upperLeft() const;
    
    // Returns the lower right coordinate.
    const PlotCoordinate& lowerRight() const;
    
    // Returns the top y value.
    double top() const;
    
    // Returns the bottom y value.
    double bottom() const;
    
    // Returns the left x value.
    double left() const;
    
    // Returns the right x value.
    double right() const;
    
    // Returns true if the region is valid, false otherwise.
    bool isValid() const;
    
private:
    // Upper-left coordinate.
    PlotCoordinate m_upperLeft;
    
    // Lower-right coordinate.
    PlotCoordinate m_lowerRight;
};


// A PlotAxesStack is basically a list of PlotRegions as well as axis
// information that provides stack functionality such as a current index, and
// moving up and down the stack.  A valid stack has a "base" followed by zero
// or more PlotRegions.  A stack can optionally have a limit on its length;
// adding to the stack after it reaches its length will remove the oldest
// members after the base.  The smallest value this limit can be is 2, (base +
// 1 value).
class PlotAxesStack {
public:
    // Constructor for empty stack.  Length limits with values <= 1 mean no
    // limit.
    PlotAxesStack(int lengthLimit = -1);
    
    // Destructor.
    ~PlotAxesStack();
    
    
    // Gets/Sets the length limit on this stack.  Values <= 1 mean no limit.
    // <group>
    int lengthLimit() const;
    void setLengthLimit(int lengthLimit);
    void clearLengthLimit() { setLengthLimit(-1); }
    // </group>
    
    // Returns whether the stack is valid (has size > 0) or not.
    bool isValid() const;
    
    // Returns the current stack index.
    unsigned int stackIndex() const;
    
    // Returns the stack size.
    unsigned int size() const;
    
    // Returns a copy of the stack.
    std::vector<PlotRegion> stack() const;
    
    // Returns a copy of the stack axes.  The first item is for x, the second
    // for y.
    std::vector<std::pair<PlotAxis, PlotAxis> > stackAxes() const;
    
    // Resets the stack and sets the stack base to the given.
    void setBase(const PlotRegion& base, PlotAxis xAxis, PlotAxis yAxis);
    
    // Adds the given region to the stack.
    void addRegion(const PlotRegion& region, PlotAxis xAxis, PlotAxis yAxis);
    
    // Clears the stack, including the base if keepBase is false.
    void clearStack(bool keepBase = false);
    
    // Returns the current region in the stack.
    PlotRegion currentRegion() const;
    
    // Returns the x-axis for the current region in the stack.
    PlotAxis currentXAxis() const;
    
    // Returns the y-axis for the current region in the stack.
    PlotAxis currentYAxis() const;
    
    // Moves the stack index the given delta.  If delta is negative, the index
    // goes backwards; if delta is positive, the index goes forward.  If delta
    // is zero, the index goes to the base.
    void move(int delta);
    
    // Moves the stack index the given delta (see move()) and returns the
    // current region.
    PlotRegion moveAndReturn(int delta);
    
private:
    // Length limit.
    int m_lengthLimit;
    
    // Region stack.
    std::vector<PlotRegion> m_stack;
    
    // Axes stack.
    std::vector<std::pair<PlotAxis, PlotAxis> > m_axes;
    
    // casacore::Stack index.
    unsigned int m_stackIndex;
    
    
    // Shrinks the region and axes stack to the given size, discarding the
    // oldest UNLESS the stack index is in the elements to be discarded.  In
    // this case, the element referenced by the index is also kept.
    void shrinkStacks(unsigned int n);
};


// PlotExportFormat contains parameters for exporting a canvas to a file.
class PlotExportFormat {
public:
    // Static //
    
    // The type of file/export.
    enum Type {
        JPG, PNG, PS, PDF, TEXT,
        NUM_FMTS
    };
    
    // Whether to have high resolution or not.
    enum Resolution {
        SCREEN, // basically a screen shot
        HIGH    // "high" resolution
    };
    
    // Converts to/from a Type and its casacore::String representation.
    // <group>
    static casacore::String exportFormat(Type t);
    static Type exportFormat(casacore::String t, bool* ok = NULL);
    // </group>
    
    // Gives/converts the standard extension for export types.
    // <group>
    static casacore::String extensionFor(Type t);   
    static Type typeForExtension(casacore::String file, bool* ok = NULL);
    // </group>
    
    // Returns all supported export formats.
    // <group>
    static std::vector<Type> supportedFormats();  
    static std::vector<casacore::String> supportedFormatStrings();
    // </group>
    
    // Returns all supported image formats.
    // <group>
    static std::vector<Type> supportedImageFormats();
    static std::vector<casacore::String> supportedImageFormatStrings();
    // </group>
    
    
    // Non-Static //
    
    // Sets up a format with the given type and location.  Default resolution
    // is SCREEN; default dpi is -1 (unspecified); default width and height
    // are -1 (unspecified).  Unspecified values are left up to the plotting
    // implementation.
    PlotExportFormat(Type t, const casacore::String& file);
    
    // Destructor.
    ~PlotExportFormat();
    
    // Public Members
    // <group>
    Type type;             // export type
	bool verbose;          // verbose text export
    casacore::String location;       // export location
    Resolution resolution; // export resolution
    int dpi;               // export dpi (if applicable)
    int width;             // export width (if applicable)
    int height;            // export height (if applicable)
    // </group>
};


//////////////////////////
// SMART POINTER MACROS //
//////////////////////////

// This is painful but necessary to have transparent smart pointers that
// support hierarchies and inheritance.  See examples in other files.
// cname = class name (to declare smart pointer for),
// cptrname = name for pointer (usually cname + Ptr),
// pname = immediate parent class name
// pptrname = name for pointer of parent class (usually pname + Ptr),
// gname = "grandparent" class name (or highest smart pointer in hierarchy),
// gptrname = grandparent pointer name (usually gname + Ptr)
#define INHERITANCE_POINTER(cname, cptrname, pname, pptrname, gname, gptrname)\
    class cptrname : public pptrname {                                        \
    public:                                                                   \
        cptrname () : pptrname () { }                                         \
        cptrname ( cname * val, bool del = true ) : pptrname() {                           \
            gname * v = dynamic_cast< gname *>(val);                          \
            if(v != NULL) gptrname ::operator=( gptrname (v, del));           \
        }                                                                     \
        cptrname ( const gptrname & val ) : pptrname () {                     \
            const cname * v = dynamic_cast<const cname *>(                    \
                              val.operator->());                              \
            if(v != NULL) gptrname ::operator=(val);                          \
        }                                                                     \
        cname & operator*() {                                                 \
            return dynamic_cast< cname &>(**(( gptrname *)this));             \
        }                                                                     \
        cname * operator->() {                                                \
            return dynamic_cast< cname *>((( gptrname *)this)->operator->()); \
        }                                                                     \
        const cname & operator*() const {                                     \
            return dynamic_cast<const cname &>(**(( gptrname * )this));       \
        }                                                                     \
        const cname * operator->() const {                                    \
            return dynamic_cast<const cname *>(                               \
                   (( gptrname *)this)->operator->());                        \
        }                                                                     \
        cptrname & operator=(const gptrname & val) {                          \
            const cname * v = dynamic_cast<const cname *>(val.operator->());  \
            if(v != NULL) (( gptrname *)this)->operator=(val);                \
            return *this;                                                     \
        }                                                                     \
        cptrname & operator=( gname * val) {                                  \
            cname * v = dynamic_cast< cname *>(val);                          \
            if(v != NULL) (( gptrname *)this)->operator=(val);                \
            return *this;                                                     \
        }                                                                     \
    };

// Convenience macro.
#define INHERITANCE_POINTER2(cname, cptrname, pname, pptrname) \
    INHERITANCE_POINTER(cname, cptrname, pname, pptrname, pname, pptrname)

// Macro for when the child class is a template.
#define INHERITANCE_TPOINTER(cname, cptrname, pname, pptrname, gname,gptrname)\
    template <class T> class cptrname : public pptrname {                     \
    public:                                                                   \
        cptrname () : pptrname () { }                                         \
        cptrname ( cname <T>* val, bool del = true ) : pptrname(){            \
            gname * v = dynamic_cast< gname *>(val);                          \
            if(v != NULL) gptrname ::operator=( gptrname (v, del));           \
        }                                                                     \
        cptrname ( const gptrname & val ) : pptrname () {                     \
            const cname <T>* v = dynamic_cast<const cname <T>*>(              \
                              val.operator->());                              \
            if(v != NULL) gptrname ::operator=(val);                          \
        }                                                                     \
        cptrname ( const cptrname <T> & val ) : pptrname() {                               \
            gptrname ::operator=((const gptrname &)val);                      \
        }                                                                     \
        cname <T>& operator*() {                                              \
            return dynamic_cast< cname <T>&>(**(( gptrname *)this));          \
        }                                                                     \
        cname <T>* operator->() {                                             \
            return dynamic_cast< cname <T>*>(                                 \
                    (( gptrname *)this)->operator->());                       \
        }                                                                     \
        const cname <T>& operator*() const {                                  \
            return dynamic_cast<const cname <T>&>(**(( gptrname * )this));    \
        }                                                                     \
        const cname <T>* operator->() const {                                 \
            return dynamic_cast<const cname <T>*>(                            \
                   (( gptrname *)this)->operator->());                        \
        }                                                                     \
        cptrname <T>& operator=(const gptrname & val) {                       \
            const cname <T>* v = dynamic_cast<const cname <T>*>(              \
                                 val.operator->());                           \
            if(v != NULL) (( gptrname *)this)->operator=(val);                \
            return *this;                                                     \
        }                                                                     \
        cptrname <T>& operator=( gname * val) {                               \
            cname <T>* v = dynamic_cast< cname <T>*>(val);                    \
            if(v != NULL) (( gptrname *)this)->operator=(val);                \
            return *this;                                                     \
        }                                                                     \
    };

// Convenience macro.
#define INHERITANCE_TPOINTER2(cname, cptrname, pname, pptrname) \
    INHERITANCE_TPOINTER(cname, cptrname, pname, pptrname, pname, pptrname)

}

#endif /*PLOTOPTIONS_H_*/