!-----------------------------------------------------------------
!
!  This file is (or was) part of SPLASH, a visualisation tool
!  for Smoothed Particle Hydrodynamics written by Daniel Price:
!
!  http://users.monash.edu.au/~dprice/splash
!
!  SPLASH comes with ABSOLUTELY NO WARRANTY.
!  This is free software; and you are welcome to redistribute
!  it under the terms of the GNU General Public License
!  (see LICENSE file for details) and the provision that
!  this notice remains intact. If you modify this file, please
!  note section 2a) of the GPLv2 states that:
!
!  a) You must cause the modified files to carry prominent notices
!     stating that you changed the files and the date of any change.
!
!  Copyright (C) 2005-2014 Daniel Price. All rights reserved.
!  Contact: daniel.price@monash.edu
!
!-----------------------------------------------------------------

!---------------------------------------------------------------------------
!  The plotlib module in SPLASH provides a consistent API so that SPLASH
!  can be compiled against different graphics libraries as the backend
!
!  This version provides an interface to giza, a plotting
!   library written by Daniel Price & James Wetter.
!
!  Giza implements basic 2D plotting functionality
!  on top of the cairo graphics library
!
! Interface written by James Wetter and Daniel Price (2010)
!---------------------------------------------------------------------------
module plotlib
 use giza, only: &
      plot_arro=>giza_arrow, &
      plot_annotate=>giza_annotate, &
      plot_band=>giza_band, &
      plot_bbuf=>giza_begin_buffer,&
      plot_box=>giza_box, &
      plot_circ=>giza_circle, &
      plot_close=>giza_close, &
      plot_curs=>giza_get_key_press, &
      plot_ebuf=>giza_end_buffer, &
      plot_end=>giza_close_device, &
      plot_env=>giza_set_environment, &
      plot_errb=>giza_error_bars, &
      plot_funx=>giza_function_x, &
      plot_label=>giza_label, &
      plot_line=>giza_line, &
      plot_lcur=>giza_mark_line, &
      plot_olin=>giza_mark_points, &
      plot_ncur=>giza_mark_points_ordered, &
      plot_page=>giza_change_page, &
      plot_poly=>giza_polygon, &
      plot_pt1=>giza_single_point, &
      plot_pt=>giza_points, &
      plot_ptxt=>giza_ptext, &
      plot_qch=>giza_get_character_height, &
      plot_qci=>giza_get_colour_index, &
      plot_qcir=>giza_get_colour_index_range, &
      plot_qcr=>giza_get_colour_representation, &
      plot_qfs=>giza_get_fill, &
      plot_qlw=>giza_get_line_width,&
      plot_qls=>giza_get_line_style,&
      plot_qlc=>giza_get_line_cap, &
      plot_qtxt=>giza_qtext, &
      plot_qwin=>giza_get_window, &
      plot_rect=>giza_rectangle, &
      plot_sah=>giza_set_arrow_style, &
      plot_scf=>giza_set_font, &
      plot_sch=>giza_set_character_height, &
      plot_sci=>giza_set_colour_index, &
      plot_scir=>giza_set_colour_index_range, &
      plot_scr=>giza_set_colour_representation, &
      plot_set_palette=>giza_set_colour_palette, &
      plot_sfs=>giza_set_fill, &
      plot_slc=>giza_set_line_cap, &
      plot_sls=>giza_set_line_style,&
      plot_slw=>giza_set_line_width, &
      plot_stbg=>giza_set_text_background, &
      plot_svp=>giza_set_viewport, &
      plot_swin=>giza_set_window, &
      plot_text=>giza_text, &
      plot_wnad=>giza_set_window_equal_scale, &
      plot_qcur=>giza_device_has_cursor, &
      plot_rgb_from_table=>giza_rgb_from_table, &
      giza_contour,            &
      giza_get_character_size, &
      giza_get_surface_size,   &
      giza_get_viewport,       &
      giza_open_device,        &
      giza_open_device_size,   &
      giza_render,             &
      giza_render_gray,        &
      giza_render_transparent, &
      giza_set_colour_table,   &
      giza_stop_prompting,     &
      giza_start_prompting,    &
      plot_left_click=>giza_left_click_f,     &
      plot_right_click=>giza_right_click_f,   &
      plot_middle_click=>giza_middle_click_f, &
      plot_shift_click=>giza_shift_click_f,   &
      plot_scroll_up=>giza_scroll_up_f,       &
      plot_scroll_down=>giza_scroll_down_f,   &
      plot_scroll_left=>giza_scroll_left_f,   &
      plot_scroll_right=>giza_scroll_right_f, &
      giza_vector,             &
      giza_format_number,      &
      giza_query_device,       &
      giza_draw_pixels, &
      giza_colour_index_min,&
      giza_colour_index_max,&
      giza_extend_none,&
      giza_extend_pad,&
      giza_extend_repeat, &
      giza_extend_reflect, &
      giza_filter_default
      implicit none
 logical, parameter :: plotlib_is_pgplot = .false.
 logical, parameter :: plotlib_supports_alpha = .true.
 integer, parameter :: plotlib_maxlinestyle = 6
 integer, parameter :: plotlib_maxfillstyle = 5
 integer, parameter :: plotlib_maxlinecolour = 16
 integer, parameter :: plotlib_maxpalette = 7
 integer, parameter :: plotlib_extend_pad = giza_extend_pad
 integer, parameter :: plotlib_extend_repeat = giza_extend_repeat
 integer, parameter :: plotlib_extend_reflect = giza_extend_reflect
 integer, parameter :: plotlib_extend_none = giza_extend_none

 public

