package com.steerinfo.ems.formula.service.impl;

import com.steerinfo.auth.utils.JwtUtil;
import com.steerinfo.ems.Utils.DateUtils;
import com.steerinfo.framework.mapper.IBaseMapper;
import com.steerinfo.framework.service.impl.BaseServiceImpl;
import com.steerinfo.ems.formula.model.Formula;
import com.steerinfo.ems.Utils.StrUtils;
import com.steerinfo.ems.Utils.TimegranidUtils;
import com.steerinfo.ems.Utils.Tree;
import com.steerinfo.ems.formula.mapper.FormulaMapper;
import com.steerinfo.ems.formula.service.IFormulaService;
import com.steerinfo.ems.trmactitem.mapper.TRmActItemMapper;
import com.steerinfo.ems.trmactitem.model.TRmActItem;
import com.steerinfo.ems.trmactvalue.mapper.TRmActValueMapper;
import com.steerinfo.ems.trmactvalue.model.TRmActValue;
import com.steerinfo.ems.trmactvalue.service.ITRmActValueService;
import com.steerinfo.ems.trmbalancevalue.mapper.TRmBalanceValueMapper;
import com.steerinfo.ems.trmbalancevalue.model.TRmBalanceValue;
import com.steerinfo.ems.trmbalancevalue.service.ITRmBalanceValueService;
import com.steerinfo.ems.trmcalpoint.mapper.TRmCalpointMapper;
import com.steerinfo.ems.trmcalpoint.model.TRmCalpoint;
import com.steerinfo.ems.trmcalpointvalue.mapper.TRmCalpointValueMapper;
import com.steerinfo.ems.trmcalpointvalue.model.TRmCalpointValue;
import com.steerinfo.ems.trmcalpointvalue.service.ITRmCalpointValueService;
import com.steerinfo.ems.trmdfvalue.mapper.TRmDfValueMapper;
import com.steerinfo.ems.trmdfvalue.model.TRmDfValue;
import com.steerinfo.ems.trmdfvalue.service.ITRmDfValueService;
import com.steerinfo.ems.trmdwvalue.mapper.TRmDwValueMapper;
import com.steerinfo.ems.trmdwvalue.model.TRmDwValue;
import com.steerinfo.ems.trmdwvalue.service.ITRmDwValueService;
import com.steerinfo.ems.trmindexitem.mapper.TRmIndexItemMapper;
import com.steerinfo.ems.trmindexitem.model.TRmIndexItem;
import com.steerinfo.ems.trmindexvalue.mapper.TRmIndexValueMapper;
import com.steerinfo.ems.trmindexvalue.model.TRmIndexValue;
import com.steerinfo.ems.trmindexvalue.service.ITRmIndexValueService;
import com.steerinfo.ems.trmplanvalue.mapper.TRmPlanValueMapper;
import com.steerinfo.ems.trmplanvalue.model.TRmPlanValue;
import com.steerinfo.ems.trmplanvalue.service.ITRmPlanValueService;
import com.steerinfo.ems.trmworkprocmaterial.mapper.TRmWorkprocMaterialMapper;
import com.steerinfo.ems.trmworkprocmaterial.model.TRmWorkprocMaterial;
import com.steerinfo.ems.trmworkprocmaterialvalue.mapper.TRmWorkprocMaterialValueMapper;
import com.steerinfo.ems.trmworkprocmaterialvalue.model.TRmWorkprocMaterialValue;
import com.steerinfo.ems.trmworkprocmaterialvalue.service.ITRmWorkprocMaterialValueService;
import com.steerinfo.ems.trmworkprocproduct.mapper.TRmWorkprocProductMapper;
import com.steerinfo.ems.trmworkprocproduct.model.TRmWorkprocProduct;
import com.steerinfo.ems.trmworkprocproductvalue.mapper.TRmWorkprocProductValueMapper;
import com.steerinfo.ems.trmworkprocproductvalue.model.TRmWorkprocProductValue;
import com.steerinfo.ems.trmworkprocproductvalue.service.ITRmWorkprocProductValueService;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

import com.steerinfo.framework.service.pagehelper.PageHelper;
import com.steerinfo.framework.service.pagehelper.PageList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * Formula服务实现：
 * @author generator
 * @version 1.0-SNAPSHORT 2019-11-13 09:38
 * 类描述
 * 修订历史：
 * 日期：2019-11-13
 * 作者：generator
 * 参考：
 * 描述：Formula服务实现
 * @see null
 * @Copyright 湖南视拓信息技术股份有限公司. All rights reserved.
 */
@Service(value = "formulaService")
public class FormulaServiceImpl extends BaseServiceImpl<Formula, String> implements IFormulaService {
	
	private static final Logger logger = LoggerFactory.getLogger(FormulaServiceImpl.class);
	
	@Autowired
    private JdbcTemplate jdbcTemplate;
	
    @Autowired
    private FormulaMapper formulaMapper;
    
    @Autowired
    private TRmCalpointMapper tRmCalpointMapper;
    
    @Autowired
    private TRmCalpointValueMapper tRmCalpointValueMapper;

    @Autowired
    private TRmActItemMapper tRmActItemMapper;

    @Autowired
    private TRmActValueMapper tRmActValueMapper;
    
    @Autowired
    private TRmBalanceValueMapper tRmBalanceValueMapper;
    
    @Autowired
    private TRmPlanValueMapper tRmPlanValueMapper;
    @Autowired
    private TRmDwValueMapper tRmDwValueMapper;
    @Autowired
    private TRmDfValueMapper tRmDfValueMapper;
    
    @Autowired
    private TRmWorkprocMaterialMapper tRmWorkprocMaterialMapper;
    @Autowired
    private TRmWorkprocMaterialValueMapper tRmWorkprocMaterialValueMapper;
    
    @Autowired
    private TRmWorkprocProductMapper tRmWorkprocProductMapper;
    @Autowired
    private TRmWorkprocProductValueMapper tRmWorkprocProductValueMapper;
    
    @Autowired
    private TRmIndexItemMapper tRmIndexItemMapper;
    
    @Autowired
    private TRmIndexValueMapper tRmIndexValueMapper;
    
    @Autowired
    ITRmCalpointValueService tRmCalpointValueService;
    @Autowired
    ITRmActValueService tRmActValueService;
    @Autowired
    ITRmBalanceValueService tRmBalanceValueService;
    @Autowired
    ITRmPlanValueService tRmPlanValueService;
    @Autowired
    ITRmWorkprocProductValueService tRmWorkprocProductValueService;
    @Autowired
    ITRmWorkprocMaterialValueService tRmWorkprocMaterialValueService;
    @Autowired
    ITRmIndexValueService tRmIndexValueService;
    @Autowired
    ITRmDwValueService tRmDwValueService;
    @Autowired
    ITRmDfValueService tRmDfValueService;
    
    @Override
    protected IBaseMapper<Formula, String> getMapper() {
        return formulaMapper;
    }

    @Override
    public List<Formula> getByCode(String code) {
        return formulaMapper.getByCode(code);
    }

    @Override
	public Double getValByFormula(String formula, String timegranid, String clock, int digits, int type) {
		// 直接读取数据字段
		if(formula == null || formula.trim().isEmpty()){
			return -2d;
		} else if(formula.startsWith("R")){
			return getValByFormulaR(formula, timegranid, clock, digits, type);
		} else if(formula.matches("([1-9]+[0-9]*|0)(\\.[\\d]+)?")){ // 指定数值
			return Double.valueOf(formula);
		} else {
			String gs = replaceFormula(formula, timegranid, clock, digits, type);
			if(gs.startsWith("error")){
				logger.error("子公式错误-" + gs.substring(6));
				return -4d;
			}
			ScriptEngineManager manager = new ScriptEngineManager();
			ScriptEngine engine = manager.getEngineByName("JavaScript");
			try {
				Object result = engine.eval(gs);
				BigDecimal b = new BigDecimal(result.toString());
				return b.setScale(digits, BigDecimal.ROUND_HALF_UP).doubleValue();
			} catch (Exception e) {
				logger.error("计算错误：" + gs + ",formula:" + formula + ",timegranid:" + timegranid + ",clock:" + clock);
				return 0d;
			}
		}
	}
    
	/**
	 * 计算公式R(*)，为直接读取数据库字段
	 * @param formula
	 * @param timegranid
	 * @param clock
	 * @param digits
	 * @param type 数据字段 0 最终值 1 累计值 2 折标值
	 * @return
	 */
	public Double getValByFormulaR(String formula, String timegranid, String clock, int digits, int type) {
		if(!formula.startsWith("R")){
			return -1d;
		}
		Pattern p = Pattern.compile("(R[(])([\\w,]*?)([)])");
		Matcher m = p.matcher(formula);
		String tbname = ""; // 表名
		String colName = ""; // 列名
		String itemid = ""; // 项目ID
		if (m.matches() && m.groupCount()==3) {
			String[] f = m.group(2).split(",");
			if (f.length != 2){
				logger.error("计算公式格式错误：" + formula);
        		return -1d;
			}
			tbname = f[0].trim();
    		itemid = f[1].trim();
    		colName = "apportvalue";
    		if(type == 1){
    			colName = "sumvalue";
    		}else if(type == 2 && !tbname.equalsIgnoreCase("T_RM_INDEX_VALUE")){
    			colName = "stdvalue";
    		}
    		// 上报项目用 上报最终值参与计算
    		if(tbname.equalsIgnoreCase("T_RM_DW_VALUE")){
    			colName = "apportwvalue";
    		}
    		if(tbname.equalsIgnoreCase("T_RM_DF_VALUE")) {
    			colName = "apportwvalue";
    			
    			if(timegranid.equalsIgnoreCase("MONTH")) {
    				String sql = "select nvl(sum(round(" + colName + ", " + digits + ")),0) from " + tbname + " where itemid = '"
    						+ itemid + "' and timegranid = 'DAY' and clock like '" + clock + "%'";
    				try {
    					Double db = jdbcTemplate.queryForObject(sql, Double.class);
    					return db==null?0d:db;
    				} catch(Exception e) {
    					logger.error("财务数据月计算错误：itemid-" + itemid + ",clock-" + clock);
    					return -5d;
    				}
    			}else if(timegranid.equalsIgnoreCase("YEAR")) {
    				String sql = "select nvl(sum(round(" + colName + ", " + digits + ")),0) from " + tbname + " where itemid = '"
    						+ itemid + "' and timegranid = 'MONTH' and clock like '" + clock + "%'";
    				try {
    					Double db = jdbcTemplate.queryForObject(sql, Double.class);
    					return db==null?0d:db;
    				} catch(Exception e) {
    					logger.error("财务数据月计算错误：itemid-" + itemid + ",clock-" + clock);
    					return -5d;
    				}
    			}
    		}
        	
        	String sql = "select nvl(sum(round(" + colName + ", " + digits + ")),0) from " + tbname + " where itemid = '"
					+ itemid + "' and timegranid = '" + timegranid + "' and clock = '" + clock + "'";
			try {
				Double db = jdbcTemplate.queryForObject(sql, Double.class);
				return db==null?0d:db;
			} catch(Exception e) {
				logger.error("数据查询失败，sql:" + sql);
				return -5d;
			}
		} else {
        	logger.error("计算公式格式错误：" + formula);
        	return -1d;
        }
	}
	
