require "numru/gave/draw"
require "vtk/Gtk"

GAVE_GTK_VERSION = 2

Gtk.init
Gtk::GL.init

class GtkGLExtVTKRenderWindow
  def OnKeyPress(wid, event=nil)
    if (event.keyval == Gdk::Keyval.from_name("q")) ||
        (event.keyval == Gdk::Keyval.from_name("Q"))
      self.parent.hide
    elsif (event.keyval == Gdk::Keyval.from_name('r')) ||
        (event.keyval == Gdk::Keyval.from_name('R'))
      self.Reset
      return true
    elsif (event.keyval == Gdk::Keyval.from_name('w')) ||
        (event.keyval == Gdk::Keyval.from_name('W'))
      self.Wireframe
      return true
    elsif (event.keyval == Gdk::Keyval.from_name('s')) ||
        (event.keyval == Gdk::Keyval.from_name('S'))
      self.Surface
      return true
    elsif (event.keyval == Gdk::Keyval.from_name('p')) ||
        (event.keyval == Gdk::Keyval.from_name('P'))
      m = pointer
      self.PickActor(m[0], m[1])
      return true
    else
      return false
    end
  end
end

class Draw
  alias :_initialize :initialize
  def initialize(n)
    _initialize(n)
  end
  alias :_clear :clear
  def clear
    _clear
  end
  def open_graphics
    @draw_area = GtkGLExtVTKRenderWindow.new
    @draw_area.set_size_request(@width,@height)
    @ren = Vtk::Renderer.new
    @draw_area.GetRenderWindow.AddRenderer(@ren)
    @window = Gtk::Window.new(Gtk::Window::TOPLEVEL).set_resizable(true)
    @window.signal_connect("delete-event"){|w,p| w.hide; true}
    @window.signal_connect("destroy"){exit}
    @window.add(@draw_area)
    names = @gphys.funcs[0]
    @window.set_title("#{@winno}: #{names[2]}@#{names[0]}")
  end


  private
  def draw_1d(title,xtitle,ytitle)
    @fig.figure_set("title = \"#{title}\"", __FILE__,__LINE__)
    @fig.figure_set("xtitle = \"#{xtitle}\"", __FILE__,__LINE__)
    @fig.figure_set("ytitle = \"#{ytitle}\"", __FILE__,__LINE__)
    @fig.figure_set('x = gphys0.coord(0).val', __FILE__,__LINE__)
    @fig.figure_set('grid = Vtk::RectilinearGrid.new', __FILE__,__LINE__)
    @fig.figure_set('length = gphys0.length', __FILE__,__LINE__)
    @fig.figure_set('grid.SetDimensions(length,1,1)', __FILE__,__LINE__)
    @fig.figure_set('grid.SetXCoordinates(x.to_va)', __FILE__,__LINE__)
    @fig.figure_set('data = gphys0.val', __FILE__,__LINE__)
    @fig.figure_set('data = data.get_array! if NArrayMiss===data', __FILE__,__LINE__)
    @fig.figure_set('grid.GetPointData.SetScalars(data.to_va)', __FILE__,__LINE__)
    @fig.figure_set('xyplot = Vtk::XYPlotActor.new', __FILE__,__LINE__)
    @fig.figure_set('xyplot.AddInput(grid)', __FILE__,__LINE__)
    @fig.figure_set('xyplot.GetProperty.SetColor(0,0,0)', __FILE__,__LINE__)
    @fig.figure_set('xyplot.SetTitle(title)', __FILE__,__LINE__)
    @fig.figure_set('xyplot.SetXTitle(xtitle)', __FILE__,__LINE__)
    @fig.figure_set('xyplot.SetYTitle(ytitle)', __FILE__,__LINE__)
#    @fig.figure_set('xyplot.PlotPointsOn', __FILE__,__LINE__)
    @fig.figure_set('tprop = xyplot.GetTitleTextProperty', __FILE__,__LINE__)
    @fig.figure_set('tprop.SetColor(*xyplot.GetProperty.GetColor)', __FILE__,__LINE__)
    @fig.figure_set('xyplot.SetAxisTitleTextProperty(tprop)', __FILE__,__LINE__)
    @fig.figure_set('xyplot.SetAxisLabelTextProperty(tprop)', __FILE__,__LINE__)
    @fig.figure_set('ren.AddActor2D(xyplot)', __FILE__,__LINE__)
    @fig.figure_set('ren.SetBackground(1, 1, 1)', __FILE__,__LINE__)
  end

  private
  def draw_2d(title,type)
    @fig.figure_set('x = gphys0.coord(0).val', __FILE__,__LINE__)
    @fig.figure_set('xmin = x.min', __FILE__,__LINE__)
    @fig.figure_set('xmax = x.max', __FILE__,__LINE__)
    @fig.figure_set('x = x/(xmax-xmin)', __FILE__,__LINE__)
    @fig.figure_set('y = gphys0.coord(1).val', __FILE__,__LINE__)
    @fig.figure_set('ymin = y.min', __FILE__,__LINE__)
    @fig.figure_set('ymax = y.max', __FILE__,__LINE__)
    @fig.figure_set('y = y/(ymax-ymin)', __FILE__,__LINE__)
