require 'getoptlong'

class LCD
   attr_accessor( :size, :spacing )

   #
   # This hash is used to define the segment display for the
   # given digit. Each entry in the array is associated with
   # the following states:
   #
   #    HORIZONTAL
   #    VERTICAL
   #     HORIZONTAL
   #     VERTICAL
   #    HORIZONTAL
   #    DONE
   #      # The HORIZONTAL state produces a single horizontal line. There
   # are two types:
   #
   #     0 - skip, no line necessary, just space fill
   #    1 - line required of given size
   #
   # The VERTICAL state produces a either a single right side line,
   # a single left side line or a both lines.
   #
   #     0 - skip, no line necessary, just space fill
   #    1 - single right side line
   #    2 - single left side line
   #    3 - both lines
   #
   # The DONE state terminates the state machine. This is not needed
   # as part of the data array.
   #
   @@lcdDisplayData = {
       "0" => [ 1, 3, 0, 3, 1 ],
       "1" => [ 0, 1, 0, 1, 0 ],
       "2" => [ 1, 1, 1, 2, 1 ],
       "3" => [ 1, 1, 1, 1, 1 ],
       "4" => [ 0, 3, 1, 1, 0 ],
       "5" => [ 1, 2, 1, 1, 1 ],
       "6" => [ 1, 2, 1, 3, 1 ],
       "7" => [ 1, 1, 0, 1, 0 ],
       "8" => [ 1, 3, 1, 3, 1 ],
       "9" => [ 1, 3, 1, 1, 1 ]
   }

   @@lcdStates = [
       "HORIZONTAL",
       "VERTICAL",
       "HORIZONTAL",
       "VERTICAL",
       "HORIZONTAL",
       "DONE"
   ]

   def initialize( size=1, spacing=1 )
       @size = size
       @spacing = spacing
   end

   def display( digits )
       states = @@lcdStates.reverse
       0.upto(@@lcdStates.length) do |i|
           case states.pop
           when "HORIZONTAL"
               line = ""
               digits.each_byte do |b|
                   line += horizontal_segment( @@lcdDisplayData[b.chr][i] )
               end
               print line + "\n"
           when "VERTICAL"
               1.upto(@size) do |j|
                   line = ""
                   digits.each_byte do |b|
                       line += vertical_segment( @@lcdDisplayData[b.chr][i] )
                   end
                   print line + "\n"
               end
           when "DONE"
               break
           end
       end
   end

   def horizontal_segment( type )
       case type
       when 1
           return " " + ("-" * @size) + " " + (" " * @spacing)
       else
           return " " + (" " * @size) + " " + (" " * @spacing)
       end
   end

   def vertical_segment( type )
       case type
       when 1
           return " " + (" " * @size) + "|" + (" " * @spacing)
       when 2
           return "|" + (" " * @size) + " " + (" " * @spacing)
       when 3
           return "|" + (" " * @size) + "|" + (" " * @spacing)
       else
           return " " + (" " * @size) + " " + (" " * @spacing)
       end
   end
end

##### Main

opts = GetoptLong.new(
   [ "--size", "-s", GetoptLong::REQUIRED_ARGUMENT ],
   [ "--spacing", "--sp", "-p", GetoptLong::REQUIRED_ARGUMENT ]
)

lcd = LCD.new

opts.each do |opt, arg|
   case opt
   when "--size"
       lcd.size = arg.to_i

   when "--spacing"
       lcd.spacing = arg.to_i
   end
end

lcd.display( ARGV.shift )