	/**
	 * 计算公式 -> 读表公式  -> 算术表达式转换
	 * 
	 * @param formula 公式
	 * @param timegranid 时间粒度
	 * @param clock 时间（公式版本）
	 * @param digits 精度
	 * @param type 数据字段 0 最终值 1 累计值 2 折标值
	 * @return
	 * @throws DataAccessException
	 */
	public String replaceFormula(String formula, String timegranid, String clock, int digits, int type) throws DataAccessException {
		String regex="\\[\\w+?\\]";
		Pattern p = Pattern.compile(regex);
		Matcher m = p.matcher(formula);
		if (m.find()) {
			// 子公式ID
			String code = m.group().substring(1, m.group().length()-1);
			// 获得计算公式与表名
			Map<String, Object> mt = getFormulaAndTbname(code,clock);
			if(mt==null || mt.get("TABLENAME") == null || mt.get("SOURCECODE") == null){
				return "error_子项[" + code + "],公式版本：" + clock + "不存在";
			}
			String tbname = mt.get("TABLENAME").toString();
			Double db;
			String scode = mt.get("SOURCECODE").toString(); // 公式内容
			if(scode.matches("([1-9]+[0-9]*|0)(\\.[\\d]+)?") && tbname.equalsIgnoreCase("T_RM_ENERGY")){
				db = Double.valueOf(scode);
			} else {
				String colName = "apportvalue";
				// 上报项目用 上报最终值参与计算
	    		if(tbname.equalsIgnoreCase("T_RM_DW_VALUE") || tbname.equalsIgnoreCase("T_RM_DF_VALUE")){
	    			colName = "apportwvalue";
	    		}
				if(tbname.equalsIgnoreCase("T_RM_ENERGY")){
					return "error_折标系数[" + code + "]错误";
				}
				String sql = "select nvl(sum(" + colName + "),0) from " + tbname + " where itemid = '"
						+ code + "' and timegranid = '" + timegranid + "' and clock = '" + clock + "'";
				try {
					if(tbname.equalsIgnoreCase("T_RM_DF_VALUE") && timegranid.equalsIgnoreCase("month")) {
						HashMap<String, Object> idm = new HashMap<String, Object>();
						idm.put("clock", clock);
						idm.put("timegranid", timegranid);
						idm.put("itemid", code);
						TRmDfValue tv = tRmDfValueMapper.selectByPrimaryKey(idm);
						db = tv.getApportwvalue().doubleValue();
						db = db==null?0d:db;
					}else {
						db = jdbcTemplate.queryForObject(sql, Double.class);
						db = db==null?0d:db;
					}
				} catch(Exception e) {
					logger.error("数据查询失败，sql:" + sql);
					return "error_子项[" + code +"]计算错误";
				}
			}
			String re = "";
			if(db<0){
				// 负数添加括号，因为ScriptEngineManager计算减负数报错。如123.5--5.5
				re = "(" + new BigDecimal(Double.toString(db)).toPlainString() + ")";
			}else{
				re = new BigDecimal(Double.toString(db)).toPlainString();
			}
			formula = formula.replaceAll("\\[" + code + "\\]", re);
			return replaceFormula(formula, timegranid, clock, digits, type);
		} else {
			return formula;
		}
	}

	@Override
	public String checkFormula(Formula fm) {
		if(fm==null){
			return "公式内容为空";
		}
		if(fm.getClock()==null || fm.getClock().isEmpty()){
			return "请写入版本";
		}
		if(fm.getSourcecode()==null || fm.getSourcecode().isEmpty()){
			return "请写入公式内容";
		}
		if(fm.getCode()==null || fm.getCode().isEmpty()){
			return "请写入项目编号";
		}
		String tbname =  fm.getTablename();
		if(tbname==null || tbname.isEmpty()){
			return "请写入表名";
		}
		// 公式内容
		String sourcecode = fm.getSourcecode();
		// 数值表示折算系数
		if(sourcecode.matches("([1-9]+[0-9]*|0)(\\.[\\d]+)?")){
			return "";
		}
		sourcecode = sourcecode.replaceAll(" ", "");
		if(!Match(sourcecode)){
			return "()或者[]格式错误";
		}
		// 直接读取字段值公式由R开头
		if(sourcecode.startsWith("R")){
			if(!sourcecode.matches("R\\(\\w+?,\\w+\\)")){
				return "公式格式错误";
			}else{
				return "";
			}
		}
		// 计算公式必须(或者[开始
		if(!sourcecode.startsWith("[") && !sourcecode.startsWith("(")){
			return "公式格式错误";
		}
		// 公式由字母、数字、下划线、+-*/、()、[]组成
		String regex="[\\.\\+\\-\\*\\/\\[\\]\\(\\)\\w]+?";
		if(!sourcecode.matches(regex)){
			return "公式中存在非法字符";
		}
		String m2 = sourcecode.replaceAll("\\(", "").replaceAll("\\)", "");
		if(!m2.matches("((\\[[\\w]+?\\]|\\d+([.][0-9]+)?)[\\+\\-\\*\\/]{1})*(\\[[\\w]+?\\]|\\d+([.][0-9]+)?)")){
			return "公式格式错误！";
		}
		//List<Tree> lt = new ArrayList<Tree>();
		//sourcecode = sourcecode.replaceAll("]", ",]");
		//String res2 = checkFormula3(sourcecode,lt,fm.getClock());
		String mintimegranid = "";
		if(tbname.equalsIgnoreCase("T_RM_CALPOINT_VALUE")){
			mintimegranid = tRmCalpointMapper.selectByPrimaryKey(fm.getCode()).getMintimegranid();
		}else if(tbname.equalsIgnoreCase("T_RM_ACT_VALUE") || tbname.equalsIgnoreCase("T_RM_BALANCE_VALUE") || tbname.equalsIgnoreCase("T_RM_PLAN_VALUE")
				|| tbname.equalsIgnoreCase("T_RM_DW_VALUE") || tbname.equalsIgnoreCase("T_RM_DF_VALUE")){
			mintimegranid = tRmActItemMapper.selectByPrimaryKey(fm.getCode()).getMintimegranid();
		}else if(tbname.equalsIgnoreCase("T_RM_INDEX_VALUE")){
			mintimegranid = tRmIndexItemMapper.selectByPrimaryKey(fm.getCode()).getMintimegranid();
		}else if(tbname.equalsIgnoreCase("T_RM_WORKPROC_MATERIAL_VALUE")){
			mintimegranid = "DAY";
		}else if(tbname.equalsIgnoreCase("T_RM_WORKPROC_PRODUCT_VALUE")){
			mintimegranid = "DAY";
		}
		String res2 = checkFormula2(sourcecode,mintimegranid,fm.getCode(),fm.getClock());
		return res2;
	}
	
	@Override
	public String checkFormulaMint(Formula fm, String mintimegranid) {
		if(fm==null){
			return "公式内容为空";
		}
		if(fm.getClock()==null || fm.getClock().isEmpty()){
			return "请写入版本";
		}
		if(fm.getSourcecode()==null || fm.getSourcecode().isEmpty()){
			return "请写入公式内容";
		}
		if(fm.getCode()==null || fm.getCode().isEmpty()){
			return "请写入项目编号";
		}
		String tbname =  fm.getTablename();
		if(tbname==null || tbname.isEmpty()){
			return "请写入表名";
		}
		// 公式内容
		String sourcecode = fm.getSourcecode();
		// 数值表示折算系数
		if(sourcecode.matches("([1-9]+[0-9]*|0)(\\.[\\d]+)?")){
			return "";
		}
		sourcecode = sourcecode.replaceAll(" ", "");
		if(!Match(sourcecode)){
			return "()或者[]格式错误";
		}
		// 直接读取字段值公式由R开头
		if(sourcecode.startsWith("R")){
			if(!sourcecode.matches("R\\(\\w+?,\\w+\\)")){
				return "公式格式错误";
			}
		}else{
			// 计算公式必须(或者[开始
			if(!sourcecode.startsWith("[") && !sourcecode.startsWith("(")){
				return "公式格式错误";
			}
			// 公式由字母、数字、下划线、+-*/、()、[]组成
			String regex="[\\.\\+\\-\\*\\/\\[\\]\\(\\)\\w]+?";
			if(!sourcecode.matches(regex)){
				return "公式中存在非法字符";
			}
			String m2 = sourcecode.replaceAll("\\(", "").replaceAll("\\)", "");
			if(!m2.matches("((\\[[\\w]+?\\]|\\d+([.][0-9]+)?)[\\+\\-\\*\\/]{1})*(\\[[\\w]+?\\]|\\d+([.][0-9]+)?)")){
				return "公式格式错误！";
			}
		}
		String res2 = checkFormula2(sourcecode,mintimegranid,fm.getCode(),fm.getClock());
		return res2;
	}
	
	/**
	 * 是否匹配()[]格式
	 * @param str
	 * @return
	 */
	public static boolean Match(String str) {
		String regex="\\[\\]|\\(\\)|\\[\\[|\\]\\]";
		Pattern p = Pattern.compile(regex);
		Matcher m = p.matcher(str);
		if (m.find()) {
			return false;
		}
		char[] charArray = str.toCharArray();
		Stack<Character> stack = new Stack<Character>();
		for (char c : charArray) {
			if (c == '(' || c == '[') {
				stack.push(c);
			}
			if (c == ')' || c == ']') {
				if (stack.empty()){
					return false;
				}
				char cc = String.valueOf(stack.pop()).toCharArray()[0];
				switch (c) {
				case ')':
					if (cc != '(')
						return false;
					break;
				case ']':
					if (cc != '[')
						return false;
					break;
				}
			}
		}
		if(stack.empty()){
			return true;
		}else{
			return false;
		}
	}
	
	/**
	 * 判断子公式是否存在、时间粒度是否匹配、是否死循环(为了效率，这里只向上检查2层)
	 * 
	 * @param sourcecode 公式内容
	 * @param code 公式code
	 * @param clock 版本
	 * @return
	 */
	public String checkFormula2(String sourcecode, String mintimegranid, String code, String clock) {
		code = "[" + code + "]";
		if(sourcecode.indexOf(code)>-1){
			return "公式存在死循环，指向本身" + code;
		}
		String regex="\\[.+?\\]";
		Pattern p = Pattern.compile(regex);
		Matcher m = p.matcher(sourcecode);
		while (m.find()) {
			String cc = m.group();
			// 子公式code
			String code2 = cc.substring(1, cc.length()-1);
			// 子公式ID查询出公式
			String sourcecode2 = getFormula(code2, clock);
			if (sourcecode2==null || sourcecode2.isEmpty()){
				Map<String, Object> m1 = new HashMap<String, Object>();
				m1.put("code", code2);
				m1.put("clock", clock);
				List<Formula> lf = formulaMapper.getByCodeClock(m1);
				if(lf!=null && lf.size()>0){
					return clock + " 子公式[" + code2 + "]已被禁用";
				}else{
					return clock + " 子公式[" + code2 + "]不存在";
				}
			}else{
				if(sourcecode2.indexOf(code)>-1){
					return "子公式存在死循环，指向" + code;
				}
				if(sourcecode2.indexOf(cc)>-1){
					return "子公式存在死循环，指向" + cc;
				}
				if(mintimegranid.equalsIgnoreCase("DAY") || mintimegranid.equalsIgnoreCase("SHIFT")){
                	HashMap<String, Object> parmas = new HashMap<>();
                	parmas.put("code", code2);
                	parmas.put("clock", clock);
                	// 获取公式
                	Formula fm = this.getFormulaCodeClock(parmas);
                	String tbname =  fm.getTablename();
                	// 子公式最小时间粒度
                	String mintimegranid_z = "";
            		if(tbname.equalsIgnoreCase("T_RM_CALPOINT_VALUE")){
            			mintimegranid_z = tRmCalpointMapper.selectByPrimaryKey(code2).getMintimegranid();
            		}else if(tbname.equalsIgnoreCase("T_RM_ACT_VALUE") || tbname.equalsIgnoreCase("T_RM_BALANCE_VALUE") || tbname.equalsIgnoreCase("T_RM_PLAN_VALUE")
            				|| tbname.equalsIgnoreCase("T_RM_DW_VALUE") || tbname.equalsIgnoreCase("T_RM_DF_VALUE")){
            			mintimegranid_z = tRmActItemMapper.selectByPrimaryKey(code2).getMintimegranid();
            		}else if(tbname.equalsIgnoreCase("T_RM_INDEX_VALUE")){
            			mintimegranid_z = tRmIndexItemMapper.selectByPrimaryKey(code2).getMintimegranid();
            		}else if(tbname.equalsIgnoreCase("T_RM_WORKPROC_MATERIAL_VALUE")){
            			mintimegranid_z = "DAY";
            		}else if(tbname.equalsIgnoreCase("T_RM_WORKPROC_PRODUCT_VALUE")){
            			mintimegranid_z = "DAY";
            		}
            		if(!mintimegranid_z.isEmpty()&&!mintimegranid_z.equalsIgnoreCase("SHIFT") && !mintimegranid_z.equalsIgnoreCase(mintimegranid)){
            			return "子公式最小粒度比该项目高：" + cc + "时间粒度:" + mintimegranid_z;
            		}
				}
			}
		}
		if(!mintimegranid.isEmpty()){
			// 用了code计算的公式
			List<Formula> formulaList = getAssociatedFormula(code.substring(1, code.length()-1));
			for(Formula fa:formulaList){
				String tb = fa.getTablename();
				// 父公式最小时间粒度
	        	String mintimegranid_f = "";
	        	if(tb.equalsIgnoreCase("T_RM_CALPOINT_VALUE")){
	        		mintimegranid_f = tRmCalpointMapper.selectByPrimaryKey(fa.getCode()).getMintimegranid();
	    		}else if(tb.equalsIgnoreCase("T_RM_ACT_VALUE") || tb.equalsIgnoreCase("T_RM_BALANCE_VALUE") || tb.equalsIgnoreCase("T_RM_PLAN_VALUE")
	    				|| tb.equalsIgnoreCase("T_RM_DW_VALUE") || tb.equalsIgnoreCase("T_RM_DF_VALUE")){
	    			mintimegranid_f = tRmActItemMapper.selectByPrimaryKey(fa.getCode()).getMintimegranid();
	    		}else if(tb.equalsIgnoreCase("T_RM_INDEX_VALUE")){
	    			mintimegranid_f = tRmIndexItemMapper.selectByPrimaryKey(fa.getCode()).getMintimegranid();
	    		}else if(tb.equalsIgnoreCase("T_RM_WORKPROC_MATERIAL_VALUE")){
	    			mintimegranid_f = "DAY";
        		}else if(tb.equalsIgnoreCase("T_RM_WORKPROC_PRODUCT_VALUE")){
	    			mintimegranid_f = "DAY";
        		}
	        	if(TimegranidUtils.isBigTimegranid(mintimegranid, mintimegranid_f)){
	        		return "父公式最小粒度比该项目小：" + fa.getCode() + "时间粒度:" + mintimegranid_f;
	        	}
			}
		}
		return "";
	}
	
