; docformat = 'rst'
;
; NAME:
;   cgOverPlot__Define
;
; PURPOSE:
;   The purpose of this program is to create a data object that can be plotted or drawn on
;   a set of axes set up by another plotting command.
;
;******************************************************************************************;
;                                                                                          ;
;  Copyright (c) 2012, by Fanning Software Consulting, Inc. All rights reserved.           ;
;                                                                                          ;
;  Redistribution and use in source and binary forms, with or without                      ;
;  modification, are permitted provided that the following conditions are met:             ;
;                                                                                          ;
;      * Redistributions of source code must retain the above copyright                    ;
;        notice, this list of conditions and the following disclaimer.                     ;
;      * Redistributions in binary form must reproduce the above copyright                 ;
;        notice, this list of conditions and the following disclaimer in the               ;
;        documentation and/or other materials provided with the distribution.              ;
;      * Neither the name of Fanning Software Consulting, Inc. nor the names of its        ;
;        contributors may be used to endorse or promote products derived from this         ;
;        software without specific prior written permission.                               ;
;                                                                                          ;
;  THIS SOFTWARE IS PROVIDED BY FANNING SOFTWARE CONSULTING, INC. ''AS IS'' AND ANY        ;
;  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES    ;
;  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT     ;
;  SHALL FANNING SOFTWARE CONSULTING, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,             ;
;  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED    ;
;  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;         ;
;  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND             ;
;  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT              ;
;  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS           ;
;  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                            ;
;******************************************************************************************;
;
;+
; The purpose of this program is to create a data object that can be plotted or drawn on
; a set of axes set up by another plotting command.
;
; :Categories:
;    Graphics
;    
; :Examples:
;    Use, for example, with the cgPlot command::
;       oplotObj1 = Obj_New('cgOverPlot', cgDemoData(17), Color='red', PSYM=-1, LINESTYLE=2)
;       oplotObj2 = Obj_New('cgOverPlot', cgDemoData(17), Color='blue', PSYM=-2, LINESTYLE=4)
;       cgPlot, cgDemoData(17), Color='purple', PSYM=-4, OPLOTS=[oplotObj1, oplotObj2]
;       Obj_Destroy, [oplotObj1, oplotObj2]
;       
; :Author:
;    FANNING SOFTWARE CONSULTING::
;        David W. Fanning 
;        1645 Sheely Drive
;        Fort Collins, CO 80526 USA
;        Phone: 970-221-0438
;        E-mail: david@idlcoyote.com
;        Coyote's Guide to IDL Programming: http://www.idlcoyote.com
;
; :History:
;     Change History::
;        Written, 18 July  2012. DWF.
;        The THICK keyword was not being set in the INIT method. Fixed. 2 Nov 2012. DWF.
;         
; :Copyright:
;     Copyright (c) 2012, Fanning Software Consulting, Inc.
;-

