require 'celluloid'
require 'io/console'
require 'pty'
require 'socket'
require 'terminfo'

module Hokaido
  class Broadcast
    class Connection
      include Celluloid

      def initialize(host, port)
        @socket = TCPSocket.new(host, port)

        @socket.puts 'broadcast'
      end

      def send(data)
        @socket.write data
      end
    end

    class OutputHandler
      include Celluloid

      def initialize(ptyout, connection)
        @ptyout, @connection = ptyout, connection

        async.run
      end

      def run
        while chunk = @ptyout.readpartial(4096)
          $stdout.write chunk
          @connection.async.send chunk
        end
      rescue EOFError, Errno::EIO
        # do nothing
      ensure
        terminate
      end
    end

    class InputHandler
      include Celluloid

      def initialize(ptyin)
        @ptyin = ptyin

        async.run
      end

      def run
        while char = $stdin.getch
          @ptyin.putc char
        end

        terminate
      end
    end

    class Command
      include Celluloid

      def initialize(command, host, port)
        ptyout, ptyin, pid = PTY.getpty(command)
        connection         = Connection.new_link(host, port)

        # FIXME: adjust on SIGWINCH
        adjust_screen_size ptyin

        OutputHandler.new_link ptyout, connection
        InputHandler.new_link ptyin

        async.wait_for_exit pid
      end

      def wait_for_exit(pid)
        Process.waitpid pid

        terminate
      end

      private

      def adjust_screen_size(ptyin)
        TermInfo.tiocswinsz ptyin, *TermInfo.screen_size
      end
    end
  end
end
