package com.ht.data;

/*
 * To change this template, choose Tools | Templates and open the template in
 * the editor.
 */
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

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

import com.ht.data.listener.IDataListener;
import com.ht.data.script.ScriptHandler;
import com.ht.web.cometd.CometdManager;
import com.ht.web.hessian.HessianFactoryManger;
import com.ht.web.remoting.HessianResponse;

/**
 *
 * @author Administrator
 */
public enum RealTimeDataManager {

    INSTANCE;
    private static final Logger log = LoggerFactory.getLogger(RealTimeDataManager.class.getName());
    
    // 脚本执行器
    private ScriptHandler scriptHandler = null;
    
    // 全局变量名
    private final  Set<String> varNameSet = Collections.synchronizedSet(new HashSet<String>());
    
    // 实时变量数据库
    private final  ConcurrentHashMap<String, Object> realtimeDataMap = new ConcurrentHashMap<String, Object>();
    
    /**
     * 变量关联的监听器 the map associating the name of a data to the list of listeners
     * or actions associated with it
     */
    private final Map<String, Set<IDataListener>> listenersActionsMap = new HashMap<String, Set<IDataListener>>();
    
    private final Object LOCK = new Object();// 启动/停止同步锁
    private boolean running = false;
    
    private RealTimeDataManager() {
        scriptHandler = new ScriptHandler(realtimeDataMap);
	}
    
    public void init() {
		log.info("初始化实时数据管理器");
    }

    public void registDataChangeListener(IDataListener listener) {
        log.debug("注册数据监听器");
        synchronized (listenersActionsMap) {
            for (String varname : listener.getDataVarNames()) {

                varNameSet.add(varname);
                //向服务器注册监听的变量
                CometdManager.INSTANCE.getVarTagService().addDataToListen(varname);
                
                // 关联变量与动画
                Set<IDataListener> list = this.listenersActionsMap.get(varname);
                if (list == null) {
                    list = new HashSet<IDataListener>();
                    this.listenersActionsMap.put(varname, list);
                }
                list.add(listener);
            }

        }
    }

    public void unregistDataChangeListener(IDataListener listener) {
        synchronized (listenersActionsMap) {

            for (String tagname : listener.getDataVarNames()) {

                Set<IDataListener> list = this.listenersActionsMap.get(tagname);
                if (list != null) {
                    while(list.remove(listener)){;};
                }
                
                if (list == null || list.size() == 0) {
                    //向服务器注销监听的变量
                	CometdManager.INSTANCE.getVarTagService().removeDataToListen(tagname);
//                    this.varNameMap.remove(tagname.replace('/', '_'));
                }
            }

        }
    }

//    public Set<String> getTagPathSet() {
//        return tagPathSet;
//    }
    
//    public Map<String, String> getVarNameMap() {
//		return varNameMap;
//	}

    public Set<String> getVarNameSet() {
		return varNameSet;
	}
    
    /**
     * 更新变量值
     * @param theName the name of a data(变量路径varPath)
     * @param value the new value for the data
     */
    public void updateVarValue(String theName, final Object value) {
        if (!running || value == null) {
            return;
        }

        if (theName != null && !theName.isEmpty()) {

            Object obj = realtimeDataMap.get(theName);
            if (obj != null && obj.equals(value)) {
                // 值未改变
                return;
            }

            realtimeDataMap.put(theName, value);
            varDataChanged(theName);
            //log.debug("updateVarValue: {} {}", theName, value);

        } else {
            log.warn("标签名称为空: {} {}", theName, value);
        }
    }

	public void varDataChanged(String theName) {
		// 触发所有相关的动画和动作
		Set<IDataListener> list = listenersActionsMap.get(theName);
		if (list != null) {
		    for (IDataListener listener : list) {
		        if (!running) {
		            break;
		        }
		        try {
		            listener.dataChanged(theName);
		        } catch (Exception e) {
		            e.printStackTrace();
		        }

		    }
		}
	}

    /**
     * returns the value corresponding to the provided tag name
     *
     * @param tagName a tag name
     * @return the value corresponding to the provided tag name
     */
    public Object getVarValue(String tagName) {
        if (!running) {
            return null;
        }
        Object value = null;

        if (tagName != null) {
            value = realtimeDataMap.get(tagName);
        }

        return value;
    }
    
    /**
     * 主动请求，强制更新全部变量值
     */
    public void updateAllVarValues() {
    	try {
			HessianResponse resp = HessianFactoryManger.INSTANCE.getTagVarService().getVarDataValue(varNameSet);
			Map<String, Object> data = (Map<String, Object>) resp.getData();
			if (data != null) {
				for (Entry<String, Object> entry : data.entrySet()) {
					realtimeDataMap.put(entry.getKey(), entry.getValue());
					varDataChanged(entry.getKey());
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
    }
    
    /**
     * 主动请求，强制更新给定变量值
     */
    public void updateVarValues(Set<String> varNames) {
    	try {
			HessianResponse resp = HessianFactoryManger.INSTANCE.getTagVarService().getVarDataValue(varNames);
			Map<String, Object> data = (Map<String, Object>) resp.getData();
			if (data != null) {
				for (Entry<String, Object> entry : data.entrySet()) {
					realtimeDataMap.put(entry.getKey(), entry.getValue());
				}
				for (Entry<String, Object> entry : data.entrySet()) {
					varDataChanged(entry.getKey());
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
    }
    
    public void start() {
        synchronized (LOCK) {
            if (!running) {
                running = true;

                scriptHandler.start();
            }
        }
    }

    public void stop() {
        synchronized (LOCK) {

            if (running) {

                running = false;
                log.info("停止实时数据库");

                if (scriptHandler != null) {
                    scriptHandler.stop();
                }

                realtimeDataMap.clear();
                listenersActionsMap.clear();
//                soeEventList.clear();
            }
        }
    }
}