contains

!---------------------------------------------
! initialise the plotting library
!---------------------------------------------
subroutine plot_init(devicein, ierr, papersizex, aspectratio, paperunits)
 use giza, only:giza_units_inches,giza_units_pixels,giza_units_mm

 character(len=*),intent(in)   :: devicein
 integer,intent(out)           :: ierr
 real, intent(in), optional    :: papersizex,aspectratio
 integer, intent(in), optional :: paperunits
 real                          :: width,height
 integer                       :: units, id

 if (present(papersizex)) then
    width = papersizex
    if (present(aspectratio)) then
       height = width*aspectratio
    else
       height = width/sqrt(2.)
    endif
    if (present(paperunits)) then
       select case(paperunits)
       case(0)
          units = giza_units_pixels
       case(1)
          units = giza_units_inches
       case(2)
          units = giza_units_mm
          width = 10.*width
          height = 10.*height
       end select
    else
       units = giza_units_inches
    endif
    id = giza_open_device_size(devicein, 'splash', width, height, units)
 else
    id = giza_open_device(devicein,'splash')
 endif
 ! id<0 should return an error, but +ve id is OK
 if (id < 0) then
    ierr = id
 else
    ierr = 0
 endif

 if (ierr==0) then
    call giza_stop_prompting
 endif
end subroutine plot_init

subroutine plot_gray(a, idim, jdim, i1, i2, j1, j2, a1, a2, tr, iextend, filter)
 integer,intent(in) :: IDIM, JDIM, I1, I2, J1, J2
 real,intent(in)    :: A(IDIM,JDIM), A1, A2, TR(6)
 real               :: affine(6)
 integer, intent(in), optional :: iextend,filter
 integer :: ifilter

 call convert_tr_to_affine(tr,affine)

 ifilter = giza_filter_default
 if (present(filter)) ifilter = filter

 if (present(iextend)) then
    call giza_render_gray(idim,jdim,a,i1-1,i2-1,j1-1,j2-1,a1,a2,iextend,ifilter,affine)
 else
    call giza_render_gray(idim,jdim,a,i1-1,i2-1,j1-1,j2-1,a1,a2,0,ifilter,affine)
 endif

end subroutine plot_gray