	/**
	 * 判断子公式是否存在或者合法
	 * 
	 * @param formula 带上来父id的公式，比如[zy0011,zy0001]
	 * @param list 用于闭环验证
	 * @param clock 版本
	 * @param xg 是否为修改公式
	 * @return
	 */
	public String checkFormula4(String sourcecode, List<Tree> list, String clock) {
		String regex="\\[.+?\\]";
		Pattern p = Pattern.compile(regex);
		Matcher m = p.matcher(sourcecode);
		if (m.find()) {
			// 子公式ID
			String cc = m.group();
			String codeStr = cc.substring(1, cc.length()-1);
			// 子公式ID查询出公式
			try {
				String code = codeStr.split(",")[0];
				String pid = "";
				if(codeStr.split(",").length >1){
					pid = codeStr.split(",")[1];
				}
				if(code.equalsIgnoreCase(pid)){
					return "公式存在死循环，指向本身";
				}
				String code2 = getFormula(code, clock);
				if (code2==null || code2.isEmpty()){
					Map<String, Object> m1 = new HashMap<String, Object>();
					m1.put("code", code);
					m1.put("clock", clock);
					List<Formula> lf = formulaMapper.getByCodeClock(m1);
					if(lf!=null && lf.size()>0){
						return clock + " 子公式[" + codeStr.split(",")[0] + "]已被禁用";
					}else{
						return clock + " 子公式[" + codeStr.split(",")[0] + "]不存在";
					}
				}
				if (code2.startsWith("R") || code2.matches("([1-9]+[0-9]*|0)(\\.[\\d]+)?")) {
					Tree t = new Tree(code,pid,false);
					list.add(t);
				} else {
					Tree t = new Tree(code,pid,true);
					list.add(t);
					if(code2.indexOf("+")>-1 || code2.indexOf("-")>-1){
						code2 = "(" + code2 + ")";
					}
					code2 = code2.replaceAll("]", ","+code+"]");
				}
				sourcecode = sourcecode.replaceAll("\\[" + codeStr + "\\]", code2);
				if(Tree.isLoop(list) || list.size()>1000){
					return "存在死循环或者数据错误-" + list.size();
				}
				return checkFormula4(sourcecode,list,clock);
			}catch (DataAccessException e) {
				return "子公式[" + codeStr.split(",")[0] + "]不存在";
			}
		} else {
			return "";
		}
	}

	@Override
	public List<String> getAllItem(List<String> ids, List<String> items, String clock, String timegranid) {
		if(ids==null || ids.size() == 0 || clock==null || clock.length()<4){
			if(items.size()>0){ // 删除第一个，即源项目ID
				items.remove(0);
			}
			return items;
		}
		String itemid = ids.get(0);
		ids.remove(0);
		String clk = "";
		if(clock.length()<6){
			clock = clock + "12";
		}
		if(clock.indexOf("-") == -1){
			clk = clock.substring(0,6);
		}else{
			clk = clock.split("-")[0] + clock.split("-")[1];
		}
		Formula fa = this.getFormulaLatest(itemid);
		// 产品产量数据修改，单耗重新计算
		if(fa!=null && fa.getTablename().equalsIgnoreCase("T_RM_WORKPROC_PRODUCT_VALUE")){
			String code = fa.getCode();
			TRmWorkprocProduct twp = tRmWorkprocProductMapper.selectByPrimaryKey(code);
			if(twp!=null && twp.getIsprimary().equals("1")){ // 主产品
				// 实绩产品，影响能源实绩、平衡项目单耗、原料单耗
				if(code.endsWith("R")){
					HashMap<String, Object> maps = new HashMap<>();
			        maps.put("useflag", "1");
			        maps.put("workprocid", twp.getWorkprocid());
			        maps.put("itemtype", "R");
			        List<TRmActItem> la = tRmActItemMapper.selectByParameters(maps);
			        maps.put("itemtype", "B");
			        la.addAll(tRmActItemMapper.selectByParameters(maps));
			        for(TRmActItem ta:la){
			        	if(!items.contains(ta.getItemid())){
			        		items.add(ta.getItemid());
			        	}
			        }
			        // 工序下的原料实绩
			        maps.put("itemtype", "R");
			        List<TRmWorkprocMaterial> lm = tRmWorkprocMaterialMapper.selectByParameters(maps);
			        for(TRmWorkprocMaterial tm:lm){
			        	if(!items.contains(tm.getItemid())){
			        		items.add(tm.getItemid());
			        	}
			        }
				}else if(code.endsWith("P")){ // 计划影响能源计划单耗
					HashMap<String, Object> maps = new HashMap<>();
			        maps.put("useflag", "1");
			        maps.put("workprocid", twp.getWorkprocid());
			        maps.put("itemtype", "P");
			        List<TRmActItem> la = tRmActItemMapper.selectByParameters(maps);
			        for(TRmActItem ta:la){
			        	if(!items.contains(ta.getItemid())){
			        		items.add(ta.getItemid());
			        	}
			        }
				}
			}
		}
		if(!items.contains(itemid)){
			items.add(itemid);
			String sql = "select code,tablename from "
			+ "(select sourcecode,code,row_number() over (partition by code order by clock desc) rn,isavailable,tablename "
			+ "from formula where clock <=?) "
			+ "where rn = 1 and isavailable = '1' and sourcecode like '%['||?||']%'";
			List<Map<String, Object>> l = jdbcTemplate.queryForList(sql,new Object[]{clk,itemid});
			if(l.size()>0){
				for(int i=0;i<l.size();i++){
					String code = l.get(i).get("code").toString();
					String tb = l.get(i).get("tablename").toString();
					if(tb.equalsIgnoreCase("T_RM_WORKPROC_PRODUCT_VALUE")){
						// 产品为日粒度
						if(timegranid.equalsIgnoreCase("DAY")){
							if(!ids.contains(code)){
								ids.add(code);
							}
							// 主产品产量，单耗计算在公式中不包含，添加重新计算单耗的项目（能源计划、实绩、平衡、原料实绩），不向后关联其他项目
							TRmWorkprocProduct twp = tRmWorkprocProductMapper.selectByPrimaryKey(code);
							if(twp!=null && twp.getIsprimary().equals("1")){ // 主产品
								// 实绩产品，影响能源实绩、平衡项目单耗、原料单耗
								if(code.endsWith("R")){
									HashMap<String, Object> maps = new HashMap<>();
							        maps.put("useflag", "1");
							        maps.put("workprocid", twp.getWorkprocid());
							        maps.put("itemtype", "R");
							        List<TRmActItem> la = tRmActItemMapper.selectByParameters(maps);
							        maps.put("itemtype", "B");
							        la.addAll(tRmActItemMapper.selectByParameters(maps));
							        for(TRmActItem ta:la){
							        	if(!items.contains(ta.getItemid())){
							        		items.add(ta.getItemid());
							        	}
							        }
							        // 工序下的原料实绩
							        maps.put("itemtype", "R");
							        List<TRmWorkprocMaterial> lm = tRmWorkprocMaterialMapper.selectByParameters(maps);
							        for(TRmWorkprocMaterial tm:lm){
							        	if(!items.contains(tm.getItemid())){
							        		items.add(tm.getItemid());
							        	}
							        }
								} else if(code.endsWith("P")){ // 计划影响能源计划单耗
									HashMap<String, Object> maps = new HashMap<>();
							        maps.put("useflag", "1");
							        maps.put("workprocid", twp.getWorkprocid());
							        maps.put("itemtype", "P");
							        List<TRmActItem> la = tRmActItemMapper.selectByParameters(maps);
							        for(TRmActItem ta:la){
							        	if(!items.contains(ta.getItemid())){
							        		items.add(ta.getItemid());
							        	}
							        }
								}
							}
						}
					} else if (tb.equalsIgnoreCase("T_RM_WORKPROC_PRODUCT_VALUE")){
						if(timegranid.equalsIgnoreCase("DAY")){ // 原料日粒度数据受公式影响
							if(!ids.contains(code)){
								ids.add(code);
							}
						}
					} else if (tb.equalsIgnoreCase("T_RM_CALPOINT_VALUE")){
						TRmCalpoint ti = tRmCalpointMapper.selectByPrimaryKey(code);
						if(ti!=null && ti.getMintimegranid().equalsIgnoreCase(timegranid)){
							if(!ids.contains(code)){
								ids.add(code);
							}
						}
					} else if (tb.equalsIgnoreCase("T_RM_ACT_VALUE") || tb.equalsIgnoreCase("T_RM_BALANCE_VALUE") || tb.equalsIgnoreCase("T_RM_PLAN_VALUE")
							|| tb.equalsIgnoreCase("T_RM_DW_VALUE") || tb.equalsIgnoreCase("T_RM_DF_VALUE")){
						TRmActItem ti = tRmActItemMapper.selectByPrimaryKey(code);
						if(ti!=null && ti.getMintimegranid().equalsIgnoreCase(timegranid)){
							if(!ids.contains(code)){
								ids.add(code);
							}
						}
					} else if(tb.equalsIgnoreCase("T_RM_INDEX_VALUE")){
						TRmIndexItem ti = tRmIndexItemMapper.selectByPrimaryKey(code);
						if(ti!=null && ti.getMintimegranid().equalsIgnoreCase(timegranid)){
							if(!ids.contains(code)){
								ids.add(code);
							}
						}
					}
					
				}
			}
		}
		return getAllItem(ids,items, clock, timegranid);
	}
	
