package com.dianping.cat.consumer.metric;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
import org.unidal.dal.jdbc.DalException;
import org.unidal.dal.jdbc.DalNotFoundException;
import org.unidal.helper.Files;
import org.unidal.lookup.annotation.Inject;
import org.xml.sax.SAXException;

import com.dianping.cat.Cat;
import com.dianping.cat.Constants;
import com.dianping.cat.advanced.metric.config.entity.MetricConfig;
import com.dianping.cat.advanced.metric.config.entity.MetricItemConfig;
import com.dianping.cat.advanced.metric.config.transform.DefaultSaxParser;
import com.dianping.cat.consumer.metric.MetricAnalyzer.ConfigItem;
import com.dianping.cat.core.config.Config;
import com.dianping.cat.core.config.ConfigDao;
import com.dianping.cat.core.config.ConfigEntity;

public class MetricConfigManager implements Initializable {

	@Inject
	protected ConfigDao m_configDao;

	@Inject
	private ProductLineConfigManager m_productLineConfigManager;

	private int m_configId;

	private MetricConfig m_metricConfig;

	private long m_modifyTime;

	private static final String CONFIG_NAME = "metricConfig";

	public String buildMetricKey(String domain, String type, String metricKey) {
		return domain + ":" + type + ":" + metricKey;
	}

	public boolean deleteDomainConfig(String key) {
		getMetricConfig().removeMetricItemConfig(key);
		return storeConfig();
	}

	public MetricConfig getMetricConfig() {
		synchronized (this) {
			return m_metricConfig;
		}
	}

	@Override
	public void initialize() throws InitializationException {
		try {
			Config config = m_configDao.findByName(CONFIG_NAME, ConfigEntity.READSET_FULL);
			String content = config.getContent();

			m_metricConfig = DefaultSaxParser.parse(content);
			m_configId = config.getId();
			m_modifyTime = config.getModifyDate().getTime();
		} catch (DalNotFoundException e) {
			try {
				String content = Files.forIO().readFrom(
				      this.getClass().getResourceAsStream("/config/default-metric-config.xml"), "utf-8");
				Config config = m_configDao.createLocal();

				config.setName(CONFIG_NAME);
				config.setContent(content);
				m_configDao.insert(config);

				m_metricConfig = DefaultSaxParser.parse(content);
				m_configId = config.getId();
				m_modifyTime = new Date().getTime();
			} catch (Exception ex) {
				Cat.logError(ex);
			}
		} catch (Exception e) {
			Cat.logError(e);
		}
		if (m_metricConfig == null) {
			m_metricConfig = new MetricConfig();
		}

		deleteUnusedConfig();
	}

	private void deleteUnusedConfig() {
		try {
			Map<String, MetricItemConfig> configs = m_metricConfig.getMetricItemConfigs();
			List<String> unused = new ArrayList<String>();

			for (MetricItemConfig config : configs.values()) {
				String domain = config.getDomain();
				String productLine = m_productLineConfigManager.queryProductLineByDomain(domain);

				if (Constants.BROKER_SERVICE.equals(domain)) {
					unused.add(config.getId());
				}
				if ("Default".equals(productLine)) {
					unused.add(config.getId());
				}
			}
			for (String id : unused) {
				m_metricConfig.removeMetricItemConfig(id);
			}
			storeConfig();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public boolean insertIfNotExist(String domain, String type, String metricKey, ConfigItem item) {
		String key = buildMetricKey(domain, type, metricKey);
		MetricItemConfig config = m_metricConfig.findMetricItemConfig(key);

		if (config != null) {
			return true;
		} else {
			config = new MetricItemConfig();

			config.setId(key);
			config.setDomain(domain);
			config.setType(type);
			config.setMetricKey(metricKey);
			config.setTitle(item.getTitle());
			config.setShowAvg(item.isShowAvg());
			config.setShowCount(item.isShowCount());
			config.setShowSum(item.isShowSum());
			return insertMetricItemConfig(config);
		}
	}

	public boolean insertMetricItemConfig(MetricItemConfig config) {
		getMetricConfig().addMetricItemConfig(config);

		return storeConfig();
	}

	public MetricItemConfig queryMetricItemConfig(String id) {
		return getMetricConfig().findMetricItemConfig(id);
	}

	public List<MetricItemConfig> queryMetricItemConfigs(Collection<String> domains) {
		List<MetricItemConfig> configs = new ArrayList<MetricItemConfig>();
		Map<String, MetricItemConfig> metricConfig = getMetricConfig().getMetricItemConfigs();

		for (Entry<String, MetricItemConfig> entry : metricConfig.entrySet()) {
			MetricItemConfig item = entry.getValue();

			if (domains.contains(item.getDomain())) {
				configs.add(item);
			}
		}
		Collections.sort(configs, new Comparator<MetricItemConfig>() {

			@Override
			public int compare(MetricItemConfig m1, MetricItemConfig m2) {
				return (int) ((m1.getViewOrder() - m2.getViewOrder()) * 100);
			}
		});
		return configs;
	}

	public void refreshMetricConfig() throws DalException, SAXException, IOException {
		Config config = m_configDao.findByName(CONFIG_NAME, ConfigEntity.READSET_FULL);
		long modifyTime = config.getModifyDate().getTime();

		synchronized (this) {
			if (modifyTime > m_modifyTime) {
				String content = config.getContent();
				MetricConfig metricConfig = DefaultSaxParser.parse(content);

				m_metricConfig = metricConfig;
				m_modifyTime = modifyTime;
			}
		}
	}

	private boolean storeConfig() {
		synchronized (this) {
			try {
				Config config = m_configDao.createLocal();

				config.setId(m_configId);
				config.setKeyId(m_configId);
				config.setName(CONFIG_NAME);
				config.setContent(getMetricConfig().toString());
				m_configDao.updateByPK(config, ConfigEntity.UPDATESET_FULL);
			} catch (Exception e) {
				Cat.logError(e);
				return false;
			}
		}
		return true;
	}

}

@@ -3353,16 +3353,102 @@
 ;%0A%09%09%09%09%7D%0A
+%09%09%09%09if (config.getId().contains(%22:metric:%22)) %7B%0A%09%09%09%09%09unused.add(config.getId());%0A%09%09%09%09%7D%0A
 %09%09%09%7D%0A%09%09%09

modify the metric config manager