subroutine plot_imag(a, idim, jdim, i1, i2, j1, j2, a1, a2, tr, iextend, filter)
 integer,intent(in) :: IDIM, JDIM, I1, I2, J1, J2
 real,intent(in)    :: A(IDIM,JDIM), A1, A2, TR(6)
 real               :: affine(6)
 integer, intent(in), optional :: iextend,filter
 integer :: ifilter

 call convert_tr_to_affine(tr,affine)

 ifilter = giza_filter_default
 if (present(filter)) ifilter = filter

 if (present(iextend)) then
    call giza_render(idim,jdim,a,i1-1,i2-1,j1-1,j2-1,a1,a2,iextend,ifilter,affine)
 else
    call giza_render(idim,jdim,a,i1-1,i2-1,j1-1,j2-1,a1,a2,0,ifilter,affine)
 endif

end subroutine plot_imag

subroutine plot_imag_alpha(dat, alpha, idim, jdim, i1, i2, j1, j2, a1, a2, tr, iextend, filter)
 integer,intent(in) :: IDIM, JDIM, I1, I2, J1, J2
 real,intent(in)    :: dat(IDIM,JDIM), alpha(IDIM,JDIM), A1, A2, TR(6)
 real               :: affine(6)
 integer, intent(in), optional :: iextend,filter
 integer :: ifilter

 call convert_tr_to_affine(tr,affine)

 ifilter = giza_filter_default
 if (present(filter)) ifilter = filter

 if (present(iextend)) then
    call giza_render(idim,jdim,dat,alpha,i1-1,i2-1,j1-1,j2-1,a1,a2,iextend,ifilter,affine)
 else
    call giza_render(idim,jdim,dat,alpha,i1-1,i2-1,j1-1,j2-1,a1,a2,0,ifilter,affine)
 endif

end subroutine plot_imag_alpha

subroutine plot_imag_transparent(a, idim, jdim, i1, i2, j1, j2, a1, a2, tr)
 integer,intent(in) :: IDIM, JDIM, I1, I2, J1, J2
 real,intent(in)    :: A(IDIM,JDIM), A1, A2, TR(6)
 real               :: affine(6)

 call convert_tr_to_affine(tr,affine)
 call giza_render_transparent(idim,jdim,a,i1-1,i2-1,j1-1,j2-1,a1,a2,0,0,affine)

end subroutine plot_imag_transparent

subroutine plot_ctab(l,r,g,b,nc,contra,bright)
 integer,intent(in) :: nc
 real,intent(in)    :: l(nc),r(nc),g(nc),b(nc),contra,bright

 call giza_set_colour_table(l,r,g,b,nc,contra,bright)

end subroutine plot_ctab

subroutine plot_qvsz(paperunits,x1,x2,y1,y2)
 use giza, only:giza_get_paper_size,giza_units_device,giza_units_inches,giza_units_pixels,giza_units_mm
 real, intent(out)   :: x1,x2,y1,y2
 integer, intent(in) :: paperunits
 integer :: units

 x1 = 0.
 y1 = 0.
 select case(paperunits)
 case(0)
    units = giza_units_pixels
 case(1)
    units = giza_units_inches
 case(2)
    units = giza_units_mm
 case default
    units = giza_units_device
 end select
 call giza_get_paper_size(units,x2,y2)

end subroutine plot_qvsz

subroutine plot_bins(nbin,x,data,centre)
 integer, intent(in)               :: nbin
 real, dimension(nbin), intent(in) :: x, data
 logical, intent(in)               :: centre

 print*,' WARNING: plot_bins not implemented in giza'

end subroutine plot_bins

subroutine plot_qvp(units, x1, x2, y1, y2)
 integer,intent(in) :: units
 real,intent(out)   :: x1, x2, y1, y2

 call giza_get_viewport(units_giza(units),x1,x2,y1,y2)

end subroutine plot_qvp

subroutine plot_qcs(units,xch,ych)
 integer,intent(in) :: units
 real,intent(out)   :: xch,ych

 call giza_get_character_size(units_giza(units),xch,ych)

end subroutine plot_qcs

