#!/usr/bin/env ruby

# INFO:
#   - ruby interpreter is required for running such script
#   - script was tested only on MacOSX, and is still an experiment
#   - add executable rights to the script: chmod +x u64printing
#   - enable virtual printer in Software IEC Settings:
#        - IEC Drive and printer: Enabled
#        - Printer output file: /Usb1/printer
#        - Printer output type ASCII
# USAGE:
#   - execute script in terminal: ./u64printing --uri=ftp://192.168.1.52/Usb1/printer.txt
#   - print something on c64 printer (device ID 4)
#   - press F5 -> Printer -> Flush/Eject
#

require 'net/ftp'
require 'tempfile'
require 'optparse'

default_uri = URI("ftp://192.168.1.52/Usb1/printer.txt")
options = {
  screen: false,
  ftp_server: default_uri.host,
  ftp_directory: "/#{File.dirname(default_uri.path)}/",
  ftp_filename: File.basename(default_uri.path)
}
OptionParser.new do |opts|
  opts.banner = "Usage: u64printing [options]"
  opts.on("-s", "--screen", "Print on screen") do |v|
    options[:screen] = true
  end

  opts.on("-uURI", "--uri=URI", "uri, example: --uri=#{default_uri}") do |uri_value|
    uri = URI(uri_value)
    options[:ftp_server] = uri.host
    options[:ftp_directory] = "/#{File.dirname(uri.path)}/"
    options[:ftp_filename] = File.basename(uri.path)
  end
end.parse!

def every_n_seconds(n)
  loop do
    before = Time.now
    yield
    interval = n - (Time.now-before)
    sleep(interval) if interval > 0
  end
end
previous = nil

ftp = Net::FTP.new()
ftp.passive = true
puts "Connecting to: #{options[:ftp_server]}"
puts "Looking for #{options[:ftp_filename]} in #{options[:ftp_directory]}:"
ftp.connect(options[:ftp_server])

at_exit do
  ftp.close
end

trap('INT') do
  puts "\nQuiting... done"
  exit
end

begin
  every_n_seconds(1) do
    Tempfile.create('printer-out') do |printer_out|
      ftp.login
      ftp.chdir(options[:ftp_directory])
      if ftp.nlst.include?(options[:ftp_filename])
        puts "found."
        ftp.getbinaryfile(options[:ftp_filename], printer_out)
        recent = File.read(printer_out.path)
        if options[:screen]
          puts "Printing:"
          puts File.read(printer_out.path)
        else
          puts `lpr #{printer_out.path}`
        end
        ftp.delete(options[:ftp_filename])
      else
        print "."
      end
    rescue => ex
      puts "Error: #{ex.message} #{ex.class}"
    end
  end
ensure
  ftp.close
end