package com.github.lock.free.queue;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;

/**
 * Daneel Yaitskov
 */
public class LockFreeQueue<T> {

    private static final Logger logger = LoggerFactory.getLogger(LockFreeQueue.class);

    // never empty
    private final AtomicLong length = new AtomicLong(1L);
    private final Node stub = new Node(null);
    private final AtomicReference<Node<T>> head = new AtomicReference<Node<T>>(stub);
    private final AtomicReference<Node<T>> tail = new AtomicReference<Node<T>>(stub);

    public void add(T x) {
//        logger.info("put {}", x);
        addNode(new Node<T>(x));
        length.incrementAndGet();
    }

    public T takeOrNull() {
        while (true) {
            long l = length.get();
            if (l == 1) {
//                logger.info("null cause length is 1");
                return null;
            } else if (l < 1) {
                throw new IllegalStateException("bad length " + l);
            }
            if (length.compareAndSet(l, l - 1)) {
//                logger.info("changed length is {}", l);
                break;
            } else {
//                logger.info("failed change length");
            }
        }
        while (true) {
            Node<T> r = head.get();
//            logger.info("head {}, next", r);
            if (r == null) {
                throw new IllegalStateException("null head");
            }
            if (r.next.get() == null) {
                length.incrementAndGet();
                return null;
            }
            if (head.compareAndSet(r, r.next.get())) {
                if (r == stub) {
//                    logger.info("took stub retry");
                    stub.next.set(null);
                    addNode(stub);
                } else {
//                    logger.info("took {}", r.ref);
                    return r.ref;
                }
            } else {
//                logger.info("failed take head");
            }
        }
    }

    private void addNode(Node<T> n) {
        Node<T> t;
        while (true) {
            t = tail.get();
            if (tail.compareAndSet(t, n)) {
//                logger.info("put");
                break;
            } else {
//                logger.info("failed put");
            }
        }
        if (t.next.compareAndSet(null, n)) {
            return;
        }
        throw new IllegalStateException("bad tail next");
    }
}
@@ -35,66 +35,8 @@
 ;%0A%0A%0A
-import org.slf4j.Logger;%0Aimport org.slf4j.LoggerFactory;%0A%0A
 impo
@@ -195,96 +195,8 @@
  %7B%0A%0A
-    private static final Logger logger = LoggerFactory.getLogger(LockFreeQueue.class);%0A%0A
     
@@ -518,44 +518,8 @@
 ) %7B%0A
-//        logger.info(%22put %7B%7D%22, x);%0A
     
@@ -704,413 +704,122 @@
 ) %7B%0A
-//                logger.info(%22null cause length is 1%22);%0A                return null;%0A            %7D else if (l %3C 1) %7B%0A                throw new IllegalStateException(%22bad length %22 + l);%0A            %7D%0A            if (length.compareAndSet(l, l - 1)) %7B%0A//                logger.info(%22changed length is %7B%7D%22, l);%0A                break;%0A            %7D else %7B%0A//                logger.info(%22failed change length%22)
+                return null;%0A            %7D%0A            if (length.compareAndSet(l, l - 1)) %7B%0A                break
 ;%0A  
@@ -903,55 +903,8 @@
 ();%0A
-//            logger.info(%22head %7B%7D, next%22, r);%0A
     
@@ -1221,62 +1221,8 @@
 ) %7B%0A
-//                    logger.info(%22took stub retry%22);%0A
     
@@ -1322,184 +1322,59 @@
 e %7B%0A
-//                    logger.info(%22took %7B%7D%22, r.ref);%0A                    return r.ref;%0A                %7D%0A            %7D else %7B%0A//                logger.info(%22failed take head%22);
+                    return r.ref;%0A                %7D
 %0A   
@@ -1557,133 +1557,29 @@
 ) %7B%0A
-//                logger.info(%22put%22);%0A                break;%0A            %7D else %7B%0A//                logger.info(%22failed put%22)
+                break
 ;%0A  

clean code