subroutine plot_qcol(icolmin,icolmax)
 integer,intent(out) :: icolmin,icolmax

 icolmin = giza_colour_index_min
 icolmax = giza_colour_index_max

end subroutine plot_qcol

subroutine plot_scrn(ci,name,ier)
 integer,intent(in)          :: ci
 character(len=*),intent(in) :: name
 integer,intent(out)         :: ier

 print*,' WARNING: plot_scrn not implemented in giza'
 ier = 1

end subroutine plot_scrn

subroutine plot_qinf(item,value,length)
 character(len=*),intent(in)  :: item
 character(len=*),intent(out) :: value
 integer,intent(out)          :: length
 character(len=10) :: datestring,timestring

 select case(item)
 case('VERSION','version')
    value = 'giza-1.1'
 case('STATE','state')
    print*,' WARNING: query for STATE not yet implemented in giza'
 case('USER','user')
    print*,' WARNING: query for USER not yet implemented in giza'
 case('NOW','now')
    call date_and_time(datestring,timestring)
    value = datestring(7:8)//'-'//datestring(5:6)//'-'//datestring(1:4)// &
             ' '//timestring(1:2)//':'//timestring(3:4)
 case('DEVICE','device')
    print*,' WARNING: query for DEVICE not yet implemented in giza'
 case('FILE','file')
    print*,' WARNING: query for FILE not yet implemented in giza'
 case('TYPE','type')
    call giza_query_device('type',value)
 case('DEV/TYPE','dev/type')
    print*,' WARNING: query for DEV/TYPE not yet implemented in giza'
 case('HARDCOPY','hardcopy')
    call giza_query_device('hardcopy',value)
 case('TERMINAL','terminal')
    !--in giza the current device is never the terminal
    value = 'NO'
 case('CURSOR','cursor')
    call giza_query_device('cursor',value)
 case('SCROLL','scroll')
    !--no scroll capability in any current giza devices
    value = 'NO'
 case default
    value = ' '
 end select
 length = len_trim(value)

end subroutine plot_qinf

subroutine plot_numb(m,pp,form,string,nc)
 integer,intent(in)           :: m,pp,form
 character(len=*),intent(out) :: string
 integer,intent(out)          :: nc

 call giza_format_number(m,pp,form,string)
 nc = len_trim(string)

end subroutine plot_numb

subroutine plot_set_opacity(alpha)
 real, intent(in)           :: alpha
 integer :: ci
 real    :: red,green,blue

 call plot_qci(ci)
 call plot_qcr(ci,red,green,blue)
 call plot_scr(ci,red,green,blue,alpha)

end subroutine plot_set_opacity


subroutine plot_err1(dir,x,y,e,t)
 integer,intent(in) :: dir
 real,intent(in)    :: x,y,e
 real,intent(in)    :: t
 real, dimension(1) :: xi,yi,ei

 xi(1) = x
 yi(1) = y
 ei(1) = e
 call plot_errb(dir,1,xi,yi,ei,t)

end subroutine plot_err1

subroutine plot_conb(a,idim,jdim,i1,i2,j1,j2,c,nc,tr,blank)
 integer,intent(in) :: idim,jdim,i1,i2,j1,j2,nc
 real,intent(in)    :: a(idim,jdim),c(*),tr(6),blank
 real               :: affine(6)

 print*,' WARNING: blanking in contouring not implemented in giza'
 call convert_tr_to_affine(tr,affine)
 call giza_contour(idim,jdim,a,i1-1,i2-1,j1-1,j2-1,nc,c,affine)

end subroutine plot_conb

subroutine plot_cons(a,idim,jdim,i1,i2,j1,j2,c,nc,tr)
 integer,intent(in) :: idim,jdim,i1,i2,j1,j2,nc
 real,intent(in)    :: a(idim,jdim),c(*),tr(6)
 real               :: affine(6)

 call convert_tr_to_affine(tr,affine)
 call giza_contour(idim,jdim,a,i1-1,i2-1,j1-1,j2-1,nc,c,affine)