	/**
	 * 重新计算单个项目数据，日粒度计算完，会重新计算对应的月、年数据
	 * @param itemid
	 * @param clock
	 * @param timegranid
	 * @return
	 */
	@Override
	// @Transactional(rollbackFor=Exception.class)
	public String reItemVal(String itemid, String clock, String timegranid, String clockend) {
		String res = "";
		String opuser = JwtUtil.getUseridByToken();
		if(clockend!=null && !clockend.isEmpty()){
			if(!clock.substring(0, 4).equals(clockend.substring(0, 4))){
				return "不得跨年计算";
			}
		}
		// 获得计算公式与表名
		Map<String, Object> mt = getFormulaAndTbname(itemid,clock.substring(0,7));
		if(mt==null || mt.get("TABLENAME") == null || mt.get("SOURCECODE") == null){
			return "itemid:" + itemid + ",公式版本：" + clock.substring(0,7) + "不存在";
		}
		String tbname = mt.get("TABLENAME").toString();
		// 日粒度
		if(timegranid.equalsIgnoreCase("DAY")){
			// 计算开始日期
			Date startDay = null;
			try {
				startDay = new SimpleDateFormat("yyyy-MM-dd").parse(clock);
			} catch (ParseException e) {
				return "日期格式错误";
			}
			Calendar sta = Calendar.getInstance();
			sta.setTime(startDay);
			// 计算结束日期(计算月最后一天或者昨天)
			Calendar calend = Calendar.getInstance();
			calend.setTime(startDay);
			calend.set(Calendar.DAY_OF_MONTH, 1);
			calend.add(Calendar.MONTH, 1);
			calend.add(Calendar.DAY_OF_YEAR, -1);
			Date endDay = calend.getTime();
			// 现在
			Calendar now = Calendar.getInstance();
			// 如果修改数据为本月，计算结束日期计算
			if(sta.get(Calendar.MONTH) == now.get(Calendar.MONTH) && sta.get(Calendar.YEAR) ==  now.get(Calendar.YEAR)){
				if(tbname.equalsIgnoreCase("T_RM_CALPOINT_VALUE")){
					if(now.get(Calendar.HOUR_OF_DAY)>2){
						now.add(Calendar.DAY_OF_YEAR, -1);
					}else{
						now.add(Calendar.DAY_OF_YEAR, -2);
					}
				}else{
					now.add(Calendar.DAY_OF_YEAR, -1);
				}
				endDay = now.getTime();
			}
			// 月粒度统计
			int startMonth = sta.get(Calendar.MONTH)+1;
			int endMonth = 12;
			// 今如果是今年，计算最后月份为上月
			if(sta.get(Calendar.YEAR) ==  now.get(Calendar.YEAR)){
				endMonth = now.get(Calendar.MONTH);
			}
			if(clockend!=null && !clockend.isEmpty()){
				try {
					endDay = new SimpleDateFormat("yyyy-MM-dd").parse(clockend);
					if(startDay.after(endDay)){
						return "开始时间不得早于结束时间";
					}
					Calendar c = Calendar.getInstance();
					c.setTime(endDay);
					// 计算最后月份
					endMonth = c.get(Calendar.MONTH)+1;
				} catch (ParseException e) {
					return "结束日期格式错误";
				}
			}
			while(!startDay.after(endDay)){
				// 日时间粒度数据累积量重新计算
				String clk = new SimpleDateFormat("yyyy-MM-dd").format(startDay);
				if(tbname.equalsIgnoreCase("T_RM_CALPOINT_VALUE")){
					if(res.isEmpty()){
						res = tRmCalpointValueService.restatCalpData(itemid, clk, "DAY", opuser);
					}else{
						tRmCalpointValueService.restatCalpData(itemid, clk, "DAY", opuser);
					}
				} else if(tbname.equalsIgnoreCase("T_RM_ACT_VALUE")){
					tRmActValueService.restatData(itemid, clk, "DAY", opuser);
				} else if(tbname.equalsIgnoreCase("T_RM_BALANCE_VALUE")){
					tRmBalanceValueService.restatData(itemid, clk, "DAY");
				} else if(tbname.equalsIgnoreCase("T_RM_PLAN_VALUE")){
					tRmPlanValueService.restatData(itemid, clk, "DAY");
				} else if(tbname.equalsIgnoreCase("T_RM_WORKPROC_MATERIAL_VALUE")){
					tRmWorkprocMaterialValueService.restatData(itemid, clk, "DAY");
				} else if(tbname.equalsIgnoreCase("T_RM_WORKPROC_PRODUCT_VALUE")){
					tRmWorkprocProductValueService.restatData(itemid, clk, "DAY");
				} else if(tbname.equalsIgnoreCase("T_RM_INDEX_VALUE")){
					tRmIndexValueService.restatData(itemid, clk, "DAY", opuser);
				} else if(tbname.equalsIgnoreCase("T_RM_DW_VALUE")){
					tRmDwValueService.restatData(itemid, clk, "DAY", opuser, null, "");
				} else if(tbname.equalsIgnoreCase("T_RM_DF_VALUE")){
					tRmDfValueService.restatData(itemid, clk, "DAY", opuser, null, "");
				}
				startDay = new Date(startDay.getTime() + 3600*24*1000);
			}
			while(startMonth <= endMonth){
				String clk = sta.get(Calendar.YEAR) + "-" + startMonth;
				if(startMonth < 10){
					clk = sta.get(Calendar.YEAR) + "-0" + startMonth;
				}
				if(tbname.equalsIgnoreCase("T_RM_CALPOINT_VALUE")){
					tRmCalpointValueService.restatCalpData(itemid, clk, "MONTH", opuser);
				} else if(tbname.equalsIgnoreCase("T_RM_ACT_VALUE")){
					tRmActValueService.restatData(itemid, clk, "MONTH", opuser);
				} else if(tbname.equalsIgnoreCase("T_RM_BALANCE_VALUE")){
					tRmBalanceValueService.restatData(itemid, clk, "MONTH");
				} else if(tbname.equalsIgnoreCase("T_RM_PLAN_VALUE")){
					tRmPlanValueService.restatData(itemid, clk, "MONTH");
				} else if(tbname.equalsIgnoreCase("T_RM_WORKPROC_MATERIAL_VALUE")){
					tRmWorkprocMaterialValueService.restatData(itemid, clk, "MONTH");
				} else if(tbname.equalsIgnoreCase("T_RM_WORKPROC_PRODUCT_VALUE")){
					tRmWorkprocProductValueService.restatData(itemid, clk, "MONTH");
				} else if(tbname.equalsIgnoreCase("T_RM_INDEX_VALUE")){
					tRmIndexValueService.restatData(itemid, clk, "MONTH", opuser);
				} else if(tbname.equalsIgnoreCase("T_RM_DW_VALUE")){
					tRmDwValueService.restatData(itemid, clk, "MONTH", opuser, null, "");
				} else if(tbname.equalsIgnoreCase("T_RM_DF_VALUE")){
					tRmDfValueService.restatData(itemid, clk, "MONTH", opuser, null, "");
				}
				startMonth++;
			}
			// 如果是今年以前数据，或者12月数据，重新计算年粒度最终值
			if(sta.get(Calendar.YEAR) < now.get(Calendar.YEAR) || endMonth == 12){
				String clk = sta.get(Calendar.YEAR) + "";
				if(tbname.equalsIgnoreCase("T_RM_CALPOINT_VALUE")){
					tRmCalpointValueService.restatCalpData(itemid, clk, "YEAR", opuser);
				}else if(tbname.equalsIgnoreCase("T_RM_ACT_VALUE")){
					tRmActValueService.restatData(itemid, clk, "YEAR", opuser);
				}else if(tbname.equalsIgnoreCase("T_RM_BALANCE_VALUE")){
					tRmBalanceValueService.restatData(itemid, clk, "YEAR");
				}else if(tbname.equalsIgnoreCase("T_RM_PLAN_VALUE")){
					tRmPlanValueService.restatData(itemid, clk, "YEAR");
				}else if(tbname.equalsIgnoreCase("T_RM_WORKPROC_MATERIAL_VALUE")){
					tRmWorkprocMaterialValueService.restatData(itemid, clk, "YEAR");
				}else if(tbname.equalsIgnoreCase("T_RM_WORKPROC_PRODUCT_VALUE")){
					tRmWorkprocProductValueService.restatData(itemid, clk, "YEAR");
				}else if(tbname.equalsIgnoreCase("T_RM_INDEX_VALUE")){
					tRmIndexValueService.restatData(itemid, clk, "YEAR", opuser);
				}else if(tbname.equalsIgnoreCase("T_RM_DW_VALUE")){
					tRmDwValueService.restatData(itemid, clk, "YEAR", opuser, null, "");
				}else if(tbname.equalsIgnoreCase("T_RM_DF_VALUE")){
					tRmDfValueService.restatData(itemid, clk, "YEAR", opuser, null, "");
				}
			}
		} else if(timegranid.equalsIgnoreCase("MONTH")){
			// 现在
			Calendar now = Calendar.getInstance();
			int startMonth = Integer.valueOf(clock.split("-")[1]);
			int startYear = Integer.valueOf(clock.split("-")[0]);
			int endMonth = 12;
			// 今如果是今年，计算最后月份为上月
			if(startYear ==  now.get(Calendar.YEAR)){
				endMonth = now.get(Calendar.MONTH);
			}
			if(clockend!=null && !clockend.isEmpty()){
				try {
					Date endDay = new SimpleDateFormat("yyyy-MM").parse(clockend);
					Calendar c = Calendar.getInstance();
					c.setTime(endDay);
					endMonth = c.get(Calendar.MONTH)+1;
				} catch (ParseException e) {
					return "结束日期格式错误";
				}
			}
			while(startMonth <= endMonth){
				String clk = startYear + "-" + startMonth;
				if(startMonth < 10){
					clk = startYear + "-0" + startMonth;
				}
				if(tbname.equalsIgnoreCase("T_RM_CALPOINT_VALUE")){
					tRmCalpointValueService.restatCalpData(itemid, clk, "MONTH", opuser);
				}else if(tbname.equalsIgnoreCase("T_RM_ACT_VALUE")){
					tRmActValueService.restatData(itemid, clk, "MONTH", opuser);
				}else if(tbname.equalsIgnoreCase("T_RM_BALANCE_VALUE")){
					tRmBalanceValueService.restatData(itemid, clk, "MONTH");
				}else if(tbname.equalsIgnoreCase("T_RM_PLAN_VALUE")){
					tRmPlanValueService.restatData(itemid, clk, "MONTH");
				}else if(tbname.equalsIgnoreCase("T_RM_WORKPROC_MATERIAL_VALUE")){
					tRmWorkprocMaterialValueService.restatData(itemid, clk, "MONTH");
				}else if(tbname.equalsIgnoreCase("T_RM_WORKPROC_PRODUCT_VALUE")){
					tRmWorkprocProductValueService.restatData(itemid, clk, "MONTH");
				}else if(tbname.equalsIgnoreCase("T_RM_INDEX_VALUE")){
					tRmIndexValueService.restatData(itemid, clk, "MONTH", opuser);
				}else if(tbname.equalsIgnoreCase("T_RM_DW_VALUE")){
					tRmDwValueService.restatData(itemid, clk, "MONTH", opuser, null, "");
				}else if(tbname.equalsIgnoreCase("T_RM_DF_VALUE")){
					tRmDfValueService.restatData(itemid, clk, "MONTH", opuser, null, "");
				}
				startMonth++;
			}
			// 如果是今年以前数据，或者12月数据，重新计算年粒度最终值
			if(startYear < now.get(Calendar.YEAR) || endMonth == 12){
				String clk = startYear + "";
				if(tbname.equalsIgnoreCase("T_RM_CALPOINT_VALUE")){
					tRmCalpointValueService.restatCalpData(itemid, clk, "YEAR", opuser);
				}else if(tbname.equalsIgnoreCase("T_RM_ACT_VALUE")){
					tRmActValueService.restatData(itemid, clk, "YEAR", opuser);
				}else if(tbname.equalsIgnoreCase("T_RM_BALANCE_VALUE")){
					tRmBalanceValueService.restatData(itemid, clk, "YEAR");
				}else if(tbname.equalsIgnoreCase("T_RM_PLAN_VALUE")){
					tRmPlanValueService.restatData(itemid, clk, "YEAR");
				}else if(tbname.equalsIgnoreCase("T_RM_WORKPROC_MATERIAL_VALUE")){
					tRmWorkprocMaterialValueService.restatData(itemid, clk, "YEAR");
				}else if(tbname.equalsIgnoreCase("T_RM_WORKPROC_PRODUCT_VALUE")){
					tRmWorkprocProductValueService.restatData(itemid, clk, "YEAR");
				}else if(tbname.equalsIgnoreCase("T_RM_INDEX_VALUE")){
					tRmIndexValueService.restatData(itemid, clk, "YEAR", opuser);
				}else if(tbname.equalsIgnoreCase("T_RM_DW_VALUE")){
					tRmDwValueService.restatData(itemid, clk, "YEAR", opuser, null, "");
				}else if(tbname.equalsIgnoreCase("T_RM_DF_VALUE")){
					tRmDfValueService.restatData(itemid, clk, "YEAR", opuser, null, "");
				}
			}
		}else if(timegranid.equalsIgnoreCase("YEAR")){
			if(tbname.equalsIgnoreCase("T_RM_CALPOINT_VALUE")){
				tRmCalpointValueService.restatCalpData(itemid, clock, "YEAR", opuser);
			}else if(tbname.equalsIgnoreCase("T_RM_ACT_VALUE")){
				tRmActValueService.restatData(itemid, clock, "YEAR", opuser);
			}else if(tbname.equalsIgnoreCase("T_RM_BALANCE_VALUE")){
				tRmBalanceValueService.restatData(itemid, clock, "YEAR");
			}else if(tbname.equalsIgnoreCase("T_RM_PLAN_VALUE")){
				tRmPlanValueService.restatData(itemid, clock, "YEAR");
			}else if(tbname.equalsIgnoreCase("T_RM_WORKPROC_MATERIAL_VALUE")){
				tRmWorkprocMaterialValueService.restatData(itemid, clock, "YEAR");
			}else if(tbname.equalsIgnoreCase("T_RM_WORKPROC_PRODUCT_VALUE")){
				tRmWorkprocProductValueService.restatData(itemid, clock, "YEAR");
			}else if(tbname.equalsIgnoreCase("T_RM_INDEX_VALUE")){
				tRmIndexValueService.restatData(itemid, clock, "YEAR", opuser);
			}else if(tbname.equalsIgnoreCase("T_RM_DW_VALUE")){
				tRmDwValueService.restatData(itemid, clock, "YEAR", opuser, null, "");
			}else if(tbname.equalsIgnoreCase("T_RM_DF_VALUE")){
				tRmDfValueService.restatData(itemid, clock, "YEAR", opuser, null, "");
			}
		}
		return res;
	}

