package com.vip.vjtools.jmx;

import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.management.MBeanServerConnection;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.management.openmbean.CompositeDataSupport;

public class GCutilExpression {

	private static final String EDEN = "eden";
	private static final String SURVIVOR = "survivor";
	private static final String OLD = "old";
	private static final String TENURED = "tenured"; // 并行GC算法老生代的名称
	private static final String PERM = "perm";
	private static final String METASPACE = "metaspace";// JDK8永久代名称
	public static final String COMPRESSED_CLASS_SPACE = "compressed class space";

	private static final DecimalFormat DF = new DecimalFormat("0.00");

	private static final String GARBAGE_COLLECTORS = "java.lang:type=GarbageCollector,name=*";
	private static final String MEM_POOL_PREFIX = "java.lang:type=MemoryPool,name=";

	// Collectors的三个属性
	private static final String MEMORY_POOL_ATTRIBUTE = "MemoryPoolNames";
	private static final String COLLECTION_TIME_ATTRIBUTE = "CollectionTime";
	private static final String COLLECTION_COUNT_ATTRIBUTE = "CollectionCount";

	private ObjectName YGC_COLLECTOR;
	private ObjectName FGC_COLLECTOR;
	private Map<String, String> pollNameMapping;

	private MBeanServerConnection mbsc;

	public GCutilExpression(MBeanServerConnection mbsc) throws Exception {
		this.mbsc = mbsc;
		mappingCollctors();
		mappingPools();
	}

	private void mappingCollctors() throws Exception {
		Set<ObjectInstance> beans = mbsc.queryMBeans(Client.getObjectName(GARBAGE_COLLECTORS), null);

		A: for (ObjectInstance collector : beans) {
			ObjectName collectorName = collector.getObjectName();
			// 获得这个Collector负责的Memory Pool Name
			String[] memoryPoolNames = (String[]) mbsc.getAttribute(collectorName, MEMORY_POOL_ATTRIBUTE);

			for (String poolName : memoryPoolNames) {
				if (poolName.toLowerCase().contains(OLD) || poolName.toLowerCase().contains(TENURED)) {
					FGC_COLLECTOR = collectorName;
					continue A;
				}
			}
			// 如果此收集器负责的分区没有Old,则是YGC_COLLECTOR
			YGC_COLLECTOR = collectorName;
		}
	}

	private void mappingPools() throws Exception {
		// full gc的collector,下属的memoryPool包括所有需要GC的Pool(Code Reserve等则不在此列)
		Set<ObjectInstance> beans = mbsc.queryMBeans(Client.getObjectName(MEM_POOL_PREFIX + "*"), null);
		pollNameMapping = new HashMap<String, String>();
		for (ObjectInstance collector : beans) {
			ObjectName collectorName = collector.getObjectName();
			String name = (String) getAttribute(collectorName, "Name");
			name = name.trim();
			String lowerCaseName = name.toLowerCase();
			if (lowerCaseName.contains(SURVIVOR)) {
				pollNameMapping.put(SURVIVOR, name);
			} else if (lowerCaseName.contains(EDEN)) {
				pollNameMapping.put(EDEN, name);
			} else if (lowerCaseName.contains(OLD) || lowerCaseName.contains(TENURED)) {
				pollNameMapping.put(OLD, name);
			} else if (lowerCaseName.contains(PERM) || lowerCaseName.contains(METASPACE)) {
				pollNameMapping.put(PERM, name);
			} else if(lowerCaseName.contains(COMPRESSED_CLASS_SPACE)) {
				pollNameMapping.put(COMPRESSED_CLASS_SPACE, name);
			}
		}
	}

	public String getE() throws Exception {
		String poolName = MEM_POOL_PREFIX + pollNameMapping.get(EDEN);
		return usedPercentage(poolName);
	}

	public String getS() throws Exception {
		String poolName = MEM_POOL_PREFIX + pollNameMapping.get(SURVIVOR);
		return usedPercentage(poolName);
	}

	public String getO() throws Exception {
		String poolName = MEM_POOL_PREFIX + pollNameMapping.get(OLD);
		return usedPercentage(poolName);
	}

	public String getP() throws Exception {
		String poolName = MEM_POOL_PREFIX + pollNameMapping.get(PERM);
		return usedPercentage(poolName);
	}
	
	public String getCCS() throws Exception {
		String poolName = MEM_POOL_PREFIX + pollNameMapping.get(COMPRESSED_CLASS_SPACE);
		return usedPercentage(poolName);
	}

	public Object getYGC() throws Exception {
		return getAttribute(YGC_COLLECTOR, COLLECTION_COUNT_ATTRIBUTE);
	}

	public Double getYGCT() throws Exception {
		return Double.parseDouble(getAttribute(YGC_COLLECTOR, COLLECTION_TIME_ATTRIBUTE).toString()) / 1000;
	}

	public Object getFGC() throws Exception {
		return getAttribute(FGC_COLLECTOR, COLLECTION_COUNT_ATTRIBUTE);
	}

	public Double getFGCT() throws Exception {
		return Double.parseDouble(getAttribute(FGC_COLLECTOR, COLLECTION_TIME_ATTRIBUTE).toString()) / 1000;
	}

	public Object getGCT() throws Exception {
		return getFGCT() + getYGCT();
	}

	private Object getAttribute(ObjectName beanName, String attributeName) throws Exception {
		return mbsc.getAttribute(beanName, attributeName);
	}

	private String usedPercentage(String poolName) throws Exception {
		CompositeDataSupport attribute = (CompositeDataSupport) mbsc.getAttribute(Client.getObjectName(poolName),
				"Usage");
		double max = Double.parseDouble(attribute.get("max").toString());
		// 如果Max没有设置或GC算法原因没有max,则以committed为准
		max = max < 0 ? Double.parseDouble(attribute.get("committed").toString()) : max;
		double resultS = Double.parseDouble(attribute.get("used").toString()) / max * 100;
		return max == 0.0d ? DF.format(max) : DF.format(resultS);
	}
}