#    @fig.figure_set('yfact = (xmax-xmin)/(ymax-ymin)', __FILE__,__LINE__)
    @fig.figure_set('grid = Vtk::RectilinearGrid.new', __FILE__,__LINE__)
    @fig.figure_set('shape = gphys0.shape', __FILE__,__LINE__)
    @fig.figure_set('grid.SetDimensions(shape[0],shape[1],1)', __FILE__,__LINE__)
    @fig.figure_set('grid.SetXCoordinates(x.to_va)', __FILE__,__LINE__)
    @fig.figure_set('grid.SetYCoordinates(y.to_va)', __FILE__,__LINE__)
    @fig.figure_set('data = gphys0.val', __FILE__,__LINE__)
    @fig.figure_set('data = data.get_array! if NArrayMiss===data', __FILE__,__LINE__)
    @fig.figure_set('grid.GetPointData.SetScalars(data.reshape!(data.length).to_va)', __FILE__,__LINE__)
    @fig.figure_set('outline = Vtk::OutlineFilter.new', __FILE__,__LINE__)
    @fig.figure_set('outline.SetInput(grid)', __FILE__,__LINE__)
    @fig.figure_set('outlineMapper = Vtk::PolyDataMapper.new', __FILE__,__LINE__)
    @fig.figure_set('outlineMapper.SetInput(outline.GetOutput)', __FILE__,__LINE__)
    @fig.figure_set('outlineActor = Vtk::Actor.new', __FILE__,__LINE__)
    @fig.figure_set('outlineActor.SetMapper(outlineMapper)', __FILE__,__LINE__)
#    @fig.figure_set('outlineActor.SetScale(1,yfact,1)', __FILE__,__LINE__)
    @fig.figure_set('outlineActor.GetProperty.SetColor(0,0,0)', __FILE__,__LINE__)
    @fig.figure_set('contour = Vtk::ContourFilter.new', __FILE__,__LINE__)
    @fig.figure_set('contour.SetInput(grid)', __FILE__,__LINE__)
    @fig.figure_set('contour.GenerateValues(40, data.min, data.max)', __FILE__,__LINE__)
    @fig.figure_set('mapper = Vtk::PolyDataMapper.new', __FILE__,__LINE__)
    @fig.figure_set('mapper.SetInput(contour.GetOutput)', __FILE__,__LINE__)
    @fig.figure_set('mapper.SetScalarRange(data.min,data.max)', __FILE__,__LINE__)
    @fig.figure_set('actor = Vtk::Actor.new', __FILE__,__LINE__)
    @fig.figure_set('actor.SetMapper(mapper)', __FILE__,__LINE__)
#    @fig.figure_set('actor.SetScale(1,yfact,1)', __FILE__,__LINE__)
    @fig.figure_set('ren.AddActor(actor)', __FILE__,__LINE__)
    @fig.figure_set('ren.AddActor(outlineActor)', __FILE__,__LINE__)
    @fig.figure_set('ren.SetBackground(1, 1, 1)', __FILE__,__LINE__)
#    @fig.figure_set('tprop = Vtk::TextProperty.new', __FILE__,__LINE__)
#    @fig.figure_set('tprop.SetColor(0,0,0)', __FILE__,__LINE__)
    @fig.figure_set('axes = Vtk::CubeAxesActor2D.new', __FILE__,__LINE__)
    @fig.figure_set('axes.SetCornerOffset(0)', __FILE__,__LINE__)
    @fig.figure_set('axes.SetInput(grid)', __FILE__,__LINE__)
    @fig.figure_set('axes.SetCamera(ren.GetActiveCamera)', __FILE__,__LINE__)
    @fig.figure_set('axes.SetFontFactor(1.2)', __FILE__,__LINE__)
