; docformat = 'rst'
;+
; Create a thumbnail image of a simple visualization of the data. The 
; visualization type is guessed based on the dimensions of the data.
;-
;+
; Create a line plot.
;
; :Returns: 
;    bytarr(3, m, n) or -1L
;
; :Params:
;    data : in, required, type=numeric array
;       data to visualize
;
; :Keywords:
;    valid : out, optional, type=boolean
;       set to a named variable to get status of visualization; if no valid 
;       visualization type could be found, -1L is returned
;-
function mg_thumbnail_lineplot, data, valid=valid
  compile_opt strictarr
  ; min and max size of the output image
  maxDimSize = 100L
  minDimSize = 10L
  
  ; goal is to make curve in output have a mean absolute value of the derivative
  ; of 1 (because that makes differences in the slope easiest to see)
  mDeriv = mean(abs(deriv(data)))
  xrange = n_elements(data) - 1L
  yrange = max(data, min=minData) - minData
  
  ; calculate output dimensions, making sure the dimensions fall in the range
  ; of minDimSize...maxDimSize 
  dims = [xrange, yrange * mDeriv]
  dims = long(dims / float(max(dims)) * maxDimSize)
  dims = dims > minDimSize < maxDimSize
  
  view = obj_new('IDLgrView')
  
  model = obj_new('IDLgrModel')
  view->add, model
  
  plot = obj_new('IDLgrPlot', data, color=[0, 0, 255])
  model->add, plot
  ; use most of the view: -0.9...0.9 for both x and y
  plot->getProperty, xrange=xr, yrange=yr
  xc = mg_linear_function(xr, [-0.9, 0.9])
  yc = mg_linear_function(yr, [-0.9, 0.9])
  if (total(finite(yc)) ne 2L) then begin
    yc = mg_linear_function([yr[0] - 1, yr[0] + 1], [-0.9, 0.9])
  endif 
  plot->setProperty, xcoord_conv=xc, ycoord_conv=yc
  
  buffer = obj_new('IDLgrBuffer', dimensions=dims)
  buffer->draw, view
  buffer->getProperty, image_data=im
  
  obj_destroy, [buffer, view]
  
  return, im
end
;+
; Create a contour plot.
;
; :Returns: 
;    bytarr(3, m, n) or -1L
;
; :Params:
;    data : in, required, type=numeric array
;       data to visualize
;
; :Keywords:
;    valid : out, optional, type=boolean
;       set to a named variable to get status of visualization; if no valid 
;       visualization type could be found, -1L is returned
;-
function mg_thumbnail_contourplot, data, valid=valid
  compile_opt strictarr
  
  maxDimSize = 100L
  minDimSize = 10L
  ; preserve aspect ration but make sure the dimensions fall in the range
  ; minDimSize...maxDimSize
  sz = size(data, /structure)
  dims = sz.dimensions[0:1]
  dims = long(dims / float(max(dims)) * maxDimSize)
  dims = dims > minDimSize < maxDimSize
  
  view = obj_new('IDLgrView')
  
  model = obj_new('IDLgrModel')
  view->add, model
  
  nLevels = 20
  contour = obj_new('IDLgrContour', data, $
                    planar=1, $ 
                    geomz=0.0, $
                    n_levels=nLevels, $
                    c_color=bytscl(bindgen(nLevels)), $
                    /fill)
  model->add, contour
  ; use most of the view: -0.9...0.9 for both x and y
  contour->getProperty, xrange=xr, yrange=yr
  xc = mg_linear_function(xr, [-1.0, 1.0])
  yc = mg_linear_function(yr, [-1.0, 1.0])
  contour->setProperty, xcoord_conv=xc, ycoord_conv=yc
  
  buffer = obj_new('IDLgrBuffer', dimensions=dims)
  buffer->draw, view
  buffer->getProperty, image_data=im
  
  obj_destroy, [buffer, view]
    
  return, im  
