################################################################################
# class definition for ClickUserSocket, that does the interface with click's
# ControlSocket. 
#
# it has 2 main methods, "read" and "write" which do the communication with 
# click's read and write handlers....
################################################################################

class ClickUserSocket
    def initialize( ctlsock, logger ) 
        ctlsock.is_a? BasicSocket or raise TypeError.new("cltsock must be of type Socket")
        @control_socket = ctlsock

        @control_socket.gets =~ /Click::ControlSocket/ or raise "This does not look like a click control socket"

        logger.is_a? Logger or raise TypeError.new("logger must if of type Logger")
        @log = logger
        @control_socket_lock = Monitor.new
    end

    def read (click_obj, click_handler ) 
    	begin
    	@log.debug "click read handler: #{click_obj}.#{click_handler}"
    	rv = nil 
    	@control_socket_lock.synchronize do 	
    		@control_socket.puts "read #{click_obj}.#{click_handler}" 
    		ret_code, ret_msg = get_return_codes
    	
    		case ret_code 
    			when 200..299:  
    				@log.debug "click read returns: #{ret_code} #{ret_msg}" 
    				rv = get_data
    			else 
    		        	@log.warn "click read returns: #{ret_code} #{ret_msg}" 
    		end
    	end
    	rv
    	rescue Errno::EPIPE
    	    return nil
    	end
    end
    
    def write (click_obj, click_handler, data) 
    	begin
        @log.debug "click write handler: #{click_obj}.#{click_handler} #{data}" 
    	ret_code = ret_msg = nil
    	@control_socket_lock.synchronize do 
    		@control_socket.puts "write #{click_obj}.#{click_handler} #{data}" 
    		ret_code, ret_msg = get_return_codes
    	end
    
    	case ret_code
    		when 200..299: 
    			@log.debug "click write returns: #{ret_code} #{ret_msg}" 
    			true
    		else 
    			@log.warn "click write returns: #{ret_code} #{ret_msg}" 
    		    	nil
    	    end	
    	    rescue Errno::EPIPE
    	        return nil
    	end
    end
private
    def get_return_codes
    	# gets.chomp 		   read from socket and discard newlines
    	#  /^(\d+) (.*)$/.match    split the string into number and rest
    	# [1,2] 		   MatchData objects contain the whole
    	# 			   matched string in [0] and all backrefs
    	# 			   in [1..-1] 
    	ret_code_s = nil
    	ret_msg = ''
    	@control_socket.each_line do |line| 
            @log.debug "return codes line: #{line} \n"
    		code_s, dash, msg = /^(\d+)(-?)\s*(.*)$/.match(line)[1..3] 
    		ret_code_s = code_s unless ret_code_s
    		ret_msg += "#{msg}#{ dash == '-' ? "\t":'' }" 
    		break unless dash == '-'
    	end
    	[ret_code_s.to_i, ret_msg] 
    end
    def get_data
	    length = /DATA (\d+)/.match(@control_socket.gets.chomp)[1].to_i
	    raise unless length
	    @control_socket.read(length) 	
    end
end


