/**
 * Copyright 2008-2009. Chongqing Communications Industry Services Co.,Ltd Information Technology Branch. All rights reserved. <a>http://www.crunii.com</a>
 */
package com.crunii.micro.common.queue.impl;

import com.crunii.micro.common.queue.FQThreadFactory;
import com.crunii.micro.common.queue.FastQueue;
import com.crunii.micro.common.queue.ObjectEvent;
import com.crunii.micro.common.queue.ObjectEventFactory;
import com.lmax.disruptor.EventHandler;
import com.lmax.disruptor.EventTranslatorOneArg;
import com.lmax.disruptor.SleepingWaitStrategy;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;
import lombok.extern.slf4j.Slf4j;

/**
 * @author 田平 create 2019年3月1日下午2:48:24
 */
@Slf4j
public class FastQueueImpl<T> implements FastQueue<T> {
	/**
	 * 一定是2的幂
	 */
	private int size = 1024;

	private Disruptor<ObjectEvent<T>> disruptor;

	private ProducerType type = ProducerType.MULTI;

	private EventHandler<ObjectEvent<T>> eventHandler = new AbstractFastQueueHandler<T>() {

		@Override
		public void handler(ObjectEvent<T> event, long sequence, boolean endOfBatch) {
			log.info("sequence:" + sequence + ",val:" + event.getVal().toString());
			event.clear();
		}

	};

	private EventTranslatorOneArg<ObjectEvent<T>, T> translatorOneArg = new FastQueueTranslatorOneArg<T>() {

		@Override
		public void translate(ObjectEvent<T> event, long sequence, T arg0) {
			event.setVal(arg0);
		}
	};

	public FastQueueImpl() {

	}

	public FastQueueImpl(ProducerType type) {
		this.type = type;
	}

	public FastQueueImpl(int size, ProducerType type) {
		this.size = size;
		this.type = type;
	}

	public FastQueueImpl(int size, EventHandler<ObjectEvent<T>> eventHandler) {
		this.size = size;
		this.eventHandler = eventHandler;
	}

	public FastQueueImpl(int size, ProducerType type, EventHandler<ObjectEvent<T>> eventHandler) {
		this.size = size;
		this.type = type;
		this.eventHandler = eventHandler;
	}

	public static void main(String[] args) {
		FastQueueImpl<String> queue = new FastQueueImpl<>(16, ProducerType.SINGLE);
		queue.init();
		for (int i = 0; i < 16; i++) {
			queue.add("TEST" + i);
		}
		queue.destroy();

	}

	@Override
	@SuppressWarnings("unchecked")
	public void init() {
		disruptor = new Disruptor<ObjectEvent<T>>(new ObjectEventFactory<T>(), this.size, new FQThreadFactory(), this.type,
				new SleepingWaitStrategy());
		disruptor.handleEventsWith(eventHandler);
		disruptor.start();
	}

	@Override
	public void destroy() {
		if (disruptor != null) {
			disruptor.shutdown();
			log.info("disruptor shutdown!");
		}
	}

	@Override
	public void add(T t) {
		disruptor.publishEvent(translatorOneArg, t);
	}

	/**
	 * @return the size
	 */
	public int getSize() {
		return size;
	}

	/**
	 * @param size the size to set
	 */
	public void setSize(int size) {
		this.size = size;
	}

	/**
	 * @return the eventHandler
	 */
	public EventHandler<ObjectEvent<T>> getEventHandler() {
		return eventHandler;
	}

	/**
	 * @param eventHandler the eventHandler to set
	 */
	public void setEventHandler(EventHandler<ObjectEvent<T>> eventHandler) {
		this.eventHandler = eventHandler;
	}

}