end
;+
; Create a volume visualization.
;
; :Returns: 
;    bytarr(3, m, n) or -1L
;
; :Params:
;    data : in, required, type=numeric array
;       date to visualize
;
; :Keywords:
;    valid : out, optional, type=boolean
;       set to a named variable to get status of visualization; if no valid 
;       visualization type could be found, -1L is returned
;-
function mg_thumbnail_volumeplot, data, valid=valid
  compile_opt strictarr
  
  maxDimSize = 100L
  minDimSize = 10L
  ; make a square display since the view dimensions don't correspond to data
  ; dimensions for a rotated volume
  dims = [maxDimSize, maxDimSize]
  
  view = obj_new('IDLgrView')
  
  model = obj_new('IDLgrModel')
  view->add, model
  
  vol = obj_new('IDLgrVolume', data)
  model->add, vol
  ; use less of the view for a 3D object: -0.7...0.7 for x, y, and z
  vol->getProperty, xrange=xr, yrange=yr, zrange=zr
  xc = mg_linear_function(xr, [-0.7, 0.7])
  yc = mg_linear_function(yr, [-0.7, 0.7])
  zc = mg_linear_function(zr, [-0.7, 0.7])
  vol->setProperty, xcoord_conv=xc, ycoord_conv=yc, zcoord_conv=zc
  
  ; who knows what orientation is best: try this one
  model->rotate, [1, 0, 0], -90
  model->rotate, [0, 1, 0], 30
  model->rotate, [1, 0, 0], 30
  
  buffer = obj_new('IDLgrBuffer', dimensions=dims)
  buffer->draw, view
  buffer->getProperty, image_data=im
  
  obj_destroy, [buffer, view]
  
  return, im   
end
;+
; Resize image to correct dimensions while preserving the aspect ratio.
;
; :Returns: 
;    bytarr(3, m, n) or -1L
;
; :Params:
;    data : in, required, type=numeric array
;       data to visualize
;
; :Keywords:
;    valid : out, optional, type=boolean
;       set to a named variable to get status of visualization; if no valid 
;       visualization type could be found, -1L is returned
;-
function mg_thumbnail_image, data, valid=valid
  compile_opt strictarr
  
  maxDimSize = 100L
  minDimSize = 10L
  
  sz = size(data, /structure)
  ind = where(sz.dimensions[0:sz.n_dimensions - 1L] le 4, count, complement=cind)
  
  ; this would be odd: quit if there is not just one dimension with size 1...4
  if (count ne 1) then begin
    valid = 0B
    return, -1L
  endif
  
  ; make the image pixel interleave
  im = transpose(data, [ind[0], cind])
  ; calculate dimensions that preserve aspect ratio, but are in the range
  ; minDimSize...maxDimSize
  origDims = [sz.dimensions[cind[0]], sz.dimensions[cind[1]]]
  dims = long(origDims / float(max(origDims)) * maxDimSize)
  
  ; only resize to smaller, never bigger
  doResize = total(dims gt origDims) eq 0
  
  dims = dims > minDimSize < maxDimSize
  
  if (doResize) then begin
    im = congrid(im, sz.dimensions[ind[0]], dims[0], dims[1])
  endif
  
  return, im
end
;+
; Dispatches data to proper helper routine to produce a simple thumbnail
; visualization of the data and returns the result as a true color image.
;
; :Returns: 
;    bytarr(3, m, n) or -1L
;
; :Params:
;    data : in, required, type=numeric array
;       data to visualize
;
; :Keywords:
;    valid : out, optional, type=boolean
;       set to a named variable to get status of visualization; if no valid 
;       visualization type could be found, -1L is returned
;-
function mg_thumbnail, data, valid=valid
  compile_opt strictarr
  
  sz = size(data, /structure)
  
  ; set to not valid for any of the following types or sizes
  valid = 0B
  
  ; invalid types/sizes
  if (sz.type eq 7) then return, -1L
  if (sz.type eq 8) then return, -1L
  if (sz.type eq 11) then return, -1L  
  
  if (sz.n_dimensions eq 0) then return, -1L
  if (sz.n_dimensions gt 3) then return, -1L
  
  if (sz.n_elements lt 3) then return, -1L
  
  valid = 1B
  
  ; valid types/sizes
  case sz.n_dimensions of
    1: return, mg_thumbnail_lineplot(data, valid=valid)
    2: return, mg_thumbnail_contourplot(data, valid=valid)
    3: begin
        ind = where(sz.dimensions[0:sz.n_dimensions - 1L] le 4, count)
        ; if not exactly one small dimension then assume volume
        if (count ne 1) then return, mg_thumbnail_volumeplot(data, valid=valid) 
        
        ; if there are small dimensions then assume an image
        return, mg_thumbnail_image(data, valid=valid)
      end
  endcase
end