require 'eventmachine'
require 'twitter'

module Aucupia
  class Receiver < EM::Connection
    def initialize screen_name
      @screen_name = screen_name
    end

    def connection_completed
      send_data "CONN_TYPE:RECEIVER #{@screen_name}"
    end

    def receive_data data
      @callback.call(data)
    end

    def unbind
      EM.stop_event_loop
    end

    def iterate &block
      @callback = block
    end
  end

  class ReceiverClient
    MESSAGE_TYPES = [:retweeted_status, :direct_message, :delete, :scrub_geo]
    def initialize screen_name, arg = {}
      time = Time.new
      @launched_at = time.to_i.to_s + time.usec.to_s
      @screen_name = screen_name
      @port = arg[:port] || 42950
      @callback = {}
      @parse_json = Twitter::Response::ParseJson.new
    end

    def on_retweet &block
      @callback[:retweet] = block
    end

    def on_direct_message &block
      @callback[:direct_message] = block
    end

    def on_tweet &block
      @callback[:tweet] = block
    end

    def stream
      EM.run do
        receiver = EM.connect('localhost', @port, Receiver, @screen_name)
        receiver.iterate do |data|
          begin
            distribute @parse_json.parse(data)
          rescue
            next
          end
        end
      end
    end

    private
    def distribute attribute
      if tweet?(attribute)
        @callback[:tweet].call(Twitter::Tweet.new(attribute))
      elsif retweet?(attribute)
        @callback[:retweet].call(Twitter::Tweet.new(attribute))
      elsif direct_message?(attribute)
        direct_message = Twitter::DirectMessage.new(attribute[:direct_message])
        @callback[:direct_message].call(direct_message)
      end
    end

    def retweet? attribute
      attribute.has_key?(:retweeted_status) && !@callback[:retweet].nil?
    end

    def direct_message? attribute
      attribute.has_key?(:direct_message) && !@callback[:direct_message].nil?
    end

    def tweet? attribute
      !attribute.has_key?(:event) &&
        (attribute.keys & MESSAGE_TYPES).empty? &&
        attribute.has_key?(:id) &&
        !@callback[:tweet].nil?
    end
  end
end