end subroutine plot_cons

subroutine plot_conl(a,idim,jdim,i1,i2,j1,j2,c,tr,label,intval,mininit)
 integer,intent(in)          :: idim,jdim,i1,i2,j1,j2,intval,mininit
 real,intent(in)             :: a(idim,jdim),c,tr(6)
 character(len=*),intent(in) :: label
 real               :: affine(6)
 integer, parameter :: nc = 1
 real, dimension(nc) :: clevel

 clevel(1) = c
 print*,' WARNING: labelled coutouring not implemented in giza'
 call convert_tr_to_affine(tr,affine)
 call giza_contour(idim,jdim,a,i1-1,i2-1,j1-1,j2-1,nc,clevel,affine)
 print*,'nc = ',nc

end subroutine plot_conl

subroutine plot_vect(a,b,idim,jdim,i1,i2,j1,j2,c,nc,tr,blank)
 integer,intent(in) :: idim,jdim,i1,i2,j1,j2,nc
 real,intent(in)    :: a(idim,jdim),b(idim,jdim),tr(6),blank,c
 real               :: affine(6)

 call convert_tr_to_affine(tr,affine)
 call giza_vector(idim,jdim,a,b,i1-1,i2-1,j1-1,j2-1,c,nc,affine,blank)

end subroutine plot_vect

subroutine plot_pixl(ia,idim,jdim,i1,i2,j1,j2,x1,x2,y1,y2)
 use giza, only:giza_draw_pixels,giza_filter_default
 integer,intent(in) :: idim,jdim,i1,i2,j1,j2
 integer,intent(in) :: ia(idim,jdim)
 real,intent(in)    :: x1,x2,y1,y2

 call giza_draw_pixels(IDIM, JDIM, IA, I1-1, I2-1, J1-1, J2-1, &
                       X1, X2, Y1, Y2, 0, giza_filter_default)

end subroutine plot_pixl

subroutine plot_pap(widthin,aspect,paperunits)
 use giza, only:giza_set_paper_size
 use giza, only:giza_units_inches,giza_units_pixels,giza_units_mm
 real,intent(in) :: widthin,aspect
 integer, intent(in), optional :: paperunits
 integer :: units
 real    :: width

 width = widthin
 units = giza_units_inches

 if (present(paperunits)) then
    select case(paperunits)
    case(0)
       units = giza_units_pixels
    case(1)
       units = giza_units_inches
    case(2)
       units = giza_units_mm
       width = 0.1*width
    end select
 endif

 call giza_set_paper_size(units,width,width*aspect)

end subroutine plot_pap

!
!--this subroutine can be called  to
!  make sure that the viewport lies exactly on
!  pixel boundaries.
!
!  unnecessary for giza
!
subroutine plot_set_exactpixelboundaries()

end subroutine plot_set_exactpixelboundaries

!------------------------------------------------------------
! Function to convert PGPLOT units value to giza units value
!------------------------------------------------------------
integer function units_giza(pgplotunits)
 use giza, only:giza_units_normalized,giza_units_inches, &
                 giza_units_mm,giza_units_pixels,giza_units_world
 integer, intent(in) :: pgplotunits

 select case(pgplotunits)
 case(0)
    units_giza = giza_units_normalized
 case(1)
    units_giza = giza_units_inches
 case(2)
    units_giza = giza_units_mm
 case(3)
    units_giza = giza_units_pixels
 case(4)
    units_giza = giza_units_world
 case default  ! giza will give an error
    units_giza = pgplotunits
 end select

end function units_giza

subroutine convert_tr_to_affine(tr,affine)
 real, dimension(6), intent(in)  :: tr
 real, dimension(6), intent(out) :: affine

 affine(1) = TR(2)
 affine(2) = TR(3)
 affine(3) = TR(5)
 affine(4) = TR(6)
 affine(5) = TR(1) + 0.5 * TR(2)
 affine(6) = TR(4) + 0.5 * TR(6)

end subroutine convert_tr_to_affine

end module plotlib