	@Override
	public String getFormula(String itemid, String clock) {
		if(clock.length()==4){
			clock  = clock + "12";
		}
		if(clock.indexOf("-") == -1){
			clock = clock.substring(0,6);
		}else{
			clock = clock.split("-")[0] + clock.split("-")[1];
		}
		Map<String, Object> m = new HashMap<String, Object>();
		m.put("itemid", itemid);
		m.put("clock", clock);
		return formulaMapper.getFormula(m);
	}

	@Override
	public Map<String, Object> getFormulaAndTbname(String itemid, String clock) {
		if(clock.length() == 4){
			clock = clock + "12";
		}
		if(clock.indexOf("-") == -1){
			clock = clock.substring(0,6);
		}else{
			clock = clock.split("-")[0] + clock.split("-")[1];
		}
		Map<String, Object> m = new HashMap<String, Object>();
		m.put("itemid", itemid);
		m.put("clock", clock);
		return formulaMapper.getFormulaAndTbname(m);
	}
	
	@Override
	// @Transactional(rollbackFor=Exception.class)
	public String reCalculate(String itemid, String clock, String timegranid, String clockend) {
		if(timegranid.equalsIgnoreCase("YEAR")){
			return "";
		}
		List<String> ids = new ArrayList<String>();
		ids.add(itemid);
		List<String> items = new ArrayList<String>();
		// 项目Id、修改的时间获得所有被影响的项目(根据公式)
		List<String> allItem = getAllItem(ids, items, clock, timegranid);
		// 重新计算
		for(String id:allItem){
			this.reItemVal(id,clock,timegranid,clockend);
			// ((IFormulaService)applicationContext.getBean("formulaService")).reItemVal(id,clock,timegranid);
			// ((IFormulaService)AopContext.currentProxy()).reItemVal(id,clock,timegranid);
			// this.formulaService.reItemVal(id,clock,timegranid);
		}
		return null;
	}
	
	@Override
    public int deleteBycode(String code) {
        return formulaMapper.deleteBycode(code);
    }

	@Override
	public String anaFormula(Formula fm) {
		if(fm==null){
			return "公式内容为空";
		}
		if(fm.getClock()==null || fm.getClock().isEmpty()){
			return "公式中请写入版本";
		}
		if(fm.getSourcecode()==null || fm.getSourcecode().isEmpty()){
			return "公式中请写入公式内容";
		}
		if(fm.getCode()==null || fm.getCode().isEmpty()){
			return "公式中请写入项目编号";
		}
		if(fm.getTablename()==null || fm.getTablename().isEmpty()){
			return "公式中请写入表名";
		}
		String formula = fm.getSourcecode().replaceAll(" ", "");
		if(formula.matches("([1-9]+[0-9]*|0)(\\.[\\d]+)?")){
			return "指定数值：" + formula;
		}
		if(!Match(formula)){
			return "()或者[]格式错误";
		}
		// 直接读取字段值公式由R开头
		if(formula.startsWith("R")){
			if(!formula.matches("R\\(\\w+?,\\w+\\)")){
				return "公式格式错误";
			}
			Pattern p = Pattern.compile("(R[(])([\\w,]*?)([)])");
			Matcher m = p.matcher(formula);
			String tbname = ""; // 表名
			String itemid = ""; // 项目ID
			if (m.matches() && m.groupCount()==3) {
				String[] f = m.group(2).split(",");
				tbname = f[0].trim();
	    		itemid = f[1].trim();
	    		return "读取表[" + tbname +"]，项目编号["+itemid+"] 的数据";
			}else{
				return "公式格式错误";
			}
		}
		String m2 = formula.replaceAll("\\(", "").replaceAll("\\)", "");
		if(!m2.matches("((\\[[\\w]+?\\]|\\d+([.][0-9]+)?)[\\+\\-\\*\\/]{1})*(\\[[\\w]+?\\]|\\d+([.][0-9]+)?)")){
			return "公式格式错误！";
		}
		String regex="\\[.+?\\]";
		Pattern p = Pattern.compile(regex);
		Matcher m = p.matcher(formula);
		while (m.find()) {
			// 子公式ID
			String code = m.group().substring(1, m.group().length()-1);
			String sql = "select description from (select description from FORMULA where code=? order by clock desc) where rownum=1";
			// 子公式ID查询出描述
			try {
				String description = jdbcTemplate.queryForObject(sql, new Object[]{code}, String.class);
				formula = formula.replaceAll("\\[" + code + "\\]", description);
			}catch (Exception e) {
				return "子公式[" + code + "]不存在";
			}
		}
		String ck = checkFormula(fm);
		if(!ck.equals("")){
			formula += " (" + ck + ")";
		}
		return formula;
	}

	public int replaceFormula(Map<String, Object> params){
		return formulaMapper.replaceFormula(params);
	}

	@Override
	public List<Formula> getFormulaByCode(String code) {
		return formulaMapper.getFormulaByCode(code);
	}

	@Override
	public String anaItem(String itemid, String clock) {
		// 获得计算公式与表名
		Map<String, Object> mt = getFormulaAndTbname(itemid,clock.substring(0,7));
		if(mt==null || mt.get("TABLENAME") == null || mt.get("SOURCECODE") == null){
			return "错误：itemid:" + itemid + ",公式版本：" + clock.substring(0,7) + "不存在";
		}
		String formula = mt.get("SOURCECODE").toString();
		if(formula.matches("([1-9]+[0-9]*|0)(\\.[\\d]+)?")){// 能介系数
			return formula;
		}
		if(formula.startsWith("R")){// 直接读取
			return getValByItemid(itemid,"DAY",clock,0) + "";
		}else{// 虚拟计量点
			String regex="\\[.+?\\]";
			Pattern p = Pattern.compile(regex);
			Matcher m = p.matcher(formula);
			while (m.find()) {
				// 子公式ID
				String code = m.group().substring(1, m.group().length()-1);
				Double dval = getValByItemid(code,"DAY",clock,0);
				if(dval>=0){
					formula = formula.replaceAll("\\[" + code + "\\]", dval+"");
				}else{
					return "子公式[" + code + "]计算公式出错了";
				}
			}
			return formula;
		}
	}

	@Override
	public Double getValByItemid(String itemid, String timegranid, String clock, int type) {
		// 获得计算公式与表名
		Map<String, Object> mt = getFormulaAndTbname(itemid,clock);
		if(mt==null || mt.get("TABLENAME") == null || mt.get("SOURCECODE") == null){
			return -2d;
		}
		String formula = mt.get("SOURCECODE").toString();
		String tbname = mt.get("TABLENAME").toString();
		Short digits = 0;
		if(tbname.equalsIgnoreCase("T_RM_CALPOINT_VALUE")){
			TRmCalpoint tRmCalpoint = tRmCalpointMapper.selectByPrimaryKey(itemid);
			digits = tRmCalpoint.getDigits() == null ? 2 : tRmCalpoint.getDigits();
		}else if(tbname.equalsIgnoreCase("T_RM_ACT_VALUE") || tbname.equalsIgnoreCase("T_RM_BALANCE_VALUE") || tbname.equalsIgnoreCase("T_RM_PLAN_VALUE")
				|| tbname.equalsIgnoreCase("T_RM_DW_VALUE") || tbname.equalsIgnoreCase("T_RM_DF_VALUE")){
			TRmActItem tRmActItem = tRmActItemMapper.selectByPrimaryKey(itemid);
			digits = tRmActItem.getDigits() == null ? 2 : tRmActItem.getDigits();
		}else if(tbname.equalsIgnoreCase("T_RM_WORKPROC_MATERIAL_VALUE")){
			TRmWorkprocMaterial trm = tRmWorkprocMaterialMapper.selectByPrimaryKey(itemid);
			digits = trm.getDigits() == null ? 2 : trm.getDigits();
		}else if(tbname.equalsIgnoreCase("T_RM_WORKPROC_PRODUCT_VALUE")){
			TRmWorkprocProduct trp = tRmWorkprocProductMapper.selectByPrimaryKey(itemid);
			digits = trp.getDigits() == null ? 2 : trp.getDigits();
		}else if(tbname.equalsIgnoreCase("T_RM_INDEX_VALUE")){
			// 指标数据全部为公式计算
			TRmIndexItem ti = tRmIndexItemMapper.selectByPrimaryKey(itemid);
			digits = ti.getDigits() == null ? 2 : ti.getDigits();
		}else if(tbname.equalsIgnoreCase("T_RM_ENERGY")){ // 折标系数
			return Double.valueOf(formula);
		}else{
			logger.error("项目公式错误,itemid:" + itemid + ",tbname:"+ tbname);
		}
		return getValByFormula(formula, timegranid, clock, digits, type);
	}

