module Zoology; class PathCache
  class Watcher
    require 'state_machine'

    include Logging

    state_machine :state, :initial => :not_watching do
      after_transition :not_watching => :watching, :do => :set_watch
      before_transition any => :shutdown, :do => :deleted

      event :watch do
        transition :not_watching => :watching
      end

      event :not_watching do
        transition :watching => :not_watching
      end

      event :shutdown do
        transition all => :shutdown
      end

      state :shutdown do
        def call(type, data = nil)
          logger.debug "Received call request, but in shutdown so not doing anything: #{@path}"
        end
      end

      state all - [:shutdown] do
        def call(type, data = nil)
          @callback.call @path, type, data
        end
      end
    end

    def initialize(client, path, zk_call = :get, &callback)
      @client   = client
      @path     = path
      @zk_call  = zk_call
      @callback = callback

      super()
    end

    def set_watch
      watcher = @client.watcher_callback do |event|
        set_watch if event.type != Zookeeper::ZOO_SESSION_EVENT
      end
      begin
        req = @client.send(@zk_call, :path => @path, :watcher => watcher)
        if req[:rc] == Zookeeper::ZOK
          call(:update, req)
        elsif req[:rc] == Zookeeper::ZNONODE
          shutdown
        else
          not_watching
        end
      rescue Zookeeper::Exceptions::ContinuationTimeoutError
        not_watching
      end
    end

    def deleted
      call(:deleted)
    end
  end
end; end