;+
; The initialization method of the object. Called automatically when the object
; is created.
; 
; :Params:
;    x: in, required, type=any
;         If X is provided without Y, a vector representing the dependent values to be 
;         plotted If both X and Y are provided, X is the independent parameter and 
;         Y is the dependent parameter to be plotted.
;    y: in, optional, type=any
;         A vector representing the dependent values to be plotted.
;       
; :Keywords:
;     addcmd: in, optional, type=boolean, default=0
;        Set this keyword to add the command to the resizeable graphics window cgWindow.
;     color: in, optional, type=string, default='opposite'
;        The name of the data color. This is the color of the data line.
;     draw: in, optional, type=boolean, default=0
;        If this keyword is set, the data is drawn as soon as the object is created.
;     linestyle: in, optional, type=integer, default=0
;        The line style for drawing the line.
;     psym: in, optional, type=integer
;        Any normal IDL PSYM values, plus any value supported by the Coyote Library
;        routine cgSYMCAT. An integer between 0 and 46.
;     skip: in, optional, type=integer, default=1
;        The number of data points to skip when the line is drawn. The default is to
;        not skip any data points, but to plot them all.
;     symcolor: in, optional, type=string
;        The name of the symbol color. By default, the same as the `COLOR` keyword.
;     symsize: in, optional, type=float, default=1.0
;        The symbol size.
;     symthick: in, optional, type=float, default=1.0
;        The thickness of the symbol.
;     thick: in, optional, type=float, default = 1.0
;        The thickness of the line.
;     visible: in, optional, type=boolean, default=1
;        Set this keyword to determine in the line should be drawn (visible=1), or
;        if the line should not be drawn (visible=0).
;-
FUNCTION cgOverPlot::INIT, x, y, $
    ADDCMD=addcmd, $
    COLOR=color, $
    DRAW=draw, $
    LINESTYLE=linestyle, $
    PSYM=psym, $
    SKIP=skip, $
    SYMCOLOR=symcolor, $
    SYMSIZE=symsize, $
    SYMTHICK=symthick, $
    THICK=thick, $
    VISIBLE=visible
    
    Compile_Opt idl2

    Catch, theError
    IF theError NE 0 THEN BEGIN
        Catch, /CANCEL
        void = cgErrorMsg()
        IF N_Elements(currentState) NE 0 THEN cgSetColorState, currentState
        RETURN, 0
    ENDIF
    
    ; Set up PostScript device for working with colors.
    IF !D.Name EQ 'PS' THEN Device, COLOR=1, BITS_PER_PIXEL=8
    
    ; Check parameters.
    IF N_Params() EQ 0 THEN BEGIN
        Print, 'USE SYNTAX: cgOverPlot, x, y'
        RETURN, 0
    ENDIF
    
    ; Adding this object to a window?
    IF Keyword_Set(addcmd) THEN BEGIN
        cgControl, Execute=0
        cgWindow, 'Draw', self, ADDCMD=1
       ENDIF
     
    ; Sort out which is the dependent and which is independent data.
    CASE N_Params() OF
      
       1: BEGIN
       dep = x
       indep = Findgen(N_Elements(dep))
       ENDCASE
    
       2: BEGIN
       dep = y
       indep = x
       ENDCASE
    
    ENDCASE
    
    ; If either of these input vectors are scalars, make them vectors.
    IF N_Elements(dep) EQ 1 THEN dep = [dep]
    IF N_Elements(indep) EQ 1 THEN indep = [indep]
    
    ; Default colors.
    cgSetColorState, 1, CURRENTSTATE=currentState
    color = cgDefaultColor(color, DEFAULT="opposite")
    symcolor = cgDefaultColor(symcolor, DEFAULT=color)

    ; Other parameter defaults.
    IF N_Elements(linestyle) EQ 0 THEN linestyle = 0
    IF N_Elements(psym) EQ 0 THEN psym = 0
    IF N_Elements(thick) EQ 0 THEN thick = 1.0
    IF N_Elements(skip) EQ 0 THEN skip = 1
    IF N_Elements(symsize) EQ 0 THEN symsize = 1.0
    IF N_Elements(symthick) EQ 0 THEN symthick = 1.0
    IF N_Elements(visible) EQ 0 THEN visible = 1
    
    ; Load the object.
    self.dep = Ptr_New(dep)
    self.indep = Ptr_New(indep)
    self.color = color
    self.linestyle = linestyle    
    self.psym = psym
    self.thick = thick
    self.skip = 1
    self.symcolor = symcolor
    self.symsize = symsize
    self.symthick = symthick
    self.xrange = [Min(indep), Max(indep)]
    self.yrange = [Min(dep), Max(dep)]
    self.visible = visible
    
    IF Keyword_Set(draw) THEN self -> Draw
    IF Keyword_Set(addcmd) THEN cgControl, Execute=1
    
    RETURN, 1
 
END

;+
; The clean-up routine for the object. Destroy pointers, etc.
;-
PRO cgOverPlot::CLEANUP

    Ptr_Free, self.dep
    Ptr_Free, self.indep
    
END