	@Override
	public String checkFormulaSeq(Formula fm) {
		if(fm.getClock()==null || fm.getClock().isEmpty()){
			return "公式中请写入版本";
		}
		if(fm.getSourcecode()==null || fm.getSourcecode().isEmpty()){
			return "公式中请写入公式内容";
		}
		if(fm.getCode()==null || fm.getCode().isEmpty()){
			return "公式中请写入项目编号";
		}
		if(fm.getTablename()==null || fm.getTablename().isEmpty()){
			return "公式中请写入表名";
		}
		String tbname = fm.getTablename();
		Long seqm;
		if(tbname.equalsIgnoreCase("T_RM_CALPOINT_VALUE")){
			seqm = tRmCalpointMapper.selectByPrimaryKey(fm.getCode()).getSeqno();
		}else if(tbname.equalsIgnoreCase("T_RM_ACT_VALUE") || tbname.equalsIgnoreCase("T_RM_BALANCE_VALUE")|| tbname.equalsIgnoreCase("T_RM_PLAN_VALUE")
				|| tbname.equalsIgnoreCase("T_RM_DW_VALUE") || tbname.equalsIgnoreCase("T_RM_DF_VALUE")){
			seqm = StrUtils.strToLong(tRmActItemMapper.selectByPrimaryKey(fm.getCode()).getSeqno()+"");
		}else if(tbname.equalsIgnoreCase("T_RM_WORKPROC_MATERIAL_VALUE")){
			seqm = StrUtils.strToLong(tRmWorkprocMaterialMapper.selectByPrimaryKey(fm.getCode()).getSeqno());
		}else if(tbname.equalsIgnoreCase("T_RM_WORKPROC_PRODUCT_VALUE")){
			seqm = StrUtils.strToLong(tRmWorkprocProductMapper.selectByPrimaryKey(fm.getCode()).getSeqno());
		}else if(tbname.equalsIgnoreCase("T_RM_INDEX_VALUE")){
			seqm = StrUtils.strToLong(tRmIndexItemMapper.selectByPrimaryKey(fm.getCode()).getSeqno()+"");
		}else{
			logger.error("项目公式错误,id:" + fm.getId() + ",tbname:"+ tbname);
			return "项目公式错误";
		}
		if(seqm==null){
			return "请设置顺序号";
		}
		List<String> rlist = new ArrayList<String>();
		rlist.add("T_RM_ACT_VALUE");
		rlist.add("T_RM_BALANCE_VALUE");
		rlist.add("T_RM_PLAN_VALUE");
		rlist.add("T_RM_DW_VALUE");
		rlist.add("T_RM_DF_VALUE");
		String regex="\\[.+?\\]";
		Pattern p = Pattern.compile(regex);
		String formula = fm.getSourcecode();
		Matcher m = p.matcher(formula);
		while (m.find()) {
			// 子公式ID
			String code = m.group().substring(1, m.group().length()-1);
			String tb = getFormulaLatest(code).getTablename();
			if((rlist.contains(tbname) && rlist.contains(tb)) || tbname.equalsIgnoreCase(tb)){
				Long seq;
				if(tb.equalsIgnoreCase("T_RM_CALPOINT_VALUE")){
					seq = tRmCalpointMapper.selectByPrimaryKey(code).getSeqno();
				}else if(tb.equalsIgnoreCase("T_RM_ACT_VALUE") || tb.equalsIgnoreCase("T_RM_BALANCE_VALUE")|| tb.equalsIgnoreCase("T_RM_PLAN_VALUE")
						|| tbname.equalsIgnoreCase("T_RM_DW_VALUE") || tbname.equalsIgnoreCase("T_RM_DF_VALUE")){
					seq = StrUtils.strToLong(tRmActItemMapper.selectByPrimaryKey(code).getSeqno()+"");
				}else if(tb.equalsIgnoreCase("T_RM_WORKPROC_MATERIAL_VALUE")){
					seq = StrUtils.strToLong(tRmWorkprocMaterialMapper.selectByPrimaryKey(code).getSeqno());
				}else if(tb.equalsIgnoreCase("T_RM_WORKPROC_PRODUCT_VALUE")){
					seq = StrUtils.strToLong(tRmWorkprocProductMapper.selectByPrimaryKey(code).getSeqno());
				}else if(tb.equalsIgnoreCase("T_RM_INDEX_VALUE")){
					seq = StrUtils.strToLong(tRmIndexItemMapper.selectByPrimaryKey(code).getSeqno()+"");
				}else{
					logger.error("项目公式子公式错误,code:" + code + ",tbname:"+ tb);
					return "项目公式子公式错误";
				}
				if(seq==null){
					return "请设置子公式[" +code+ "]顺序号";
				}
				if(seq>=seqm){
					return "公式错误，公式的顺序号应该比子公式：" + code + "的大";
				}
			}
		}
		return "";
	}

	@Override
	public Formula getFormulaLatest(String itemid) {
		return formulaMapper.getFormulaLatest(itemid);
	}

	@Override
	public Integer getFormulaSeq(Formula fm) {
		Integer seqmin = 10;
		String formula = fm.getSourcecode();
		String itemid = fm.getCode();
		if(formula==null || formula.isEmpty() || formula.startsWith("R")){
			return 10;
		}
		String tbname = fm.getTablename();
		String regex="\\[.+?\\]";
		Pattern p = Pattern.compile(regex);
		Matcher m = p.matcher(formula);
		while (m.find()) {
			// 子公式ID
			String code = m.group().substring(1, m.group().length()-1);
			String tb = getFormulaLatest(code).getTablename();
			if(tbname.equalsIgnoreCase(tb)){
				if(tb.equalsIgnoreCase("T_RM_CALPOINT_VALUE")){
					Long sz = tRmCalpointMapper.selectByPrimaryKey(code).getSeqno();
					if(sz!=null && sz.intValue() >= seqmin){
						seqmin = sz.intValue() + 1;
					}
				}else if(tb.equalsIgnoreCase("T_RM_ACT_VALUE") || tb.equalsIgnoreCase("T_RM_BALANCE_VALUE")|| tb.equalsIgnoreCase("T_RM_PLAN_VALUE")
						|| tbname.equalsIgnoreCase("T_RM_DW_VALUE") || tbname.equalsIgnoreCase("T_RM_DF_VALUE")){
					Integer sz = tRmActItemMapper.selectByPrimaryKey(code).getSeqno();
					if(sz!=null && sz >= seqmin){
						seqmin = Integer.valueOf(sz) + 1;
					}
				}else if(tb.equalsIgnoreCase("T_RM_WORKPROC_MATERIAL_VALUE")){
					String sz = tRmWorkprocMaterialMapper.selectByPrimaryKey(code).getSeqno();
					if(sz!=null && !sz.isEmpty() && Integer.valueOf(sz) >= seqmin){
						seqmin = Integer.valueOf(sz) + 1;
					}
				}else if(tb.equalsIgnoreCase("T_RM_WORKPROC_PRODUCT_VALUE")){
					String sz = tRmWorkprocProductMapper.selectByPrimaryKey(code).getSeqno();
					if(sz!=null && !sz.isEmpty() && Integer.valueOf(sz) >= seqmin){
						seqmin = Integer.valueOf(sz) + 1;
					}
				}else if(tb.equalsIgnoreCase("T_RM_INDEX_VALUE")){
					Integer sz = tRmIndexItemMapper.selectByPrimaryKey(code).getSeqno();
					if(sz!=null && sz >= seqmin){
						seqmin = sz + 1;
					}
				}else{
					seqmin = 11;
				}
			}
		}
		// 检查最大值，检查自己作为子公式的公式，要比母项目顺序号小，初始值1000000
		Integer seqmax = 1000000;
		List<Formula> formulaList = getAssociatedFormula(itemid);
		for(Formula fa:formulaList){
			String tb = fa.getTablename();
			String code = fa.getCode();
			if(tbname.equalsIgnoreCase(tb)){
				if(tb.equalsIgnoreCase("T_RM_CALPOINT_VALUE")){
					Long seqm = tRmCalpointMapper.selectByPrimaryKey(code).getSeqno();
					if(seqm!=null && seqm.intValue() <= seqmax){
						seqmax = seqm.intValue() - 1;
					}
				}else if(tb.equalsIgnoreCase("T_RM_ACT_VALUE") || tb.equalsIgnoreCase("T_RM_BALANCE_VALUE")|| tb.equalsIgnoreCase("T_RM_PLAN_VALUE")
						|| tbname.equalsIgnoreCase("T_RM_DW_VALUE") || tbname.equalsIgnoreCase("T_RM_DF_VALUE")){
					Integer seqm = tRmActItemMapper.selectByPrimaryKey(code).getSeqno();
					if(seqm!=null && seqm.intValue() <= seqmax){
						seqmax = seqm.intValue() - 1;
					}
				}else if(tb.equalsIgnoreCase("T_RM_WORKPROC_MATERIAL_VALUE")){
					Long seqm = StrUtils.strToLong(tRmWorkprocMaterialMapper.selectByPrimaryKey(code).getSeqno());
					if(seqm!=null && seqm.intValue() <= seqmax){
						seqmax = seqm.intValue() - 1;
					}
				}else if(tb.equalsIgnoreCase("T_RM_WORKPROC_PRODUCT_VALUE")){
					Long seqm = StrUtils.strToLong(tRmWorkprocProductMapper.selectByPrimaryKey(code).getSeqno());
					if(seqm!=null && seqm.intValue() <= seqmax){
						seqmax = seqm.intValue() - 1;
					}
				}else if(tb.equalsIgnoreCase("T_RM_INDEX_VALUE")){
					Long seqm = StrUtils.strToLong(tRmIndexItemMapper.selectByPrimaryKey(code).getSeqno()+"");
					if(seqm!=null && seqm.intValue() <= seqmax){
						seqmax = seqm.intValue() - 1;
					}
				}
			}
		}
		// 如果项目已经被使用，最小序号为500005
		if(seqmax != 1000000 && seqmax > 500010 && seqmin < 500005){
			seqmin = 500005;
		}
		if(seqmin>seqmax){
			logger.error("获取项目顺序号错误,seqmin:" + seqmin + ",seqmax:"+ seqmax);
			return -1;
		}
		return seqmin + (seqmax-seqmin)/2;
	}

	public List<Formula> getAssociatedFormula(String code){
		code = "[" + code + "]";
		return this.formulaMapper.getAssociatedFormula(code);
	}

	/**
	 * 根据所传的内容来修改公式或新增新版本公式
	 * @param
	 * （需要属性:公式内容SOURCECODE、表名TABLENAME、项目编号CODE,是否启用ISAVAILABLE）
	 * @return
	 */
	public Formula updateFormula(Formula model){
		Formula f = this.getById(model.getId());
		int seq = getFormulaSeq(model);
		String tb = f.getTablename();
		if(seq<0){
			logger.error("项目执行顺序错误,itemid:" + f.getCode());
			return null;
		}else{ // 修改项目执行顺序
			if(tb.equalsIgnoreCase("T_RM_ACT_VALUE")||tb.equalsIgnoreCase("T_RM_BALANCE_VALUE")||tb.equalsIgnoreCase("T_RM_PLAN_VALUE")
					|| tb.equalsIgnoreCase("T_RM_DW_VALUE") || tb.equalsIgnoreCase("T_RM_DF_VALUE")){
				TRmActItem t =  tRmActItemMapper.selectByPrimaryKey(f.getCode());
				if(t != null && (t.getSeqno() ==null || t.getSeqno()!=seq)){
					t.setSeqno(seq);
					tRmActItemMapper.updateByPrimaryKeySelective(t);
				}
			}else if(tb.equalsIgnoreCase("T_RM_WORKPROC_MATERIAL_VALUE")){
				TRmWorkprocMaterial t = tRmWorkprocMaterialMapper.selectByPrimaryKey(f.getCode());
				if(t != null && !(seq + "").equals(t.getSeqno())){
					t.setSeqno(seq + "");
					tRmWorkprocMaterialMapper.updateByPrimaryKeySelective(t);
				}
			}else if(tb.equalsIgnoreCase("T_RM_WORKPROC_PRODUCT_VALUE")){
				TRmWorkprocProduct t = tRmWorkprocProductMapper.selectByPrimaryKey(f.getCode());
				if(t != null && !(seq + "").equals(t.getSeqno())){
					t.setSeqno(seq + "");
					tRmWorkprocProductMapper.updateByPrimaryKeySelective(t);
				}
			}else if(tb.equalsIgnoreCase("T_RM_INDEX_VALUE")){
				TRmIndexItem t = tRmIndexItemMapper.selectByPrimaryKey(f.getCode());
				if(t != null && (t.getSeqno() ==null || t.getSeqno().intValue() != seq)){
					t.setSeqno(seq);
					tRmIndexItemMapper.updateByPrimaryKeySelective(t);
				}
			}else if(tb.equalsIgnoreCase("T_RM_CALPOINT_VALUE")){
				TRmCalpoint t = tRmCalpointMapper.selectByPrimaryKey(f.getCode());
				if(t != null && (t.getSeqno() ==null || t.getSeqno().intValue() != seq)){
					t.setSeqno((long)seq);
					tRmCalpointMapper.updateByPrimaryKeySelective(t);
				}
			}
		}
		f.setRevisor(JwtUtil.getUseridByToken());
		f.setRevisetime(DateUtils.getCurrentTime("yyyy-MM-dd HH:mm:ss"));
		f.setDescription(model.getDescription());
		f.setIsavailable(model.getIsavailable());
		f.setUnitid(model.getUnitid());
		f.setSourcecode(model.getSourcecode());
		f.setBz(model.getBz());
		// 如果修改公式版本，删除该版本的公式
		if(!f.getClock().equalsIgnoreCase(model.getClock())){
			f.setClock(model.getClock());
			this.deleteByCodeClock(f.getCode(), model.getClock());
		}
		return this.modify(f);
		// String nowTime = DateUtils.getCurrentTime("yyyyMM");
		// 修改内容并且是新日期，增加公式版本
		// if(!f.getSourcecode().equalsIgnoreCase(model.getSourcecode()) &&
		// !f.getClock().equalsIgnoreCase(nowTime)){
		// f.setId("");
		// f.setSourcecode(model.getSourcecode());
		// f.setClock(nowTime);
		// return this.add(f);
		// } else{
		// f.setSourcecode(model.getSourcecode());
		// return this.modify(f);
		// }
	}
	
