package nc.pub.smart.cache;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.StaxDriver;
import com.ufida.iufo.pub.tools.AppDebug;
import com.ufida.iufo.pub.tools.StringTools;
import com.yonyou.cloud.ncc.NCCEnv;

import nc.bs.framework.common.NCLocator;
import nc.bs.framework.common.RuntimeEnv;
import nc.bs.framework.core.service.IDataSourceQuery;
import nc.itf.iufo.IBaseSPService;
import nc.pub.iufo.cache.store.CacheElement;
import nc.pub.smart.script.engine.rule.config.ScriptRuleConfig;
import nc.pub.smart.util.SmartUtilities;
import nc.vo.smart.config.ProviderConfigRegister;
import nc.vo.smart.config.SmartConfig;
import nc.vo.smart.config.SmartDataSource;
import nc.vo.smart.config.SmartHideConfig;
import nccloud.commons.lang.ArrayUtils;
import nccloud.commons.lang.StringUtils;
import uap.pub.ae.datasource.exception.DataSourceRegistryException;
import uap.pub.ae.datasource.registry.DataSourceRegistry;
import uap.pub.ae.datasource.registry.DataSourceRegistryItem;
import uap.pubitf.ae.datasource.IDataSourceRegistryService;

/**
 * smart配置加载器
 *
 * @author liuyy
 *
 */
public class SmartConfigLoader extends DefaultCacheLoader {

	@Override
	public Object[] add(Object[] values) {
		return null;
	}

	@Override
	public Object[] load(String[] keys) {
		return loadAll();
	}

	@Override
	public Object[] loadAll() {
			SmartConfig config = new SmartConfig();

			try {
				loadDataSource(config);
			} catch (Exception e1) {
				AppDebug.error(e1);
				return null;
			}

			//如果是后台加载，线程数据源为null时，把定义数据源设置为线程数据源，以防止加载模块信息时抛异常--add by biancm 20110719
			final String userDsName = SmartUtilities.getCurrentDsName();

			try {
			if (RuntimeEnv.getInstance().isRunningInServer()){
				if(StringUtils.isEmpty(userDsName)){
					String designDsName = config.getDesignDsName();
					if (!StringUtils.isEmpty(designDsName)) {
						SmartUtilities.setCurrentDsName(designDsName);
					}
				}else if(userDsName.equalsIgnoreCase("design")){
					//prop.xml文件中是否配置了，如否，压入定义数据源
					String[] dss;
					try {
						dss = NCLocator.getInstance().lookup(IDataSourceQuery.class)
								.getDataSorceNames();
					} catch (Exception e) {
						AppDebug.error(e);
						dss = new String[0];
					}
					List<String> dssList = new ArrayList<String>();
					if(dss != null){
						for(String ds : dss){
							dssList.add(ds.toLowerCase());
						}
					}
					if(!dssList.contains(userDsName.toLowerCase())){
						String designDsName = config.getDesignDsName();
						if (!StringUtils.isEmpty(designDsName)) {
							SmartUtilities.setCurrentDsName(designDsName);
						}
					}
				}

			}

			IBaseSPService service = NCLocator.getInstance().lookup(
					IBaseSPService.class);

			// 加载ScriptRuleConfig
			ScriptRuleConfig[] scriptRuleConfigs = service.getScriptRuleConfigs(
					SmartConfig.CONFIG_DIRECTORY,
					SmartConfig.RULE_CONFIG_FILE_PATTERN);

			// Map结构能保证去除重复项（以moduleCode为准）
			Map<String, ScriptRuleConfig> scriptRuleConfigMap = new HashMap<String, ScriptRuleConfig>();
			for (ScriptRuleConfig reg : scriptRuleConfigs) {
				if (reg != null) {
					if(scriptRuleConfigMap.get(reg.getModuleCode()) != null){
						ScriptRuleConfig existedReg = scriptRuleConfigMap.get(reg.getModuleCode());
						existedReg.addRuleConfigItem(reg.getItems());
					}else{
						scriptRuleConfigMap.put(reg.getModuleCode(), reg);
					}

				}
			}

			config.setScriptRuleConfigs(scriptRuleConfigMap.values().toArray(
					new ScriptRuleConfig[scriptRuleConfigMap.size()]));



			// 加载provider
			ProviderConfigRegister[] providerRegs = service.getProviderConfigRegisters(
					SmartConfig.CONFIG_DIRECTORY,
					SmartConfig.PROVIDER_CONFIG_FILE_PATTERN);

			// Map结构能保证去除重复项（以moduleName为准）
			Map<String, ProviderConfigRegister> providerRegMap = new HashMap<String, ProviderConfigRegister>();
			for (ProviderConfigRegister reg : providerRegs) {
				if (reg != null) {
					if(providerRegMap.get(reg.getModuleName()) != null){
						ProviderConfigRegister existedReg = providerRegMap.get(reg.getModuleName());
						existedReg.addProviderConfigs(reg.getProviders());
					}else{
						providerRegMap.put(reg.getModuleName(), reg);
					}

				}
			}

			config.setProviderConfigRegisters(providerRegMap.values().toArray(
					new ProviderConfigRegister[providerRegMap.size()]));

			SmartHideConfig[] smartHideConfigs = service.getSmartHideConfigs(SmartConfig.CONFIG_DIRECTORY,
					SmartConfig.HIDE_CONFIG_FILE_PATTERN);
			config.setSmartHideConfigs(smartHideConfigs);
			config.initSmartHideConfig();
			//加载数据源注册表
			loadDataSourceRegistry(config);

		} catch (Exception e) {
			AppDebug.error(e);
		}finally{
			SmartUtilities.setCurrentDsName(userDsName);
		}

		CacheElement e = new CacheElement(
				SmartConfigCache.KEY_SMART_CONFIG, config);
		return new Object[] { e };
	}

