# Copyright (c) 2023 M.J.N. Corino, The Netherlands
#
# This software is released under the MIT license.
# 
# Some parts are
# Copyright 2004-2007, wxRuby development team
# released under the MIT-like wxRuby2 license

# wxRuby3 Sample Code. (converted from wxPython/Phoenix printing.py example)
###

require 'wx'

module Printing2

  FONTSIZE = 10

  # A printout class that is able to print simple text documents.
  # Does not handle page numbers or titles, and it assumes that no
  # lines are longer than what will fit within the page width.  Those
  # features are left as an exercise for the reader. ;-)
  class TextDocPrintout < Wx::PRT::Printout

    def initialize(text, title, margins)
      super(title)
      @lines = text.split("\n")
      @margins = margins
      @num_pages = 0
    end

    def has_page(page)
      page <= @num_pages
    end

    def get_page_info
      [1, @num_pages, 1, @num_pages]
    end

    def calculate_scale(dc)
      # Scale the DC such that the printout is roughly the same as
      # the screen scaling.
      ppiPrinterX, ppiPrinterY = get_ppi_printer
      ppiScreenX, ppiScreenY = get_ppi_screen
      logScale = ppiPrinterX.to_f / ppiScreenX.to_f

      # Now adjust if the real page size is reduced (such as when
      # drawing on a scaled Wx::MemoryDC in the Print Preview.)  If
      # page width == DC width then nothing changes, otherwise we
      # scale down for the DC.
      pw, ph = get_page_size_pixels
      dsz = dc.get_size
      scale = logScale * (dsz.width.to_f / pw.to_f)

      # Set the DC's scale.
      dc.set_user_scale(scale, scale)

      # Find the logical units per millimeter (for calculating the
      # margins)
      @log_units_mm = ppiPrinterX.to_f / (logScale*25.4)
    end


    def calculate_layout(dc)
      # Determine the position of the margins and the
      # page/line height
      bottomRight, topLeft = @margins
      dsz = dc.get_size
      @x1 = topLeft.x * @log_units_mm
      @y1 = topLeft.y * @log_units_mm
      @x2 = dc.device_to_logical_x_rel(dsz.width) - bottomRight.x * @log_units_mm
      @y2 = dc.device_to_logical_y_rel(dsz.height) - bottomRight.y * @log_units_mm

      # use a 1mm buffer around the inside of the box, and a few
      # pixels between each line
      @pageHeight = @y2 - @y1 - 2*@log_units_mm
      font = Wx::Font.new(FONTSIZE, Wx::FONTFAMILY_TELETYPE,
                          Wx::FONTSTYLE_NORMAL, Wx::FONTWEIGHT_NORMAL)
      dc.set_font(font)
      @lineHeight = dc.char_height
      @linesPerPage = @pageHeight.div @lineHeight
    end


    def on_prepare_printing
      # calculate the number of pages
      dc = get_dc
      calculate_scale(dc)
      calculate_layout(dc)
      @num_pages = @lines.size / @linesPerPage
      @num_pages += 1 unless (@lines.size % @linesPerPage) == 0
    end


    def on_print_page(page)
      dc = get_dc
      calculate_scale(dc)
      calculate_layout(dc)

      # draw a page outline at the margin points
      dc.set_pen(Wx::Pen.new(Wx::Colour.new("black"), 0))
      dc.set_brush(Wx::TRANSPARENT_BRUSH)
      r = Wx::Rect.new(Wx::Point.new(@x1.to_i, @y1.to_i), Wx::Point.new(@x2.to_i, @y2.to_i))
      dc.draw_rectangle(r)
      dc.set_clipping_region(r)

      # Draw the text lines for this page
      line = (page-1) * @linesPerPage
      x = (@x1 + @log_units_mm).to_i
      y = (@y1 + @log_units_mm).to_i
      while line < (page * @linesPerPage)
        dc.draw_text(@lines[line], x, y)
        y += @lineHeight
        line += 1
        break if line >= @lines.size
      end
      true
    end
  end

  class SamplePrintFrame < Wx::Frame
    def initialize
      super(nil, size: [640, 480], title: 'Print Framework Sample')
      self.icon = Wx.Icon(:sample, Wx::BITMAP_TYPE_XPM, art_path: File.join(__dir__, '..'))
      create_status_bar

      # A text widget to display the doc and let it be edited
      @tc = Wx::TextCtrl.new(self, -1, "",
                             style:Wx::TE_MULTILINE|Wx::TE_DONTWRAP)
      @tc.set_font(Wx::Font.new(FONTSIZE, Wx::FONTFAMILY_TELETYPE,
                                Wx::FONTSTYLE_NORMAL, Wx::FONTWEIGHT_NORMAL))
      filename = File.join(File.dirname(__FILE__), 'sample-text.txt')
      @tc.set_value(File.read(filename))
      @tc.evt_set_focus { |evt| on_clear_selection(evt) }
      @tc.call_after(:set_insertion_point, 0)

      # Create the menu and menubar
      menu = Wx::Menu.new
      item = menu.append(-1, "Page Setup...\tF5",
                         "Set up page margins and etc.")
      evt_menu(item, :on_page_setup)
      item = menu.append(-1, "Print Preview...\tF6",
                         "View the printout on-screen")
      evt_menu(item, :on_print_preview)
      item = menu.append(-1, "Print...\tF7", "Print the document")
      evt_menu(item, :on_print)
      menu.append_separator
      ##         item = menu.Append(-1, "Test other stuff...\tF9", "")
      ##         self.Bind(Wx::EVT_MENU, self.OnPrintTest, item)
      ##         menu.AppendSeparator()

      item = menu.append(Wx::ID_ABOUT, "About", "About this application")
      evt_menu(item, :on_about)
      item = menu.append(Wx::ID_EXIT, "E&xit\tCtrl-Q", "Close this application")
      evt_menu(item, :on_exit)

      menubar = Wx::MenuBar.new
      menubar.append(menu, "&File")
      self.menu_bar = menubar

      # initialize the print data and set some default values
      @pdata = Wx::PrintData.new
      @pdata.set_paper_id(Wx::PAPER_LETTER)
      @pdata.set_orientation(Wx::PORTRAIT)
      @margins = [Wx::Point.new(15,15), Wx::Point.new(15,15)]
    end

    def on_exit(evt)
      self.close
    end

    def on_about(evt)
      msg = <<~__STR
        Print framework sample application
  
        Using wxRuby #{Wx::version()}
      __STR

      Wx::message_box(msg,'About')
    end

    def on_clear_selection(evt)
      evt.skip
      @tc.call_after(:set_insertion_point, @tc.insertion_point)
    end

    def on_page_setup(evt)
      data = Wx::PageSetupDialogData.new
      data.set_print_data(@pdata)

      data.set_default_min_margins(true)
      data.set_margin_top_left(@margins.first)
      data.set_margin_bottom_right(@margins.last)

      Wx::PRT.PageSetupDialog(self, data) do |dlg|
        data = dlg.get_page_setup_data if dlg.show_modal == Wx::ID_OK
        @pdata = data.get_print_data
        @pdata.set_paper_id(data.paper_id)
        #print_("paperID %r, paperSize %r" % (self.pdata.GetPaperId(), self.pdata.GetPaperSize()))
        @margins = [data.margin_top_left,
                    data.margin_bottom_right]
      end
    end

    def on_print_preview(evt)
      data = Wx::PrintDialogData.new(@pdata)
      text = @tc.value
      printout1 = TextDocPrintout.new(text, "title", @margins)
      printout2 = TextDocPrintout.new(text, "title", @margins)
      preview = Wx::PrintPreview.new(printout1, printout2, data)
      unless preview
        Wx::message_box("Unable to create PrintPreview!", "Error")
      else
        # create the preview frame such that it overlays the app frame
        frame = Wx::PreviewFrame.new(preview, self, "Print Preview",
                                     self.position,
                                     self.size)
        frame.init
        frame.show
      end
    end

    def on_print(evt)
      data = Wx::PrintDialogData.new(@pdata)
      printer = Wx::Printer.new(data)
      text = @tc.value
      printout = TextDocPrintout.new(text, "title", @margins)
      useSetupDialog = true
      if !printer.print(self, printout, useSetupDialog) && Wx::Printer.get_last_error == Wx::PRT::PRINTER_ERROR
        Wx::message_box(
           "There was a problem printing.\n" +
           "Perhaps your current printer is not set correctly?",
    'Printing Error', Wx::OK)
      else
        data = printer.print_dialog_data
      end
      @pdata = data.print_data
    end
  end

end

module Printing2Sample

  include WxRuby::Sample if defined? WxRuby::Sample

  def self.describe
    { file: __FILE__,
      summary: 'Another wxRuby Printing example.',
      description: 'Another wxRuby example showcasing printing framework.' }
  end

  def self.activate
    frame = Printing2::SamplePrintFrame.new
    frame.show
    frame
  end

  if $0 == __FILE__
    Wx::App.run { Printing2Sample.activate }
  end

end