;+
; This method draws the overplot object. It assumes a set of axes has been
; established by some other graphics command.
;
; :Keywords:
;     skip: in, optional, type=integer
;         Set this keyword to the number of data points to skip when drawing the
;         data vectors. Similar to the SKIP parameter, but this keyword gives you
;         the opportunity to temporarily over-ride the value of the SKIP parameter.
;-
PRO cgOverPlot::Draw, SKIP=skip

    Compile_Opt idl2

    Catch, theError
    IF theError NE 0 THEN BEGIN
        Catch, /CANCEL
        void = cgErrorMsg()
        RETURN
    ENDIF
    
    ; If the plot is not visible, return now.
    IF ~self.visible THEN RETURN
    
    ; Are we skipping data points?
    IF N_Elements(skip) NE 0 THEN skipCount = skip
    IF N_Elements(skipCount) EQ 0 THEN skipCount = self.skip

    ; If you aren't skipping, draw all the data.
    IF skipCount EQ 1 THEN BEGIN
        asymbol = cgSymCat(self.psym, THICK=self.symThick, COLOR=self.symcolor)
        IF self.psym LT 0 THEN asymbol = -asymbol
        OPlot, *self.indep, *self.dep, COLOR=cgColor(self.color), LINESTYLE=self.linestyle, $
            PSYM=asymbol, SYMSIZE=self.symsize, THICK=self.thick
    ENDIF ELSE BEGIN
        count = N_Elements(*self.dep)-1
        asymbol = cgSymCat(self.psym, THICK=self.symThick, COLOR=self.symcolor)
        IF self.psym LT 0 THEN asymbol = -asymbol 
        OPlot, (*self.indep)[0:count:skipCount], (*self.dep)[0:count:skipCount], $
            COLOR=cgColor(self.color), LINESTYLE=self.linestyle, $
            PSYM=asymbol, SYMSIZE=self.symsize, THICK=self.thick
    ENDELSE
    
END


;+
; This method obtains the current properties of the object. 
; 
; :Keywords:
;     color: out, optional, type=string
;        The name of the data color. This is the color of the data line.
;     dep: out, optional, type=varies
;        The current dependent data of the object.
;     draw: out, optional, type=boolean
;        If this keyword is set, the data is drawn as soon as the object is created.
;     indep: out, optional, type=varies
;        The current independent data of the object.
;     linestyle: out, optional, type=integer
;        The line style for drawing the line.
;     psym: out, optional, type=integer
;        Any normal IDL PSYM values, plus any value supported by the Coyote Library
;        routine cgSYMCAT. An integer between 0 and 46.
;     skip: out, optional, type=integer, default=1
;        The number of data points to skip when the line is drawn. 
;     symcolor: out, optional, type=string
;        The name of the symbol color. 
;     symsize: out, optional, type=float
;        The symbol size.
;     symthick: out, optional, type=float
;        The thickness of the symbol.
;     thick: out, optional, type=float
;        The thickness of the line.
;     xrange: out, optional, type=fltarr
;        The range of the dependent data.
;     yrange: out, optional, type=fltarr
;        The range of the independent data.
;     visible: out, optional, type=boolean
;        The visibility of the objects plot line.
;-
PRO cgOverPlot::GetProperty, $
    COLOR=color, $
    DEP=dep, $
    DRAW=draw, $
    INDEP=indep, $
    LINESTYLE=linestyle, $
    PSYM=psym, $
    SKIP=skip, $
    SYMCOLOR=symcolor, $
    SYMSIZE=symsize, $
    SYMTHICK=symthick, $
    THICK=thick, $
    XRANGE=xrange, $
    YRANGE=yrange, $
    VISIBLE=visible

    Compile_Opt idl2

    Catch, theError
    IF theError NE 0 THEN BEGIN
        Catch, /CANCEL
        void = cgErrorMsg()
        RETURN
    ENDIF

    IF Arg_Present(color) THEN color = self.color
    IF Arg_Present(dep) THEN dep = *self.dep
    IF Arg_Present(indep) THEN indep = *self.indep
    IF Arg_Present(linestyle) THEN linestyle = self.linestyle
    IF Arg_Present(psym) THEN psym = self.psym
    IF Arg_Present(skip) THEN skip = self.skip
    IF Arg_Present(symcolor) THEN symcolor = self.symcolor
    IF Arg_Present(symsize) THEN symsize = self.symsize
    IF Arg_Present(symthick) THEN symthick = self.symthick
    IF Arg_Present(thick) THEN thick = self.thick
    IF Arg_Present(xrange) THEN xrange = self.xrange
    IF Arg_Present(yrange) THEN yrange = self.yrange
    IF Arg_Present(visible) THEN visible = self.visible
    
