 
 
 (defn- do-write [^Client client ^bytes v close-after-write {:keys [error-ch] :as conf}]
-  (info "client " client)
+  "Writes to the channel, this operation is non blocking and a exception listener is added to the write's ChannelFuture
+   to send any errors to the error-ch"
   (try 
-     (let [ch-f (-> client :channel-f (.channel) (.writeAndFlush v) (.addListener (exception-listener v conf)))]
+    (do 
+     (let [ch-f (-> client ^ChannelFuture (:channel-f) ^Channel (.channel) ^ChannelFuture (.writeAndFlush v) (.addListener ^ChannelFutureListener (exception-listener v conf)))]
        (if close-after-write
-         (.addListener ch-f (close-listener client conf))))
-     
+         (.addListener ch-f ^ChannelFutureListener (close-listener client conf)))))
      (catch Exception e (do 
-                          (error e e)
-                          (>!! error-ch [e v])))))
+                          (error (str "Error in do-write " e) e)
+                          (>!! error-ch [e v])
+                          ))))
 
 
 (defn start-client [host port {:keys [group read-ch error-ch write-ch handlers] :as conf 
                                  :or {group (NioEventLoopGroup.) read-ch (chan 100) error-ch (chan 100) write-ch (chan 100)}}]
+  "Start a Client instance with read-ch, write-ch and error-ch"
   (try
   (let [g (if group group (NioEventLoopGroup.))
         b (Bootstrap.)]
     (-> b (.group g)
-      (.channel NioSocketChannel)
-      (.remoteAddress (InetSocketAddress. host port))
-      (.handler (client-channel-initializer conf)))
+      ^Bootstrap (.channel NioSocketChannel)
+      ^Bootstrap (.remoteAddress (InetSocketAddress. host port))
+      ^Bootstrap (.handler ^ChannelInitializer (client-channel-initializer conf)))
     (let [ch-f (.connect b)]
       (.sync ch-f)
-      (->Client g ch-f write-ch read-ch error-ch)))
+      (->Client g ch-f write-ch read-ch error-ch (AtomicInteger.))))
   (catch Exception e (do
-                       (error e e)
-                       (>!! error-ch [e nil])))))
+                       (error (str "Error starting client " e) e)
+                       (>!! error-ch [e nil])
+                       ))))
     
 (defn read-print-ch [n ch]
   (go 
-    (while true
-      (let [c (<! ch)]
-         (info n " = " (String. c))))))
-
-(defn read-print-error [{:keys [error-ch]}]
-  (read-print-ch "error" error-ch))
+    (loop [ch1 ch]
+      (let [c (<! ch1)]
+         (if (instance? Reconnected c)
+           (do 
+             ;(info "Reconnected " (:cause c) " ch1 " ch1 " new ch " (-> c :client :read-ch))
+             (recur (-> c :client :read-ch)))
+           (do 
+             (info n " = " c)
+             (recur ch1)))))))
 
 (defn read-print-in [{:keys [read-ch]}]
   (read-print-ch "read" read-ch))
 
 
 (defn client [host port {:keys [handlers
+                                  retry-limit
                                   write-buff read-buff error-buff
                                   write-timeout read-timeout] 
-                           :or {handlers [byte-encoder]
+                           :or {handlers [byte-encoder] retry-limit 10
                                 write-buff 100 read-buff 100 error-buff 1000 reuse-client false write-timeout 1500 read-timeout 1500} }]
   (let [ write-ch (chan write-buff) 
          read-ch (chan read-buff)

  (let [group (NioEventLoopGroup.)]
	  (proxy [ChannelInitializer]
	    []
	    (initChannel [ch]
        (try 
	        ;add the last default read handler that will send all read objects to the read-ch blocking if full
          (-> ch (.pipeline) (.addLast group (into-array ChannelHandler [(client-handler conf)])))
         ;add any extra handlers e.g. for encoding or deconding
          (if handlers
            (-> ch (.pipeline) (.addLast group (into-array ChannelHandler (map #(%) handlers)))))
         (catch Exception e (do 
                              (error e e)
                              (go (>! error-ch [e nil])))))
	      ))))

(defn exception-listener [v {:keys [error-ch]}]
  (reify GenericFutureListener
    (operationComplete [this f]
       (if-let [o (.get ^Future f)]
         (if (instance? Throwable o)
           (go (>! error-ch [o v])))))))

(defn close-listener [^Client client {:keys [error-ch]}]
  "Close a client after a write operation has been completed"

  (proxy [SimpleChannelInboundHandler]
    []
    (channelActive [^ChannelHandlerContext ctx]
      ;(.writeAndFlush ctx (Unpooled/copiedBuffer "Netty Rocks1" CharsetUtil/UTF_8))
      )
    (channelRead0 [^ChannelHandlerContext ctx ^ByteBuf in]