	/**
	 * 加载数据源注册表
	 * @param config
	 */
	private void loadDataSourceRegistry(SmartConfig config) {
		IDataSourceRegistryService service = NCLocator.getInstance().lookup(IDataSourceRegistryService.class);
		try {
			DataSourceRegistry registry = service.loadDataSourceRegistry();
			config.setDataSourceRegistry(registry);
		} catch (DataSourceRegistryException e) {
			AppDebug.error(e);
		}

	}

	private void loadDataSource(SmartConfig config) throws Exception{
		IBaseSPService service = NCLocator.getInstance().lookup(
				IBaseSPService.class);
		// 加载数据源配置信息
		config.setDataSource(loadDataSource());// 设置数据源信息

		if (reviseDataSource(config)) {
			service.saveSmartDataSource(config.getDataSource());
		}

	}

	/**
	 * 加载数据源配置信息
	 *
	 * @return
	 */
	private SmartDataSource loadDataSource() {
		SmartDataSource dataSource = null;
		try {
			IBaseSPService service = NCLocator.getInstance().lookup(
					IBaseSPService.class);
			dataSource = service.getSmartDataSource();
		} catch (Exception e) {
			AppDebug.error(e);
		}
		if (dataSource == null) {
			dataSource = new SmartDataSource();// 容错处理
		}
		return dataSource;
	}

	@Override
	public void remove(String[] keys) {

	}

	@Override
	public Object[] update(Object[] values) {
		return null;
	}

