package com.dianping.cat.report.page.logview.service;

import java.nio.charset.Charset;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.Unpooled;
import org.unidal.cat.message.storage.Bucket;
import org.unidal.cat.message.storage.BucketManager;
import org.unidal.cat.message.storage.MessageFinderManager;
import org.unidal.lookup.annotation.Inject;
import org.unidal.lookup.annotation.Named;

import com.dianping.cat.Cat;
import com.dianping.cat.configuration.NetworkInterfaceManager;
import com.dianping.cat.consumer.dump.DumpAnalyzer;
import com.dianping.cat.consumer.dump.LocalMessageBucketManager;
import com.dianping.cat.message.CodecHandler;
import com.dianping.cat.message.Message;
import com.dianping.cat.message.Transaction;
import com.dianping.cat.message.codec.HtmlMessageCodec;
import com.dianping.cat.message.codec.WaterfallMessageCodec;
import com.dianping.cat.message.internal.MessageId;
import com.dianping.cat.message.spi.MessageTree;
import com.dianping.cat.message.storage.MessageBucketManager;
import com.dianping.cat.mvc.ApiPayload;
import com.dianping.cat.report.service.LocalModelService;
import com.dianping.cat.report.service.ModelPeriod;
import com.dianping.cat.report.service.ModelRequest;
import com.dianping.cat.report.service.ModelResponse;
import com.dianping.cat.report.service.ModelService;

@Named(type = LocalModelService.class, value = "logview")
public class LocalMessageService extends LocalModelService<String> implements ModelService<String> {
	public static final String ID = DumpAnalyzer.ID;

	@Inject
	private MessageFinderManager m_finderManager;

	@Inject("local")
	private BucketManager m_bucketManager;

	@Inject(type = MessageBucketManager.class, value = LocalMessageBucketManager.ID)
	private MessageBucketManager m_messageBucketManager;

	private WaterfallMessageCodec m_waterfall = new WaterfallMessageCodec();

	private HtmlMessageCodec m_html = new HtmlMessageCodec();

	public LocalMessageService() {
		super("logview");
	}

	@Override
	public String buildReport(ModelRequest request, ModelPeriod period, String domain, ApiPayload payload)
							throws Exception {
		String result = buildOldReport(request, period, domain, payload);

		if (result == null) {
			result = buildNewReport(request, period, domain, payload);
		}
		return result;
	}

	public String buildNewReport(ModelRequest request, ModelPeriod period, String domain, ApiPayload payload)
							throws Exception {
		String messageId = payload.getMessageId();
		boolean waterfull = payload.isWaterfall();
		MessageId id = MessageId.parse(messageId);
		ByteBuf buf = m_finderManager.find(id);
		MessageTree tree = null;

		try {
			if (buf != null) {
				tree = CodecHandler.decode(generateRealByteBuf(buf));
			}

			if (tree == null) {
				Bucket bucket = m_bucketManager
										.getBucket(id.getDomain(), NetworkInterfaceManager.INSTANCE.getLocalHostAddress(), id.getHour(), false);

				if (bucket != null) {
					bucket.flush();

					ByteBuf data = bucket.get(id);

					if (data != null) {
						tree = CodecHandler.decode(generateRealByteBuf(data));
					}
				}
			}
		} finally {
			CodecHandler.reset();
		}

		if (tree != null) {
			ByteBuf content = ByteBufAllocator.DEFAULT.buffer(8192);

			if (tree.getMessage() instanceof Transaction && waterfull) {
				m_waterfall.encode(tree, content);
			} else {
				m_html.encode(tree, content);
			}

			try {
				content.readInt(); // get rid of length
				return content.toString(Charset.forName("utf-8"));
			} catch (Exception e) {
				// ignore it
			}
		}

		return null;
	}

	public String buildOldReport(ModelRequest request, ModelPeriod period, String domain, ApiPayload payload)
							throws Exception {
		String messageId = payload.getMessageId();
		boolean waterfull = payload.isWaterfall();
		MessageTree tree = m_messageBucketManager.loadMessage(messageId);

		if (tree != null) {
			ByteBuf buf = ByteBufAllocator.DEFAULT.buffer(8192);

			if (tree.getMessage() instanceof Transaction && waterfull) {
				m_waterfall.encode(tree, buf);
			} else {
				m_html.encode(tree, buf);
			}

			try {
				buf.readInt(); // get rid of length
				return buf.toString(Charset.forName("utf-8"));
			} catch (Exception e) {
				// ignore it
			}
		}
		return null;
	}

	@Override
	public ModelResponse<String> invoke(ModelRequest request) {
		ModelResponse<String> response = new ModelResponse<String>();
		Transaction t = Cat.newTransaction("ModelService", getClass().getSimpleName());

		try {
			ModelPeriod period = request.getPeriod();
			String domain = request.getDomain();
			ApiPayload payload = new ApiPayload();

			payload.setMessageId(request.getProperty("messageId"));
			payload.setWaterfall(Boolean.valueOf(request.getProperty("waterfall", "false")));

			String report = getReport(request, period, domain, payload);

			response.setModel(report);

			t.addData("period", period);
			t.addData("domain", domain);
			t.setStatus(Message.SUCCESS);
		} catch (Exception e) {
			e.printStackTrace();
			Cat.logError(e);
			t.setStatus(e);
			response.setException(e);
		} finally {
			t.complete();
		}
		return response;
	}

	private ByteBuf generateRealByteBuf(ByteBuf originByteBuf) {
		ByteBuf realBuf = Unpooled.buffer(originByteBuf.capacity() + 3);

		realBuf.writeBytes("NT11".getBytes(Charset.forName("utf-8")));
		realBuf.writeBytes(originByteBuf);
		return realBuf;
	}

	@Override
	public boolean isEligable(ModelRequest request) {
		if (m_configManager.isHdfsOn()) {
			boolean eligibale = request.getPeriod().isCurrent();

			return eligibale;
		} else {
			return true;
		}
	}

}

@@ -159,41 +159,8 @@
 or;%0A
-import io.netty.buffer.Unpooled;%0A
 impo
@@ -201,16 +201,16 @@
 Bucket;%0A
+
 import o
@@ -2712,33 +2712,12 @@
 ode(
-generateRealByteBuf(
 buf)
-)
 ;%0A%09%09
@@ -3042,34 +3042,13 @@
 ode(
-generateRealByteBuf(
 data)
-)
 ;%0A%09%09
@@ -5058,24 +5058,24 @@
 lete();%0A%09%09%7D%0A
+
 %09%09return res
@@ -5089,262 +5089,8 @@
 %09%7D%0A%0A
-%09private ByteBuf generateRealByteBuf(ByteBuf originByteBuf) %7B%0A%09%09ByteBuf realBuf = Unpooled.buffer(originByteBuf.capacity() + 3);%0A%0A%09%09realBuf.writeBytes(%22NT11%22.getBytes(Charset.forName(%22utf-8%22)));%0A%09%09realBuf.writeBytes(originByteBuf);%0A%09%09return realBuf;%0A%09%7D%0A%0A
 %09@Ov

fix storage bug