require 'active_record'
require 'distributed_mutex'

class MySQLMutex < DistributedMutex

  @active_locks = Hash.new

  def initialize(key, timeout = DEFAULT_TIMEOUT, exception_on_timeout = DEFAULT_EXCEPTION_ON_TIMEOUT, connection = ActiveRecord::Base.connection)
    @connection = connection
    @lock_was_free = false
    @get_sql = ActiveRecord::Base.send(:sanitize_sql_array,["SELECT IS_FREE_LOCK(?), GET_LOCK(?,?)", key, key, timeout])
    @release_sql = ActiveRecord::Base.send(:sanitize_sql_array,["SELECT RELEASE_LOCK(?)", key])
    super(key, timeout, exception_on_timeout)
  end

  def self.active_locks
    @active_locks
  end

  def self.synchronize(key, timeout = DEFAULT_TIMEOUT, exception_on_timeout = DEFAULT_TIMEOUT, con = ActiveRecord::Base.connection, &block)
    mutex = new(key, timeout, exception_on_timeout, con)
    @active_locks[key] = timeout
    mutex.synchronize(&block)
    @active_locks.delete(key)
  end

  private

  def get_lock
    is_free_lock, get_lock = @connection.select_rows(@get_sql).first
    @lock_was_free = ('1' == is_free_lock)
    '1' == get_lock
  end

  def release_lock
    if @lock_was_free
      '1' == @connection.select_value(@release_sql)
    else
      true
    end
  end

end

at_exit do
  locks = MySQLMutex.active_locks
  if locks.size > 0
    if defined?(Rails)
      Rails.logger.error("MySQLMutex: Locks still active! - #{locks.inspect}")
    else
      STDERR.puts("MySQLMutex: Locks still active! - #{locks.inspect}")
    end
  else
    if defined?(Rails)
      Rails.logger.debug("MySQLMutex: All locks released.")
    else
      STDERR.puts("MySQLMutex: All locks released.")
    end
  end
end