END
    

;+
; This method sets the properties of the object.
;
; :Keywords:
;     color: in, optional, type=string
;        The name of the data color. This is the color of the data line.
;     dep: in, optional, type=varies
;        A vector of dependent data.
;     draw: in, optional, type=boolean, default=0
;        If this keyword is set, the data is drawn as soon as the properties are set.
;     indep: in, optional, type=varies
;        A vector of independent data.
;     linestyle: in, optional, type=integer
;        The line style for drawing the line.
;     psym: in, optional, type=integer
;        Any normal IDL PSYM values, plus any value supported by the Coyote Library
;        routine cgSYMCAT. An integer between 0 and 46.
;     skip: in, optional, type=integer, default=1
;        The number of data points to skip when the line is drawn. The default is to
;        not skip any data points, but to plot them all.
;     symcolor: in, optional, type=string
;        The name of the symbol color. By default, the same as the `COLOR` keyword.
;     symsize: in, optional, type=float, default=1.0
;        The symbol size.
;     symthick: in, optional, type=float, default=1.0
;        The thickness of the symbol.
;     thick: in, optional, type=float, default = 1.0
;        The thickness of the line.
;     visible: in, optional, type=boolean, default=1
;        Set this keyword to determine in the line should be drawn (visible=1), or
;        if the line should not be drawn (visible=0).
;-
PRO cgOverPlot::SetProperty, $
    COLOR=color, $
    DEP=dep, $
    DRAW=draw, $
    INDEP=indep, $
    LINESTYLE=linestyle, $
    PSYM=psym, $
    SKIP=skip, $
    SYMCOLOR=symcolor, $
    SYMSIZE=symsize, $
    SYMTHICK=symthick, $
    THICK=thick, $
    VISIBLE=visible

    Compile_Opt idl2

    Catch, theError
    IF theError NE 0 THEN BEGIN
        Catch, /CANCEL
        void = cgErrorMsg()
        RETURN
    ENDIF

    IF N_Elements(color) NE 0 THEN self.color = color
    IF N_Elements(dep) NE 0 THEN *self.dep = dep
    IF N_Elements(indep) NE 0 THEN *self.indep = indep
    self.yrange = [Min(*self.dep), Max(*self.dep)]
    self.xrange = [Min(*self.indep), Max(*self.indep)]
    IF N_Elements(linestyle) NE 0 THEN self.linestyle = linestyle
    IF N_Elements(psym) NE 0 THEN self.psym = psym
    IF N_Elements(skip) NE 0 THEN self.skip = skip
    IF N_Elements(symcolor) NE 0 THEN self.symcolor = symcolor
    IF N_Elements(symsize) NE 0 THEN self.symsize = symsize
    IF N_Elements(symthick) NE 0 THEN self.symthick = symthick
    IF N_Elements(thick) NE 0 THEN self.thick = thick
    IF N_Elements(visible) NE 0 THEN self.visible = visible
    
    ; Need to draw?
    IF Keyword_Set(draw) THEN self -> Draw
     
END

;+
; The class definition module for the object.
; 
; :Params:
;     class: out, optional, type=struct
;        The class definition as a structure variable. Occasionally useful.
;-
PRO cgOverPlot__Define, class

    class = { CGOVERPLOT, $
              INHERITS IDL_OBJECT, $ ; To allow IDL 8 dot referencing of properties.
              dep: Ptr_New(), $      ; The dependent data.
              indep: Ptr_New(), $    ; The independent data.
              color: "", $           ; The color of the overplotted line.
              linestyle: 0L, $       ; The linestyle of the overplotted line.
              psym: 0L, $            ; The symbol of the overplotted line.
              symcolor: "", $        ; The symbol color.
              symthick: 0L, $        ; The thickness of the line symbol.
              symsize: 0L, $         ; The size of the line symbol.
              thick: 0L, $, $        ; The thickness of the overplotted line.
              skip: 0L, $            ; The number of data points to skip in the drawing.
              visible: 0L, $         ; A flag that indicates if the plot should be drawn.
              xrange: FltArr(2), $   ; The X range of the data.
              yrange: FltArr(2) $    ; The Y range of the data.
            }
            
END