require 'delegate'
require 'singleton'

module Squealer
  class Target

    def self.current
      Queue.instance.current
    end

    def initialize(database_connection, table_name, row_id, &block)
      throw "Block must be given to target (otherwise, there's no work to do)" unless block_given?

      @table_name = table_name.to_s
      @row_id = row_id
      @column_names = []
      @column_values = []
      @sql = ''

      target(&block)
    end

    def sql
      @sql
    end

    def assign(column_name, &block)
      @column_names << column_name
      @column_values << block.call
    end


    private

    def target(&block)
      Queue.instance.push(self)

      yield self

      @sql = "INSERT #{@table_name}"
      @sql << " (#{pk_name}#{column_names}) VALUES (?#{column_value_markers})"
      @sql << " ON DUPLICATE KEY UPDATE #{column_markers}"

      execute_sql(@sql)

      Queue.instance.pop
    end

    def self.targets
      @@targets
    end

    def targets
      @@targets
    end

    def execute_sql(sql)
      statement = Database.instance.export.prepare(sql)
      values = [*column_values] + [*column_values]  #array expando
      statement.send(:execute, @row_id, *values) #expand values into distinct arguments
    end

    def pk_name
      'id'
    end

    def column_names
      return if @column_names.size == 0
      ",#{@column_names.join(',')}"
    end

    def column_values
      @column_values
    end

    def column_value_markers
      return if @column_names.size == 0
      result = ""
      @column_names.size.times { result << ',?'}
      result
    end

    def column_markers
      return if @column_names.size == 0
      result = ""
      @column_names.each {|k| result << "#{k}=?," }
      result.chop
    end

    class Queue < DelegateClass(Array)
      include Singleton

      def current
        last
      end

      protected

      def initialize
        super([])
      end

    end

  end
end