#    @fig.figure_set('axes.SetAxisTitleTextProperty(tprop)', __FILE__,__LINE__)
#    @fig.figure_set('axes.SetAxisLabelTextProperty(tprop)', __FILE__,__LINE__)
    @fig.figure_set('axes.GetProperty.SetColor(0,0,0)', __FILE__,__LINE__)
    @fig.figure_set('axes.UseRangesOn', __FILE__,__LINE__)
    @fig.figure_set('axes.SetRanges(xmin,xmax,ymin,ymax,0,0)', __FILE__,__LINE__)
    @fig.figure_set('ren.AddProp(axes)', __FILE__,__LINE__)
  end

  def draw_3d(title)
    @fig.figure_set('x = gphys0.coord(0).val', __FILE__,__LINE__)
    @fig.figure_set('xmin = x.min', __FILE__,__LINE__)
    @fig.figure_set('xmax = x.max', __FILE__,__LINE__)
    @fig.figure_set('x = x/(xmax-xmin)', __FILE__,__LINE__)
    @fig.figure_set('y = gphys0.coord(1).val', __FILE__,__LINE__)
    @fig.figure_set('ymin = y.min', __FILE__,__LINE__)
    @fig.figure_set('ymax = y.max', __FILE__,__LINE__)
    @fig.figure_set('y = y/(ymax-ymin)', __FILE__,__LINE__)
    @fig.figure_set('z = gphys0.coord(2).val', __FILE__,__LINE__)
    @fig.figure_set('zmin = z.min', __FILE__,__LINE__)
    @fig.figure_set('zmax = z.max', __FILE__,__LINE__)
    @fig.figure_set('z = z/(zmax-zmin)', __FILE__,__LINE__)
#    @fig.figure_set('yfact = (xmax-xmin)/(ymax-ymin)', __FILE__,__LINE__)
#    @fig.figure_set('zfact = (xmax-xmin)/(zmax-zmin)', __FILE__,__LINE__)
    @fig.figure_set('grid = Vtk::RectilinearGrid.new', __FILE__,__LINE__)
    @fig.figure_set('shape = gphys0.shape', __FILE__,__LINE__)
    @fig.figure_set('grid.SetDimensions(*shape)', __FILE__,__LINE__)
    @fig.figure_set('grid.SetXCoordinates(x.to_va)', __FILE__,__LINE__)
    @fig.figure_set('grid.SetYCoordinates(y.to_va)', __FILE__,__LINE__)
    @fig.figure_set('grid.SetZCoordinates(z.to_va)', __FILE__,__LINE__)
    
    @fig.figure_set('data = gphys0.val', __FILE__,__LINE__)
    @fig.figure_set('data = data.get_array! if NArrayMiss===data', __FILE__,__LINE__)
    @fig.figure_set('data = (data-data.min)/(data.max-data.min)', __FILE__,__LINE__)
    @fig.figure_set('grid.GetPointData.SetScalars(data.reshape!(data.length).to_va)', __FILE__,__LINE__)
    @fig.figure_set('outline = Vtk::OutlineFilter.new', __FILE__,__LINE__)
    @fig.figure_set('outline.SetInput(grid)', __FILE__,__LINE__)
    @fig.figure_set('outlineMapper = Vtk::PolyDataMapper.new', __FILE__,__LINE__)
    @fig.figure_set('outlineMapper.SetInput(outline.GetOutput)', __FILE__,__LINE__)
    @fig.figure_set('outlineActor = Vtk::Actor.new', __FILE__,__LINE__)
    @fig.figure_set('outlineActor.SetMapper(outlineMapper)', __FILE__,__LINE__)
#    @fig.figure_set('outlineActor.SetScale(1,yfact,zfact)', __FILE__,__LINE__)
#    @fig.figure_set('outlineActor.GetProperty.SetColor(0,0,0)', __FILE__,__LINE__)
    @fig.figure_set('surface = Vtk::ContourFilter.new', __FILE__,__LINE__)
    @fig.figure_set('surface.SetInput(grid)', __FILE__,__LINE__)
    if @surface
      @fig.figure_set("surface.SetValue(0,#{@surface})", __FILE__,__LINE__)
    else
      @fig.figure_set('surface.SetValue(0,0.5)', __FILE__,__LINE__)
    end
    @fig.figure_set('mapper = Vtk::PolyDataMapper.new', __FILE__,__LINE__)
    @fig.figure_set('mapper.SetInput(surface.GetOutput)', __FILE__,__LINE__)
    @fig.figure_set('mapper.SetScalarModeToUsePointFieldData', __FILE__,__LINE__)
    @fig.figure_set('actor = Vtk::Actor.new', __FILE__,__LINE__)
    @fig.figure_set('actor.SetMapper(mapper)', __FILE__,__LINE__)
    @fig.figure_set('actor.GetProperty.SetOpacity(0.5)', __FILE__,__LINE__)
#    @fig.figure_set('actor.SetScale(1,yfact,zfact)', __FILE__,__LINE__)
    @fig.figure_set('ren.AddActor(outlineActor)', __FILE__,__LINE__)
    @fig.figure_set('ren.AddActor(actor)', __FILE__,__LINE__)
    @fig.figure_set('ren.SetBackground(0.1, 0.2, 0.4)', __FILE__,__LINE__)