	/**
	 * 对配置文件中的数据源进行校正
	 *
	 * @param config
	 * @return 如果为true，则需要更新配置文件
	 */
	private boolean reviseDataSource(SmartConfig config) {
		boolean result = false;
		String[] propDSs = null;
		try {
			IDataSourceQuery srv = NCLocator.getInstance().lookup(
					IDataSourceQuery.class);
			propDSs = srv.getDataSorceNames();


		} catch (Exception e) {
			AppDebug.error(e);
		}
		if (propDSs == null || propDSs.length == 0) {
			AppDebug.error(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("1413002_0","01413002-0978")/*@res "prop.xml中未配置任何数据源！"*/);
			return false;
		}

		//定义数据源允许为空 biancm 20140925
//		if (StringUtils.isEmpty(config.getDesignDsName())
//				|| !StringTools.contains(propDSs, config.getDesignDsName(), true)) {
//			config.setDesignDsName(null);
//
//			if(propDSs.length > 1){
//				//定义数据源优先取线程中的用户数据源
//				String userDs = SmartUtilities.getCurrentDsName();
//				if(!StringUtils.isEmpty(userDs)
//						&& StringTools.contains(propDSs, userDs, true)){
//					if(SmartUtilities.isNCDataSource(userDs)){
//						config.setDesignDsName(userDs);
//						AppDebug.warn(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("1413002_0","01413002-0979")/*@res "datasource.xml中定义数据源为空或者不存在，被指定为当前用户数据源："*/ + userDs);
//					}
//				}
//			}
//
//
//			// 设置定义数据源
//			if (config.getDesignDsName() == null) {
//				for (String dds : propDSs) {
//					if (SmartUtilities.isNCDataSource(dds)) {
//						config.setDesignDsName(dds);
//						AppDebug.warn(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("1413002_0","01413002-0980")/*@res "datasource.xml中定义数据源为空或者不存在，被指定为："*/ + dds);
//						break;
//					}
//				}
//			}
//
//			if(config.getDesignDsName() == null){
//				AppDebug.error(nc.vo.ml.NCLangRes4VoTransl.getNCLangRes().getStrByID("1413002_0","01413002-0981")/*@res "找不到NC数据源！分析平台初始化失败！"*/);
//				return false;
//			}
//			result = true;
//		}


		String[] execDss = config.getExecuteDsNames();

		//有效数据源列表
		//直接调IDataSourceRegistryService加载，不能走缓存
		String[] validDs = null;

		try{
			DataSourceRegistry registry = NCLocator.getInstance().lookup(IDataSourceRegistryService.class).loadDataSourceRegistry();
			DataSourceRegistryItem[] registryItems = registry.getAllDataSourceRegistryItems();

			List<String> dsList = new ArrayList<String>();
			for(DataSourceRegistryItem item:registryItems){
				String dsName = item.getName();
				if(!StringUtils.isEmpty(dsName)){
					dsList.add(dsName);
				}
			}

			validDs = dsList.toArray(new String[dsList.size()]);

		} catch (Exception e) {
			AppDebug.error(e);
		}

		if (validDs == null || validDs.length == 0) {
			AppDebug.error("未在datasource_registry.xml中加载到任何数据源"); /*-=notranslate=-*/
			return false;
		}

		if (execDss != null && execDss.length > 0) {
			// 倒腾一下执行数据源
			String[] clones = execDss.clone();
			if (execDss != null && execDss.length > 0) {
				for (String execDs : execDss) {
					if (!StringTools.contains(validDs, execDs, true)) {
						clones = (String[]) ArrayUtils.removeElement(clones,
								execDs);
						AppDebug.info("未在prop.xml中找到数据源：" + execDs); /*-=notranslate=-*/
						result = true;
					}
				}
			}
			if (clones.length != execDss.length) {
				config.setExecuteDsNames(clones);
			}
		}

		if (config.getExecuteDsNames() == null
				|| config.getExecuteDsNames().length < 1) {
			if(!StringUtils.isEmpty(config.getDesignDsName())) {
				config.setExecuteDsNames(new String[] { config.getDesignDsName() });
				result = true;
			}

		}else if(!StringUtils.isEmpty(config.getDesignDsName())
				&& !StringTools.contains(config.getExecuteDsNames(), config.getDesignDsName(), true)){
			//执行数据源中必须有定义数据源--added by biancm 20110720
			String[] newExeDss = (String[]) ArrayUtils.add(config.getExecuteDsNames(), config.getDesignDsName());
			config.setExecuteDsNames(newExeDss);
			result = true;
		}

    // 配置文件丢失了designDsName
    // 暂时先引用图形化工程的代码 kanghhf 2020-11-11
    if (StringUtils.isEmpty(config.getDesignDsName())) {
      config.setDesignDsName(getAE_Datasource());
    }
		return result;
	}
	
  /**
   * get AE资源库的名称 （云原生环境下读取ae数据源方法）
   */
  public static String getAE_Datasource_cloud() {

    String propFilePath = RuntimeEnv.getInstance().getNCHome() + File.separator
        + "ierp" + File.separator + "bin" + File.separator + "prop.xml";

    String aeDs = "";
    try (BufferedReader reader =
        new BufferedReader(new FileReader(propFilePath))) {
      String content = "";
      while (!StringUtils.isEmpty((content = reader.readLine()))) {
        if (content.contains("aeDataSource")) {
          break;
        }
      }
      if (!StringUtils.isEmpty(content)) {
        aeDs = content.substring(content.indexOf(">") + 1,
            content.lastIndexOf("<"));
      }
    }
    catch (IOException e) {
      AppDebug.error(e);
    }

    return aeDs;
  }

  /****
   * 非云原生环境下读取ae数据源方法
   */
  public static String getAE_Datasource_normal() {

    String filePath =
        RuntimeEnv.getInstance().getNCHome() + File.separator + "resources"
            + File.separator + "smart" + File.separator + "datasource.xml";
    File xmlFile = new File(filePath);

    XStream stream = null;
    stream = new XStream(new StaxDriver());
    Object config = stream.fromXML(xmlFile);

    String aeDs = "";
    if (config instanceof SmartDataSource) {
      SmartDataSource smartDs = (SmartDataSource) config;
      aeDs = smartDs.getDesignDsName();
    }

    return aeDs;
  }

  /**
   * 获取AE资源库名称，包含云原生和非云原生环境
   * 
   * @return
   */
  public static String getAE_Datasource() {
    return NCCEnv.isCloudNative() ? getAE_Datasource_cloud()
        : getAE_Datasource_normal();
  }
}