	@Override
	public Formula addFormula(Formula model) {
		int seq = getFormulaSeq(model);
		String tb = model.getTablename();
		String code = model.getCode();
		model.setId("");
		if(seq<0){
			logger.error("项目执行顺序错误,itemid:" + code);
			return null;
		}else{ // 修改项目执行顺序
			if(tb.equalsIgnoreCase("T_RM_ACT_VALUE")||tb.equalsIgnoreCase("T_RM_BALANCE_VALUE")||tb.equalsIgnoreCase("T_RM_PLAN_VALUE")
					|| tb.equalsIgnoreCase("T_RM_DW_VALUE") || tb.equalsIgnoreCase("T_RM_DF_VALUE")){
				TRmActItem t =  tRmActItemMapper.selectByPrimaryKey(code);
				if(t != null && (t.getSeqno() ==null || t.getSeqno()!=seq)){
					t.setSeqno(seq);
					tRmActItemMapper.updateByPrimaryKeySelective(t);
				}
			}else if(tb.equalsIgnoreCase("T_RM_WORKPROC_MATERIAL_VALUE")){
				TRmWorkprocMaterial t = tRmWorkprocMaterialMapper.selectByPrimaryKey(code);
				if(t != null && !(seq + "").equals(t.getSeqno())){
					t.setSeqno(seq + "");
					tRmWorkprocMaterialMapper.updateByPrimaryKeySelective(t);
				}
			}else if(tb.equalsIgnoreCase("T_RM_WORKPROC_PRODUCT_VALUE")){
				TRmWorkprocProduct t = tRmWorkprocProductMapper.selectByPrimaryKey(code);
				if(t != null && !(seq + "").equals(t.getSeqno())){
					t.setSeqno(seq + "");
					tRmWorkprocProductMapper.updateByPrimaryKeySelective(t);
				}
			}else if(tb.equalsIgnoreCase("T_RM_INDEX_VALUE")){
				TRmIndexItem t = tRmIndexItemMapper.selectByPrimaryKey(code);
				if(t != null && (t.getSeqno() ==null || t.getSeqno().intValue() != seq)){
					t.setSeqno(seq);
					tRmIndexItemMapper.updateByPrimaryKeySelective(t);
				}
			}else if(tb.equalsIgnoreCase("T_RM_CALPOINT_VALUE")){
				TRmCalpoint t = tRmCalpointMapper.selectByPrimaryKey(code);
				if(t != null && (t.getSeqno() ==null || t.getSeqno().intValue() != seq)){
					t.setSeqno((long)seq);
					tRmCalpointMapper.updateByPrimaryKeySelective(t);
				}
			}
		}
		// 删除该项目的此版本
		model.setRevisor(JwtUtil.getUseridByToken());
		model.setRevisetime(DateUtils.getCurrentTime("yyyy-MM-dd HH:mm:ss"));
		this.deleteByCodeClock(model.getCode(), model.getClock());
		return this.add(model);
	}

	// 重新计算修改项目itemid数据后其他项目的数据(指标)
	@Override
	@Transactional(rollbackFor=Exception.class)
	public void reCalculateIndexVal(String itemid, String clock, String timegranid) {
		// 指标数据现在只有月需要重新计算
		if (!timegranid.equalsIgnoreCase("MONTH")) {
			return;
		}
		List<String> ids = new ArrayList<String>();
		ids.add(itemid);
		// 项目Id、修改的时间获得所有被影响的项目(根据公式)
		List<String> itemids = getAllItem(ids, new ArrayList<String>(), clock, timegranid);
		// 重新计算
		for(String tid:itemids){
			// 计算开始日期
			Date startDay = null;
			try {
				startDay = new SimpleDateFormat("yyyy-MM").parse(clock);
			} catch (ParseException e) {
				logger.error("reCalculateIndexVal-日期格式错误:" + clock);
				return;
			}
			Calendar sta = Calendar.getInstance();
			sta.setTime(startDay);
			// 现在
			Calendar now = Calendar.getInstance();
			// 月粒度统计
			int startMonth = sta.get(Calendar.MONTH)+1;
			int endMonth = 12;
			int year = sta.get(Calendar.YEAR);
			// 如果是今年，计算最后月份为上月
			if(sta.get(Calendar.YEAR) ==  now.get(Calendar.YEAR)){
				endMonth = now.get(Calendar.MONTH);
			}
			while (startMonth <= endMonth) {
				// 重新计算
				String clk = year + "-" + startMonth;
				if(startMonth < 10){
					clk = year + "-0" + startMonth;
				}
				// 获取精度
				TRmIndexItem ti = tRmIndexItemMapper.selectByPrimaryKey(tid);
				Short digits = ti.getDigits() == null ? 2 : ti.getDigits();
				// 读取原数据
				HashMap<String, Object> id = new HashMap<String, Object>();
				id.put("clock", clk);
				id.put("timegranid", timegranid);
				id.put("itemid", tid);
				TRmIndexValue t = tRmIndexValueMapper.selectByPrimaryKey(id);
				if(t != null){
					// 获得计算公式
					String formula = getFormula(tid,clock.substring(0,7));
					// 根据公式获取计算值
					Double dval = getValByFormula(formula, timegranid, clk, digits, 2);
					t.setActualvalue(dval==null?null:new BigDecimal(Double.toString(dval)));
					// 最终值=计算值+修正值
					if(dval!=null&&t.getCorrectvalue()!=null){
						t.setApportvalue(new BigDecimal(Double.toString(dval)).add(t.getCorrectvalue()));
					}else if(dval!=null){
						t.setApportvalue(new BigDecimal(Double.toString(dval)));
					}else if(t.getCorrectvalue()!=null){
						t.setApportvalue(t.getCorrectvalue());
					}
					// 重新计算累积值=本月之前累积值 + 本月最终值
					// 上月clock
					String bfclock = "";
					Double dsm = 0d;
					if (startMonth > 1) {
						if (startMonth - 1 < 10) {
							bfclock = year + "-0" + (startMonth - 1);
						} else {
							bfclock = year + "-" + (startMonth - 1);
						}
						// 计算累计值
						Map<String, Object> params = new HashMap<String, Object>();
						params.put("digits", digits);
						params.put("itemid", tid);
						params.put("clock", bfclock);
						dsm = tRmIndexValueMapper.getMonthSumVal(params);
					}
					if (dsm != null && t.getApportvalue() != null) {
						t.setSumvalue(t.getApportvalue().add(new BigDecimal(Double.toString(dsm))));
					} else if (dsm != null) {
						t.setSumvalue(new BigDecimal(Double.toString(dsm)));
					} else if (t.getApportvalue() != null) {
						t.setSumvalue(t.getApportvalue());
					}
					t.setRecTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
					tRmIndexValueMapper.updateByPrimaryKeySelective(t);
				}else{
					logger.error("原数据不存在：" + clk + ",itemid:"+ tid);
				}
				startMonth++;
			}
		}
	}

	@Override
	public Formula saveOnly(Formula model) {
		Formula f = new Formula();
		f.setRevisor(JwtUtil.getUseridByToken());
		f.setSourcecode(model.getSourcecode());
		f.setIsavailable(model.getIsavailable());
		f.setDescription(model.getDescription());
		f.setRevisetime(DateUtils.getCurrentTime("yyyy-MM-dd HH:mm:ss"));
		f.setCode(model.getCode());
		f.setTablename(model.getTablename());
		f.setId("");
		f.setClock("201901");
		String tb = model.getTablename();
		int seq = getFormulaSeq(f);
		if(seq<0){
			logger.error("项目执行顺序错误,itemid:" + f.getCode());
			return null;
		}else{ // 修改项目执行顺序
			if(tb.equalsIgnoreCase("T_RM_ACT_VALUE")||tb.equalsIgnoreCase("T_RM_BALANCE_VALUE")||tb.equalsIgnoreCase("T_RM_PLAN_VALUE")
					|| tb.equalsIgnoreCase("T_RM_DW_VALUE") || tb.equalsIgnoreCase("T_RM_DF_VALUE")){
				TRmActItem t =  tRmActItemMapper.selectByPrimaryKey(f.getCode());
				if(t != null && (t.getSeqno() ==null || t.getSeqno()!=seq)){
					t.setSeqno(seq);
					tRmActItemMapper.updateByPrimaryKeySelective(t);
				}
			}else if(tb.equalsIgnoreCase("T_RM_WORKPROC_MATERIAL_VALUE")){
				TRmWorkprocMaterial t = tRmWorkprocMaterialMapper.selectByPrimaryKey(f.getCode());
				if(t != null && !(seq + "").equals(t.getSeqno())){
					t.setSeqno(seq + "");
					tRmWorkprocMaterialMapper.updateByPrimaryKeySelective(t);
				}
			}else if(tb.equalsIgnoreCase("T_RM_WORKPROC_PRODUCT_VALUE")){
				TRmWorkprocProduct t = tRmWorkprocProductMapper.selectByPrimaryKey(f.getCode());
				if(t != null && !(seq + "").equals(t.getSeqno())){
					t.setSeqno(seq + "");
					tRmWorkprocProductMapper.updateByPrimaryKeySelective(t);
				}
			}else if(tb.equalsIgnoreCase("T_RM_INDEX_VALUE")){
				TRmIndexItem t = tRmIndexItemMapper.selectByPrimaryKey(f.getCode());
				if(t != null && (t.getSeqno() ==null || t.getSeqno().intValue() != seq)){
					t.setSeqno(seq);
					tRmIndexItemMapper.updateByPrimaryKeySelective(t);
				}
			}
		}
		this.deleteByProperty("code", f.getCode());
		return this.add(f);
	}

	@Override
	public int updateDesBycode(Map<String, Object> params) {
		return formulaMapper.updateDesBycode(params);
	}

	@Override
	public List<String> getClockByCode(Map<String, Object> params) {
		return formulaMapper.getClockByCode(params);
	}

	@Override
	public Formula getFormulaCodeClock(Map<String, Object> params) {
		return formulaMapper.getFormulaCodeClock(params);
	}

	@Override
	public int deleteByCodeClock(String code, String clock) {
		Map<String, Object> parmas = new HashMap<String, Object>();
		parmas.put("code", code);
		parmas.put("clock", clock);
		Formula f = formulaMapper.getFormulaCodeClock2(parmas);
		if (f!=null && f.getId()!=null) {
			return formulaMapper.deleteByPrimaryKey(f.getId());
		}
		return 0;
	}