#    @fig.figure_set('tprop = Vtk::TextProperty.new', __FILE__,__LINE__)
#    @fig.figure_set('tprop.SetColor(1,1,1)', __FILE__,__LINE__)
    @fig.figure_set('axes = Vtk::CubeAxesActor2D.new', __FILE__,__LINE__)
    @fig.figure_set('axes.SetCornerOffset(0)', __FILE__,__LINE__)
    @fig.figure_set('axes.SetInput(grid)', __FILE__,__LINE__)
    @fig.figure_set('axes.SetCamera(ren.GetActiveCamera)', __FILE__,__LINE__)
    @fig.figure_set('axes.SetFontFactor(1.2)', __FILE__,__LINE__)
#    @fig.figure_set('axes.SetAxisTitleTextProperty(tprop)', __FILE__,__LINE__)
#    @fig.figure_set('axes.SetAxisLabelTextProperty(tprop)', __FILE__,__LINE__)
    @fig.figure_set('axes.UseRangesOn', __FILE__,__LINE__)
    @fig.figure_set('axes.SetRanges(xmin,xmax,ymin,ymax,zmin,zmax)', __FILE__,__LINE__)
    @fig.figure_set('ren.AddProp(axes)', __FILE__,__LINE__)
  end

  private
  def draw(drawing_area)
    @fig.figure_clear
    acts = @ren.GetActors
    for i in 0...acts.GetNumberOfItems
      act = Vtk::Actor.SafeDownCast(acts.GetItemAsObject(0))
      @ren.RemoveActor(act)
    end

    if @type == LINE
      draw_1d(@title,@x_title,@y_title)
    elsif @type == CONTOUR
      draw_2d(@title,@type)
    elsif @type == SURFACE
      draw_3d(@title)
    end

    root = @window
    gphys0 = @gphys
    renWin = @draw_area
    ren = @ren
    codes = @fig.draw_eval
    for j in 0...codes.length
      eval *codes[j]
    end
    @draw_area.Render
    @window.show_all
  end

  private
  class Fig
    attr_reader :head, :var, :open, :close
    def initialize
      @var = ""
      @figure = Array.new
      @head = <<"END"
require "numru/gphys"
require "vtk"

include NumRu
END
      @open = <<"END"
renWin = Vtk::RenderWindow.new
ren = Vtk::Renderer.new
renWin.AddRenderer(ren)

END
      @close = <<"END"
iren = Vtk::RenderWindowInteractor.new
iren.SetRenderWindow(renWin)
iren.Initialize
renWin.Render
iren.Start
END
    end
    def var_set(funcs,mapping,n)
      @var = "" if n==0
      filename, filetype, varname = funcs[0]
      if filename.length==1
        @var += "filename = \"#{filename[0]}\"\n"
      else
        @var += "filename = [\"#{filename.join('", "')}\"]\n"
      end
      @var += "varname = \"#{varname}\"\n"


      if filetype.nil?
        @var += "gphys#{n} = GPhys::IO.open(filename,varname)\n"
      elsif filetype=="druby"
        @var += "require \"drb/drb\"\n"
        @var += "DRb.start_service\n"
        @var += "class NArray\n"
        @var += "  def self._load(o) to_na(*Marshal::load(o)).ntoh end\n"
        @var += "end\n"
        @var += "ary = filename.split('/')\n"
        @var += "host = 'druby://'+ary[2]\n"
        @var += "path = ary[3..-1].join('/')\n"
        @var += "tree = DRbObject.new(nil,host)\n"
        @var += "gphys#{n} = tree.data(path)\n"
      else
        raise "filetype is invalid"
      end

      if funcs.length!=0
	funcs[1..-1].each{|func|
	  @var += "gphys#{n} = gphys#{n}.cut(#{func[2].join(",")})\n"
	  @var += "gphys#{n} = gphys#{n}.#{func[0]}(#{func[1]})\n"
	}
      end
      str = mapping.collect{|a|
        if NArray===a
          "NArray[#{a.to_a.join(",")}]"
        else
          a
        end
        }.join(",")
      @var += "gphys#{n} = gphys#{n}[#{str}]\n"
    end

    def title_set(xt,xu,yt,yu, file,line)
    end

    def figure_clear
      @figure.clear
    end
    def figure_set(str,file,line)
      @figure.push([str,file,line])
    end
    def draw_parm
    end
    def draw
      @figure.collect{|c| c[0]}.join("\n")
    end
    def draw_eval
      codes = Array.new
      @figure.each{|c| codes.push [c[0], nil, c[1], c[2]]}
      codes
    end
  end
end
