module EventMachine
  module Protocols
    class ClientConnection < Connection
      def self.start(host, port)
        EM.start_server(host, port, self)
        puts "Listening on #{host}:#{port}"
      end

      def post_init
        @buffer = []
        @tries = 0
        ProxyMachine.incr
      end

      def receive_data(data)
        if !@server_side
          @buffer << data
          ensure_server_side_connection
        else @server_side
          # p data
          @server_side.send_data(data)
        end
      rescue => e
        close_connection
        puts "#{e.class} - #{e.message}"
      end

      def ensure_server_side_connection
        @timer.cancel if @timer
        unless @server_side
          commands = ProxyMachine.router.call(@buffer.join)
          close_connection unless commands.instance_of?(Hash)
          if remote = commands[:remote]
            m, host, port = *remote.match(/^(.+):(.+)$/)
            if try_server_connect(host, port.to_i)
              if data = commands[:data]
                @buffer = [data]
              end
              send_and_clear_buffer
            end
          elsif close = commands[:close]
            if close == true
              close_connection
            else
              send_data(close)
              close_connection_after_writing
            end
          elsif commands[:noop]
            # do nothing
          else
            close_connection
          end
        end
      end

      def try_server_connect(host, port)
        @server_side = ServerConnection.request(host, port, self)
        if @tries > 0
          puts "Successful connection."
        end
        true
      rescue => e
        if @tries < 10
          @tries += 1
          puts "Failed on server connect attempt #{@tries}. Trying again..."
          @timer.cancel if @timer
          @timer = EventMachine::Timer.new(0.1) do
            self.ensure_server_side_connection
          end
        else
          puts "Failed after ten connection attempts."
        end
        false
      end

      def send_and_clear_buffer
        if !@buffer.empty?
          @buffer.each do |x|
            @server_side.send_data(x)
          end
          @buffer = []
        end
      end

      def unbind
        @server_side.close_connection_after_writing if @server_side
        ProxyMachine.decr
      end
    end
  end
end