	@Override
	public String getAnaByVal(String itemid, String timegranid, String clock) {
		// 获得计算公式与表名
		Map<String, Object> mt = getFormulaAndTbname(itemid,clock);
		if(mt==null || mt.get("TABLENAME") == null || mt.get("SOURCECODE") == null){
			return "计算公式不存在";
		}
		String formula = mt.get("SOURCECODE").toString();
		String tbname = mt.get("TABLENAME").toString();
		Short digits = 0;
		if(tbname.equalsIgnoreCase("T_RM_CALPOINT_VALUE")){
			TRmCalpoint tRmCalpoint = tRmCalpointMapper.selectByPrimaryKey(itemid);
			digits = tRmCalpoint.getDigits() == null ? 2 : tRmCalpoint.getDigits();
			String mintimegranid = tRmCalpoint.getMintimegranid();
			// 时间粒度非最小粒度或者DAY，此时项目数据为累计值，而不是公式计算
			if(!timegranid.equalsIgnoreCase("DAY") && !timegranid.equalsIgnoreCase(mintimegranid)){
				if(timegranid.equalsIgnoreCase("MONTH")){
					return "日粒度数据累加";
				}else if(timegranid.equalsIgnoreCase("YEAR")){
					return "月粒度数据累加";
				}else{
					return "低时间粒度数据累加";
				}
			}
		}else if(tbname.equalsIgnoreCase("T_RM_ACT_VALUE") || tbname.equalsIgnoreCase("T_RM_BALANCE_VALUE") || tbname.equalsIgnoreCase("T_RM_PLAN_VALUE")
				|| tbname.equalsIgnoreCase("T_RM_DW_VALUE")){
			TRmActItem tRmActItem = tRmActItemMapper.selectByPrimaryKey(itemid);
			digits = tRmActItem.getDigits() == null ? 2 : tRmActItem.getDigits();
			// 时间粒度非最小粒度，此时项目数据为累计值，而不是公式计算
			if(!timegranid.equalsIgnoreCase(tRmActItem.getMintimegranid())){
				if(timegranid.equalsIgnoreCase("MONTH")){
					return "日粒度数据累加";
				}else if(timegranid.equalsIgnoreCase("YEAR")){
					return "月粒度数据累加";
				}else{
					return "低时间粒度数据累加";
				}
			}
		}else if(tbname.equalsIgnoreCase("T_RM_DF_VALUE")){
			TRmActItem tRmActItem = tRmActItemMapper.selectByPrimaryKey(itemid);
			digits = tRmActItem.getDigits() == null ? 2 : tRmActItem.getDigits();
			if (!tRmActItem.getEnergyid().equalsIgnoreCase("Y181")){ // 指标类型为公式计算
				// 时间粒度非最小粒度，此时项目数据为累计值，而不是公式计算
				if(!timegranid.equalsIgnoreCase(tRmActItem.getMintimegranid())){
					if(timegranid.equalsIgnoreCase("MONTH")){
						return "日粒度数据累加";
					}else if(timegranid.equalsIgnoreCase("YEAR")){
						return "月粒度数据累加";
					}else{
						return "低时间粒度数据累加";
					}
				}
			}
		}else if(tbname.equalsIgnoreCase("T_RM_WORKPROC_MATERIAL_VALUE")){
			// 原料数据最小时间粒度默认为日
			if(!timegranid.equalsIgnoreCase("DAY")){
				if(timegranid.equalsIgnoreCase("MONTH")){
					return "日粒度数据累加";
				}else if(timegranid.equalsIgnoreCase("YEAR")){
					return "月粒度数据累加";
				}else{
					return "低时间粒度数据累加";
				}
			}
			TRmWorkprocMaterial trm = tRmWorkprocMaterialMapper.selectByPrimaryKey(itemid);
			digits = trm.getDigits() == null ? 2 : trm.getDigits();
		}else if(tbname.equalsIgnoreCase("T_RM_WORKPROC_PRODUCT_VALUE")){
			// 产品最小时间粒度默认为日
			if(!timegranid.equalsIgnoreCase("DAY")){
				if(timegranid.equalsIgnoreCase("MONTH")){
					return "日粒度数据累加";
				}else if(timegranid.equalsIgnoreCase("YEAR")){
					return "月粒度数据累加";
				}else{
					return "低时间粒度数据累加";
				}
			}
			TRmWorkprocProduct trp = tRmWorkprocProductMapper.selectByPrimaryKey(itemid);
			digits = trp.getDigits() == null ? 2 : trp.getDigits();
		}else if(tbname.equalsIgnoreCase("T_RM_INDEX_VALUE")){
			// 指标数据全部为公式计算
			TRmIndexItem ti = tRmIndexItemMapper.selectByPrimaryKey(itemid);
			digits = ti.getDigits() == null ? 2 : ti.getDigits();
		}else if(tbname.equalsIgnoreCase("T_RM_ENERGY")){ // 折标系数
			return formula;
		}else{
			logger.error("项目公式错误,itemid:" + itemid + ",tbname:"+ tbname);
		}
		if(formula == null || formula.trim().isEmpty()){
			return "公式不存在";
		} else if(formula.startsWith("R")){
			return getValByFormulaR(formula, timegranid, clock, digits, 0).toString();
		} else if(formula.matches("([1-9]+[0-9]*|0)(\\.[\\d]+)?")){ // 指定数值
			return formula;
		} else {
			String gs = replaceFormula(formula, timegranid, clock, digits, 0);
			if(gs.startsWith("error")){
				return "子公式错误-" + gs.substring(6);
			}else{
				if (tbname.equalsIgnoreCase("T_RM_DF_VALUE") && timegranid.equalsIgnoreCase("DAY")) {
					HashMap<String, Object> id = new HashMap<String, Object>();
		    		id.put("clock", clock);
		    		id.put("timegranid", timegranid);
		    		id.put("itemid", itemid);
		    		TRmDfValue tv = tRmDfValueMapper.selectByPrimaryKey(id);
		    		if(tv != null){
		    			formula = "(" + formula + ") * 实际波动系数";
		    			gs = "(" + gs + ") * " + tv.getStdwvalue().toPlainString();
		    		}
				}
				return formula + " = <br/>" + gs;
			}
		}
	}

	@Override
	public PageList<Map<String, Object>> getDateForPage(HashMap<String, Object> parmas, Integer pageNum, Integer pageSize) {
		PageHelper.startPage(pageNum, pageSize);
		List<Map<String, Object>> rows = formulaMapper.getDateForPage(parmas);
		PageList<Map<String, Object>> pageInfo = new PageList<Map<String, Object>>(rows);
		return pageInfo;
	}

	@Override
	public Double readValByItemid(String itemid, String timegranid, String clock, int type) {
		// 获得计算公式与表名
		Map<String, Object> mt = getFormulaAndTbname(itemid,clock);
		if(mt==null || mt.get("TABLENAME") == null || mt.get("SOURCECODE") == null){
			return -2d;
		}
		String formula = mt.get("SOURCECODE").toString();
		String tbname = mt.get("TABLENAME").toString();
		// 读取原数据
		HashMap<String, Object> id = new HashMap<String, Object>();
		id.put("clock", clock);
		id.put("timegranid", timegranid);
		id.put("itemid", itemid);
		if(tbname.equalsIgnoreCase("T_RM_CALPOINT_VALUE")){
			TRmCalpointValue t = tRmCalpointValueMapper.selectByPrimaryKey(id);
			if(t != null){
				if(type == 1){
					return t.getSumvalue()!=null?t.getSumvalue().doubleValue():null;
				}else if(type == 2){
					return t.getStdvalue()!=null?t.getStdvalue().doubleValue():null;
				}else{
					return t.getApportvalue().doubleValue();
				}
			}else{
				return null;
			}
		}else if(tbname.equalsIgnoreCase("T_RM_ACT_VALUE")){
			TRmActValue t = tRmActValueMapper.selectByPrimaryKey(id);
			if(t != null){
				if(type == 1){
					return t.getSumvalue()!=null?t.getSumvalue().doubleValue():null;
				}else if(type == 2){
					return t.getStdvalue()!=null?t.getStdvalue().doubleValue():null;
				}else{
					return t.getApportvalue().doubleValue();
				}
			}else{
				return null;
			}
		}else if(tbname.equalsIgnoreCase("T_RM_BALANCE_VALUE")){
			TRmBalanceValue t = tRmBalanceValueMapper.selectByPrimaryKey(id);
			if(t != null){
				if(type == 1){
					return t.getSumvalue()!=null?t.getSumvalue().doubleValue():null;
				}else if(type == 2){
					return t.getStdvalue()!=null?t.getStdvalue().doubleValue():null;
				}else{
					return t.getApportvalue().doubleValue();
				}
			}else{
				return null;
			}
		}else if(tbname.equalsIgnoreCase("T_RM_PLAN_VALUE")){
			TRmPlanValue t = tRmPlanValueMapper.selectByPrimaryKey(id);
			if(t != null){
				if(type == 1){
					return t.getSumvalue()!=null?t.getSumvalue().doubleValue():null;
				}else if(type == 2){
					return t.getStdvalue()!=null?t.getStdvalue().doubleValue():null;
				}else{
					return t.getApportvalue().doubleValue();
				}
			}else{
				return null;
			}
		}else if(tbname.equalsIgnoreCase("T_RM_DW_VALUE")){
			TRmDwValue t = tRmDwValueMapper.selectByPrimaryKey(id);
			if(t != null){
				if(type == 1){
					return null;
				}else if(type == 2){
					return t.getStdwvalue()!=null?t.getStdwvalue().doubleValue():null;
				}else{
					return t.getApportwvalue().doubleValue();
				}
			}else{
				return null;
			}
		}else if(tbname.equalsIgnoreCase("T_RM_DF_VALUE")){
			TRmDfValue t = tRmDfValueMapper.selectByPrimaryKey(id);
			if(t != null){
				if(type == 1){
					return null;
				}else if(type == 2){
					return t.getStdwvalue()!=null?t.getStdwvalue().doubleValue():null;
				}else{
					return t.getApportwvalue().doubleValue();
				}
			}else{
				return null;
			}
		}else if(tbname.equalsIgnoreCase("T_RM_WORKPROC_MATERIAL_VALUE")){
			TRmWorkprocMaterialValue t = tRmWorkprocMaterialValueMapper.selectByPrimaryKey(id);
			if(t != null){
				if(type == 1){
					return t.getSumvalue()!=null?t.getSumvalue().doubleValue():null;
				}else if(type == 2){
					return null;
				}else{
					return t.getApportvalue().doubleValue();
				}
			}else{
				return null;
			}
		}else if(tbname.equalsIgnoreCase("T_RM_WORKPROC_PRODUCT_VALUE")){
			id.put("itemtype", itemid.substring(itemid.length()-1, itemid.length()));
			TRmWorkprocProductValue t = tRmWorkprocProductValueMapper.selectByPrimaryKey(id);
			if(t != null){
				if(type == 1){
					return t.getSumvalue()!=null?t.getSumvalue().doubleValue():null;
				}else if(type == 2){
					return null;
				}else{
					return t.getApportvalue().doubleValue();
				}
			}else{
				return null;
			}
		}else if(tbname.equalsIgnoreCase("T_RM_INDEX_VALUE")){
			TRmIndexValue t = tRmIndexValueMapper.selectByPrimaryKey(id);
			if(t != null){
				if(type == 1){
					return t.getSumvalue()!=null?t.getSumvalue().doubleValue():null;
				}else if(type == 2){
					return null;
				}else{
					return t.getApportvalue().doubleValue();
				}
			}else{
				return null;
			}
		}else if(tbname.equalsIgnoreCase("T_RM_ENERGY")){ // 折标系数
			return Double.valueOf(formula);
		}else{
			logger.error("项目公式错误,itemid:" + itemid + ",tbname:"+ tbname);
			return null;
		}
	}
}
